mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-02-03 09:44:26 -05:00
Dual bookmark backup files with user notification, auto-recovery and bail; save top level branch expand states
This commit is contained in:
parent
69e23fd13a
commit
68495b4d90
@ -678,6 +678,7 @@ AppFrame::AppFrame() :
|
||||
deviceChanged.store(false);
|
||||
devInfo = NULL;
|
||||
wxGetApp().deviceSelector();
|
||||
saveDisabled = false;
|
||||
|
||||
// static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
|
||||
// wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not");
|
||||
@ -1293,6 +1294,11 @@ void AppFrame::OnClose(wxCloseEvent& event) {
|
||||
}
|
||||
wxGetApp().getSpectrumProcessor()->removeOutput(spectrumCanvas->getVisualDataQueue());
|
||||
|
||||
if (saveDisabled) {
|
||||
event.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize());
|
||||
wxGetApp().getConfig()->setWindowMaximized(this->IsMaximized());
|
||||
wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme());
|
||||
@ -1926,6 +1932,10 @@ BookmarkView *AppFrame::getBookmarkView() {
|
||||
return bookmarkView;
|
||||
}
|
||||
|
||||
void AppFrame::disableSave(bool state) {
|
||||
saveDisabled = state;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
bool AppFrame::canFocus() {
|
||||
|
@ -112,6 +112,7 @@ public:
|
||||
bool isUserDemodBusy();
|
||||
|
||||
BookmarkView *getBookmarkView();
|
||||
void disableSave(bool state);
|
||||
|
||||
#ifdef _WIN32
|
||||
bool canFocus();
|
||||
@ -204,6 +205,7 @@ private:
|
||||
std::string rigPort;
|
||||
int numRigs;
|
||||
bool rigInit;
|
||||
bool saveDisabled;
|
||||
#endif
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
@ -8,11 +8,18 @@ BookmarkMgr::BookmarkMgr() {
|
||||
rangesSorted = false;
|
||||
}
|
||||
|
||||
void BookmarkMgr::saveToFile(std::string bookmarkFn) {
|
||||
void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup) {
|
||||
DataTree s("cubicsdr_bookmarks");
|
||||
DataNode *header = s.rootNode()->newChild("header");
|
||||
header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring());
|
||||
|
||||
DataNode *branches = s.rootNode()->newChild("branches");
|
||||
|
||||
*branches->newChild("active") = wxGetApp().getAppFrame()->getBookmarkView()->getExpandState("active")?1:0;
|
||||
*branches->newChild("range") = wxGetApp().getAppFrame()->getBookmarkView()->getExpandState("range")?1:0;
|
||||
*branches->newChild("bookmark") = wxGetApp().getAppFrame()->getBookmarkView()->getExpandState("bookmark")?1:0;
|
||||
*branches->newChild("recent") = wxGetApp().getAppFrame()->getBookmarkView()->getExpandState("recent")?1:0;
|
||||
|
||||
DataNode *view_ranges = s.rootNode()->newChild("ranges");
|
||||
|
||||
for (auto re_i : ranges) {
|
||||
@ -50,7 +57,7 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn) {
|
||||
|
||||
if (saveFile.IsDirWritable()) {
|
||||
// Hopefully leave at least a readable backup in case of failure..
|
||||
if (saveFile.FileExists() && (!saveFileBackup.FileExists() || saveFileBackup.IsFileWritable())) {
|
||||
if (backup && saveFile.FileExists() && (!saveFileBackup.FileExists() || saveFileBackup.IsFileWritable())) {
|
||||
wxCopyFile(saveFile.GetFullPath(wxPATH_NATIVE).ToStdString(), saveFileBackup.GetFullPath(wxPATH_NATIVE).ToStdString());
|
||||
}
|
||||
s.SaveToFileXML(saveFile.GetFullPath(wxPATH_NATIVE).ToStdString());
|
||||
@ -58,20 +65,50 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn) {
|
||||
}
|
||||
|
||||
|
||||
void BookmarkMgr::loadFromFile(std::string bookmarkFn) {
|
||||
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");
|
||||
|
||||
DataTree s;
|
||||
bool loadStatusOk = true;
|
||||
|
||||
if (!loadFile.IsFileReadable()) {
|
||||
return;
|
||||
// Clear any active data
|
||||
bmData.erase(bmData.begin(),bmData.end());
|
||||
recents.erase(recents.begin(),recents.end());
|
||||
ranges.erase(ranges.begin(),ranges.end());
|
||||
bmDataSorted.erase(bmDataSorted.begin(),bmDataSorted.end());
|
||||
|
||||
// File exists but is not readable
|
||||
if (loadFile.FileExists() && !loadFile.IsFileReadable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// New instance of bookmark savefiles
|
||||
if (backup && !loadFile.FileExists() && !lastLoaded.FileExists() && !backupFile.FileExists()) {
|
||||
wxGetApp().getAppFrame()->getBookmarkView()->loadDefaultRanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempt to load file
|
||||
if (!s.LoadFromFileXML(loadFile.GetFullPath(wxPATH_NATIVE).ToStdString())) {
|
||||
// TODO: if exists; inform user & optionally load backup
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (s.rootNode()->hasAnother("branches")) {
|
||||
DataNode *branches = s.rootNode()->getNext("branches");
|
||||
int bActive = 1, bRange = 0, bBookmark = 1, bRecent = 1;
|
||||
if (branches->hasAnother("active")) branches->getNext("active")->element()->get(bActive);
|
||||
if (branches->hasAnother("range")) branches->getNext("range")->element()->get(bRange);
|
||||
if (branches->hasAnother("bookmark")) branches->getNext("bookmark")->element()->get(bBookmark);
|
||||
if (branches->hasAnother("recent")) branches->getNext("recent")->element()->get(bRecent);
|
||||
wxGetApp().getAppFrame()->getBookmarkView()->setExpandState("active", bActive?true:false);
|
||||
wxGetApp().getAppFrame()->getBookmarkView()->setExpandState("range", bRange?true:false);
|
||||
wxGetApp().getAppFrame()->getBookmarkView()->setExpandState("bookmark", bBookmark?true:false);
|
||||
wxGetApp().getAppFrame()->getBookmarkView()->setExpandState("recent", bRecent?true:false);
|
||||
}
|
||||
|
||||
if (s.rootNode()->hasAnother("ranges")) {
|
||||
DataNode *view_ranges = s.rootNode()->getNext("ranges");
|
||||
while (view_ranges->hasAnother("range")) {
|
||||
@ -79,10 +116,10 @@ void BookmarkMgr::loadFromFile(std::string bookmarkFn) {
|
||||
|
||||
BookmarkRangeEntry *re = new BookmarkRangeEntry;
|
||||
|
||||
range->getNext("label")->element()->get(re->label);
|
||||
range->getNext("freq")->element()->get(re->freq);
|
||||
range->getNext("start")->element()->get(re->startFreq);
|
||||
range->getNext("end")->element()->get(re->endFreq);
|
||||
if (range->hasAnother("label")) range->getNext("label")->element()->get(re->label);
|
||||
if (range->hasAnother("freq")) range->getNext("freq")->element()->get(re->freq);
|
||||
if (range->hasAnother("start")) range->getNext("start")->element()->get(re->startFreq);
|
||||
if (range->hasAnother("end")) range->getNext("end")->element()->get(re->endFreq);
|
||||
|
||||
addRange(re);
|
||||
}
|
||||
@ -108,6 +145,7 @@ void BookmarkMgr::loadFromFile(std::string bookmarkFn) {
|
||||
addBookmark(groupName.c_str(), be);
|
||||
} else {
|
||||
std::cout << "error loading bookmarked modem.." << std::endl;
|
||||
loadStatusOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,9 +161,39 @@ void BookmarkMgr::loadFromFile(std::string bookmarkFn) {
|
||||
addRecent(be);
|
||||
} else {
|
||||
std::cout << "error loading recent modem.." << std::endl;
|
||||
loadStatusOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (backup) {
|
||||
if (loadStatusOk) { // Loaded OK; keep a copy
|
||||
if (loadFile.IsDirWritable()) {
|
||||
if (loadFile.FileExists() && (!lastLoaded.FileExists() || lastLoaded.IsFileWritable())) {
|
||||
wxCopyFile(loadFile.GetFullPath(wxPATH_NATIVE).ToStdString(), lastLoaded.GetFullPath(wxPATH_NATIVE).ToStdString());
|
||||
}
|
||||
}
|
||||
} else if (!loadStatusOk) {
|
||||
if (loadFile.IsDirWritable()) { // Load failed; keep a copy of the failed bookmark file for analysis?
|
||||
if (loadFile.FileExists() && (!failFile.FileExists() || failFile.IsFileWritable())) {
|
||||
wxCopyFile(loadFile.GetFullPath(wxPATH_NATIVE).ToStdString(), failFile.GetFullPath(wxPATH_NATIVE).ToStdString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadStatusOk;
|
||||
}
|
||||
|
||||
|
||||
bool BookmarkMgr::hasLastLoad(std::string bookmarkFn) {
|
||||
wxFileName lastLoaded(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".lastloaded");
|
||||
return lastLoaded.FileExists() && lastLoaded.IsFileReadable();
|
||||
}
|
||||
|
||||
bool BookmarkMgr::hasBackup(std::string bookmarkFn) {
|
||||
wxFileName backupFile(wxGetApp().getConfig()->getConfigDir(), bookmarkFn + ".backup");
|
||||
return backupFile.FileExists() && backupFile.IsFileReadable();
|
||||
}
|
||||
|
||||
void BookmarkMgr::addBookmark(std::string group, DemodulatorInstance *demod) {
|
||||
@ -419,7 +487,9 @@ BookmarkEntry *BookmarkMgr::nodeToBookmark(const char *name_in, DataNode *node)
|
||||
if (node->hasAnother("user_label")) {
|
||||
node->getNext("user_label")->element()->get(be->label);
|
||||
}
|
||||
|
||||
|
||||
node->rewindAll();
|
||||
|
||||
be->node = new DataNode("node",*node);
|
||||
|
||||
return be;
|
||||
|
@ -25,6 +25,12 @@ public:
|
||||
|
||||
class BookmarkRangeEntry {
|
||||
public:
|
||||
BookmarkRangeEntry() : label(L""), freq(0), startFreq(0), endFreq(0) {
|
||||
|
||||
}
|
||||
BookmarkRangeEntry(std::wstring label, long long freq, long long startFreq, long long endFreq) : label(label), freq(freq), startFreq(startFreq), endFreq(endFreq) {
|
||||
}
|
||||
|
||||
std::mutex busy_lock;
|
||||
|
||||
std::wstring label;
|
||||
@ -63,8 +69,11 @@ class BookmarkMgr {
|
||||
public:
|
||||
BookmarkMgr();
|
||||
|
||||
void saveToFile(std::string bookmarkFn);
|
||||
void loadFromFile(std::string bookmarkFn);
|
||||
void saveToFile(std::string bookmarkFn, bool backup = true);
|
||||
bool loadFromFile(std::string bookmarkFn, bool backup = true);
|
||||
|
||||
bool hasLastLoad(std::string bookmarkFn);
|
||||
bool hasBackup(std::string bookmarkFn);
|
||||
|
||||
void addBookmark(std::string group, DemodulatorInstance *demod);
|
||||
void addBookmark(std::string group, BookmarkEntry *be);
|
||||
|
@ -27,6 +27,9 @@ IMPLEMENT_APP(CubicSDR)
|
||||
#include <fstream>
|
||||
#include <clocale>
|
||||
|
||||
#include "ActionDialog.h"
|
||||
|
||||
|
||||
//#ifdef ENABLE_DIGITAL_LAB
|
||||
//// console output buffer for windows
|
||||
//#ifdef _WINDOWS
|
||||
@ -133,8 +136,65 @@ long long strToFrequency(std::string freqStr) {
|
||||
}
|
||||
|
||||
|
||||
CubicSDR::CubicSDR() : frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE),agcMode(false)
|
||||
{
|
||||
|
||||
class ActionDialogBookmarkCatastophe : public ActionDialog {
|
||||
public:
|
||||
ActionDialogBookmarkCatastophe() : ActionDialog(wxGetApp().getAppFrame(), wxID_ANY, wxT("Bookmark Last-Loaded Backup Failure :( :( :(")) {
|
||||
m_questionText->SetLabelText(wxT("All attempts to recover bookmarks have failed. \nWould you like to exit without touching any more save files?\nClick OK to exit without saving; or Cancel to continue anyways."));
|
||||
}
|
||||
|
||||
void doClickOK() {
|
||||
wxGetApp().getAppFrame()->disableSave(true);
|
||||
wxGetApp().getAppFrame()->Close(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ActionDialogBookmarkBackupLoadFailed : public ActionDialog {
|
||||
public:
|
||||
ActionDialogBookmarkBackupLoadFailed() : ActionDialog(wxGetApp().getAppFrame(), wxID_ANY, wxT("Bookmark Backup Load Failure :( :(")) {
|
||||
m_questionText->SetLabelText(wxT("Sorry; unable to load your bookmarks backup file. \nWould you like to attempt to load the last succssfully loaded bookmarks file?"));
|
||||
}
|
||||
|
||||
void doClickOK() {
|
||||
if (wxGetApp().getBookmarkMgr().hasLastLoad("bookmarks.xml")) {
|
||||
if (wxGetApp().getBookmarkMgr().loadFromFile("bookmarks.xml.lastloaded",false)) {
|
||||
wxGetApp().getBookmarkMgr().updateBookmarks();
|
||||
wxGetApp().getBookmarkMgr().updateActiveList();
|
||||
} else {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkCatastophe());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ActionDialogBookmarkLoadFailed : public ActionDialog {
|
||||
public:
|
||||
ActionDialogBookmarkLoadFailed() : ActionDialog(wxGetApp().getAppFrame(), wxID_ANY, wxT("Bookmark Load Failure :(")) {
|
||||
m_questionText->SetLabelText(wxT("Sorry; unable to load your bookmarks file. \nWould you like to attempt to load the backup file?"));
|
||||
}
|
||||
|
||||
void doClickOK() {
|
||||
bool loadOk = false;
|
||||
if (wxGetApp().getBookmarkMgr().hasBackup("bookmarks.xml")) {
|
||||
loadOk = wxGetApp().getBookmarkMgr().loadFromFile("bookmarks.xml.backup",false);
|
||||
}
|
||||
if (loadOk) {
|
||||
wxGetApp().getBookmarkMgr().updateBookmarks();
|
||||
wxGetApp().getBookmarkMgr().updateActiveList();
|
||||
} else if (wxGetApp().getBookmarkMgr().hasLastLoad("bookmarks.xml")) {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkBackupLoadFailed());
|
||||
} else {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkCatastophe());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
CubicSDR::CubicSDR() : frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), agcMode(false)
|
||||
{
|
||||
sampleRateInitialized.store(false);
|
||||
agcMode.store(true);
|
||||
soloMode.store(false);
|
||||
@ -294,6 +354,19 @@ bool CubicSDR::OnInit() {
|
||||
// pthread_setschedparam(pthread_self(), main_policy, &main_param);
|
||||
//#endif
|
||||
|
||||
if (!wxGetApp().getBookmarkMgr().loadFromFile("bookmarks.xml")) {
|
||||
if (wxGetApp().getBookmarkMgr().hasBackup("bookmarks.xml")) {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkLoadFailed());
|
||||
} else if (wxGetApp().getBookmarkMgr().hasLastLoad("bookmarks.xml")) {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkBackupLoadFailed());
|
||||
} else {
|
||||
ActionDialog::showDialog(new ActionDialogBookmarkCatastophe());
|
||||
}
|
||||
} else {
|
||||
getBookmarkMgr().updateActiveList();
|
||||
getBookmarkMgr().updateBookmarks();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -405,7 +478,6 @@ bool CubicSDR::OnCmdLineParsed(wxCmdLineParser& parser) {
|
||||
}
|
||||
|
||||
config.load();
|
||||
wxGetApp().getBookmarkMgr().loadFromFile("bookmarks.xml");
|
||||
|
||||
#ifdef BUNDLE_SOAPY_MODS
|
||||
if (parser.Found("b")) {
|
||||
|
@ -102,7 +102,7 @@ BookmarkView::BookmarkView( wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
recentBranch = m_treeView->AppendItem(rootBranch, "Recents");
|
||||
|
||||
expandState["active"] = true;
|
||||
expandState["range"] = true;
|
||||
expandState["range"] = false;
|
||||
expandState["bookmark"] = true;
|
||||
expandState["recent"] = true;
|
||||
|
||||
@ -579,6 +579,16 @@ bool BookmarkView::isMouseInView() {
|
||||
}
|
||||
|
||||
|
||||
bool BookmarkView::getExpandState(std::string branchName) {
|
||||
return expandState[branchName];
|
||||
}
|
||||
|
||||
|
||||
void BookmarkView::setExpandState(std::string branchName, bool state) {
|
||||
expandState[branchName] = state;
|
||||
}
|
||||
|
||||
|
||||
void BookmarkView::hideProps() {
|
||||
m_frequencyLabel->Hide();
|
||||
m_frequencyVal->Hide();
|
||||
@ -940,7 +950,7 @@ void BookmarkView::rangeBranchSelection() {
|
||||
clearButtons();
|
||||
hideProps();
|
||||
|
||||
m_labelText->Clear();
|
||||
m_labelText->SetValue(wxT(""));
|
||||
m_labelText->Show();
|
||||
m_labelLabel->Show();
|
||||
|
||||
@ -1386,7 +1396,7 @@ void BookmarkView::onSearchText( wxCommandEvent& event ) {
|
||||
while(std::getline(searchTextLo, tmp, L' ')) {
|
||||
if (tmp.length() != 0 && tmp.find(L"search.") == wstring::npos) {
|
||||
searchKeywords.push_back(tmp);
|
||||
std::wcout << L"Keyword: " << tmp << '\n';
|
||||
// std::wcout << L"Keyword: " << tmp << '\n';
|
||||
}
|
||||
|
||||
}
|
||||
@ -1406,6 +1416,7 @@ void BookmarkView::onSearchText( wxCommandEvent& event ) {
|
||||
|
||||
|
||||
void BookmarkView::onClearSearch( wxCommandEvent& event ) {
|
||||
m_clearSearchButton->Hide();
|
||||
m_searchText->SetValue(L"Search..");
|
||||
m_treeView->SetFocus();
|
||||
if (!searchKeywords.empty()) {
|
||||
@ -1413,7 +1424,19 @@ void BookmarkView::onClearSearch( wxCommandEvent& event ) {
|
||||
}
|
||||
wxGetApp().getBookmarkMgr().updateActiveList();
|
||||
wxGetApp().getBookmarkMgr().updateBookmarks();
|
||||
m_clearSearchButton->Hide();
|
||||
refreshLayout();
|
||||
}
|
||||
|
||||
void BookmarkView::loadDefaultRanges() {
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"160 Meters",1900000,1800000,2000000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"80 Meters",3750000,3500000,4000000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"60 Meters",5368500,5332000,5405000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"40 Meters",7150000,7000000,7300000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"30 Meters",10125000,10100000,10150000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"20 Meters",14175000,14000000,14350000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"17 Meters",18068180,17044180,19092180));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"15 Meters",21225000,21000000,21450000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"12 Meters",24940000,24890000,24990000));
|
||||
wxGetApp().getBookmarkMgr().addRange(new BookmarkRangeEntry(L"10 Meters",28850000,28000000,29700000));
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,10 @@ public:
|
||||
void onMenuItem(wxCommandEvent& event);
|
||||
bool isMouseInView();
|
||||
|
||||
bool getExpandState(std::string branchName);
|
||||
void setExpandState(std::string branchName, bool state);
|
||||
|
||||
void loadDefaultRanges();
|
||||
|
||||
protected:
|
||||
void activeSelection(DemodulatorInstance *dsel);
|
||||
|
@ -34,18 +34,20 @@ void ActionDialog::setActiveDialog(ActionDialog *dlg) {
|
||||
|
||||
|
||||
void ActionDialog::onClickCancel( wxCommandEvent& event ) {
|
||||
doClickCancel();
|
||||
activeDialog->EndModal(0);
|
||||
ActionDialog *dlg = activeDialog;
|
||||
ActionDialog::setActiveDialog(nullptr);
|
||||
delete activeDialog;
|
||||
dlg->EndModal(0);
|
||||
doClickCancel();
|
||||
delete dlg;
|
||||
}
|
||||
|
||||
|
||||
void ActionDialog::onClickOK( wxCommandEvent& event ) {
|
||||
doClickOK();
|
||||
activeDialog->EndModal(0);
|
||||
ActionDialog *dlg = activeDialog;
|
||||
ActionDialog::setActiveDialog(nullptr);
|
||||
delete activeDialog;
|
||||
dlg->EndModal(0);
|
||||
doClickOK();
|
||||
delete dlg;
|
||||
}
|
||||
|
||||
|
||||
|
@ -561,6 +561,8 @@ DataNode *DataNode::newChildCloneFrom(const char *name_in, DataNode *cloneFrom)
|
||||
cloneNode->newChildCloneFrom(cNode->getName().c_str(), cNode);
|
||||
}
|
||||
|
||||
cloneFrom->rewind();
|
||||
|
||||
return children.back();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user