From d4251b41fb3d602cdb5a95b10e73e84ba7e9cacc Mon Sep 17 00:00:00 2001 From: vsonnier Date: Sat, 6 Jan 2018 10:22:14 +0100 Subject: [PATCH] Feature #486 : Save/Load bookmarks into files --- src/AppFrame.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++ src/AppFrame.h | 5 +++ src/BookmarkMgr.cpp | 59 ++++++++++++++++++++++++--------- src/BookmarkMgr.h | 7 ++-- 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 76a26a7..96ed628 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -417,6 +417,10 @@ AppFrame::AppFrame() : menu->Append(wxID_SAVEAS, "Save Session &As.."); menu->AppendSeparator(); menu->Append(wxID_RESET, "&Reset Session"); + menu->AppendSeparator(); + menu->Append(wxID_OPEN_BOOKMARK, "Open Bookmark"); + menu->Append(wxID_SAVE_BOOKMARK, "Save Bookmark"); + menu->Append(wxID_SAVEAS_BOOKMARK, "Save Bookmark As.."); #ifndef __APPLE__ menu->AppendSeparator(); @@ -1121,6 +1125,7 @@ bool AppFrame::actionOnMenuReset(wxCommandEvent& event) { SetTitle(CUBICSDR_TITLE); currentSessionFile = ""; + currentBookmarkFile = ""; bookmarkSplitter->Unsplit(bookmarkView); bookmarkSplitter->SplitVertically(bookmarkView, mainVisSplitter, wxGetApp().getConfig()->getBookmarkSplit()); hideBookmarksItem->Check(false); @@ -1401,6 +1406,77 @@ bool AppFrame::actionOnMenuLoadSave(wxCommandEvent& event) { return true; } + //save mecanic for bookmark files + else if (event.GetId() == wxID_SAVE_BOOKMARK) { + + if (!currentBookmarkFile.empty()) { + wxGetApp().getBookmarkMgr().saveToFile(currentBookmarkFile, false, true); + } + else { + wxFileDialog saveFileDialog(this, _("Save XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (saveFileDialog.ShowModal() == wxID_CANCEL) { + return true; + } + + // Make sure the file name actually ends in .xml + std::string fileName = saveFileDialog.GetPath().ToStdString(); + std::string lcFileName = fileName; + + std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower); + + if (lcFileName.find_last_of(".xml") != lcFileName.length() - 1) { + fileName.append(".xml"); + } + + wxGetApp().getBookmarkMgr().saveToFile(fileName, false, true); + currentBookmarkFile = fileName; + } + + return true; + } + else if (event.GetId() == wxID_OPEN_BOOKMARK) { + + wxFileDialog openFileDialog(this, _("Open XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_OPEN | wxFD_FILE_MUST_EXIST); + if (openFileDialog.ShowModal() == wxID_CANCEL) { + return true; + } + if (wxGetApp().getBookmarkMgr().loadFromFile(openFileDialog.GetPath().ToStdString(), false, true)) { + + wxGetApp().getBookmarkMgr().updateBookmarks(); + wxGetApp().getBookmarkMgr().updateActiveList(); + + currentBookmarkFile = openFileDialog.GetPath().ToStdString(); + } + else { + //failure at loading. + currentBookmarkFile = ""; + } + + return true; + } + else if (event.GetId() == wxID_SAVEAS_BOOKMARK) { + + wxFileDialog saveFileDialog(this, _("Save XML Bookmark file"), "", "", "XML files (*.xml)|*.xml", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (saveFileDialog.ShowModal() == wxID_CANCEL) { + return true; + } + + // Make sure the file name actually ends in .xml + std::string fileName = saveFileDialog.GetPath().ToStdString(); + std::string lcFileName = fileName; + + std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower); + + if (lcFileName.find_last_of(".xml") != lcFileName.length() - 1) { + fileName.append(".xml"); + } + + wxGetApp().getBookmarkMgr().saveToFile(fileName, false, true); + currentBookmarkFile = fileName; + + return true; + } + return false; } @@ -2153,6 +2229,11 @@ bool AppFrame::loadSession(std::string fileName) { return false; } + //Check if it is a session file, read the root node. + if (l.rootNode()->getName() != "cubicsdr_session") { + return false; + } + wxGetApp().getDemodMgr().setActiveDemodulator(nullptr, false); wxGetApp().getDemodMgr().terminateAll(); diff --git a/src/AppFrame.h b/src/AppFrame.h index 45413ce..f81541a 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -43,6 +43,10 @@ #define wxID_SET_DB_OFFSET 2012 #define wxID_ABOUT_CUBICSDR 2013 +#define wxID_OPEN_BOOKMARK 2020 +#define wxID_SAVE_BOOKMARK 2021 +#define wxID_SAVEAS_BOOKMARK 2022 + #define wxID_MAIN_SPLITTER 2050 #define wxID_VIS_SPLITTER 2051 #define wxID_BM_SPLITTER 2052 @@ -229,6 +233,7 @@ private: std::string currentTXantennaName; std::string currentSessionFile; + std::string currentBookmarkFile; FFTVisualDataThread *waterfallDataThread; diff --git a/src/BookmarkMgr.cpp b/src/BookmarkMgr.cpp index fb9e58e..521ef88 100644 --- a/src/BookmarkMgr.cpp +++ b/src/BookmarkMgr.cpp @@ -18,7 +18,8 @@ BookmarkMgr::BookmarkMgr() { //represents an empty BookMarkList that is returned by reference by some functions. const BookmarkList BookmarkMgr::emptyResults; -void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) { +void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup, bool useFullpath) { + DataTree s("cubicsdr_bookmarks"); DataNode *header = s.rootNode()->newChild("header"); header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring()); @@ -62,9 +63,18 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) { recent_modems->newChildCloneFrom("modem", r_i->node); } - wxFileName saveFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn); - wxFileName saveFileBackup(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup"); - + wxFileName saveFile; + wxFileName saveFileBackup; + + if (useFullpath) { + saveFile.Assign(bookmarkFn); + saveFileBackup.Assign(bookmarkFn + ".backup"); + } + else { + saveFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn); + saveFileBackup.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup"); + } + if (saveFile.IsDirWritable()) { // Hopefully leave at least a readable backup in case of failure.. if (backup && saveFile.FileExists() && (!saveFileBackup.FileExists() || saveFileBackup.IsFileWritable())) { @@ -74,20 +84,28 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) { } } -bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) { - wxFileName loadFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn); - wxFileName failFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".failedload"); - wxFileName lastLoaded(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded"); - wxFileName backupFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup"); +bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFullpath) { + + wxFileName loadFile; + wxFileName failFile; + wxFileName lastLoaded; + wxFileName backupFile; + + if (useFullpath) { + loadFile.Assign(bookmarkFn); + failFile.Assign(bookmarkFn + ".failedload"); + lastLoaded.Assign(bookmarkFn + ".lastloaded"); + backupFile.Assign(bookmarkFn + ".backup"); + } + else { + loadFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn); + failFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".failedload"); + lastLoaded.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded"); + backupFile.Assign(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup"); + } DataTree s; bool loadStatusOk = true; - - // Clear any active data - bmData.clear(); - clearRecents(); - clearRanges(); - bmDataSorted.clear(); // File exists but is not readable if (loadFile.FileExists() && !loadFile.IsFileReadable()) { @@ -104,6 +122,17 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup) { if (!s.LoadFromFileXML(loadFile.GetFullPath(wxPATH_NATIVE).ToStdString())) { return false; } + + //Check if it is a bookmark file, read the root node. + if (s.rootNode()->getName() != "cubicsdr_bookmarks") { + return false; + } + + // Clear any active data + bmData.clear(); + clearRecents(); + clearRanges(); + bmDataSorted.clear(); if (s.rootNode()->hasAnother("branches")) { DataNode *branches = s.rootNode()->getNext("branches"); diff --git a/src/BookmarkMgr.h b/src/BookmarkMgr.h index 1fec76e..272c1b9 100644 --- a/src/BookmarkMgr.h +++ b/src/BookmarkMgr.h @@ -78,9 +78,10 @@ typedef std::map BookmarkExpandState; class BookmarkMgr { public: BookmarkMgr(); - - void saveToFile(std::string bookmarkFn, bool backup = true); - bool loadFromFile(std::string bookmarkFn, bool backup = true); + //if useFullpath = false, use the application config dir. + //else assume bookmarkFn is a full path and use it for location. + void saveToFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false); + bool loadFromFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false); bool hasLastLoad(std::string bookmarkFn); bool hasBackup(std::string bookmarkFn);