diff options
Diffstat (limited to 'ui/MainDialog.cpp')
-rw-r--r-- | ui/MainDialog.cpp | 882 |
1 files changed, 362 insertions, 520 deletions
diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp index 47926383..3f845364 100644 --- a/ui/MainDialog.cpp +++ b/ui/MainDialog.cpp @@ -15,16 +15,18 @@ #include <wx/file.h> #include "../library/customGrid.h" #include <algorithm> -#include "../library/processXml.h" +#include "../library/sorting.h" #include <wx/msgdlg.h> using namespace globalFunctions; using namespace xmlAccess; + int leadingPanel = 0; -MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language) : +MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings) : GuiGenerated(frame), + globalSettings(settings), programLanguage(language), filteringInitialized(false), filteringPending(false), @@ -49,6 +51,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale //initialize and load configuration readConfigurationFromXml(cfgFileName, true); + readGlobalSettings(); leftOnlyFilesActive = true; leftNewerFilesActive = true; @@ -186,6 +189,9 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale case wxLANGUAGE_JAPANESE: m_menuItemJapanese->Check(); break; + case wxLANGUAGE_DUTCH: + m_menuItemDutch->Check(); + break; default: m_menuItemEnglish->Check(); } @@ -238,16 +244,62 @@ MainDialog::~MainDialog() //save configuration writeConfigurationToXml(FreeFileSync::FfsLastConfigFile); //don't trow exceptions in destructors + writeGlobalSettings(); if (restartOnExit) //this is needed so that restart happens AFTER configuration was written! { //create new dialog - MainDialog* frame = new MainDialog(NULL, FreeFileSync::FfsLastConfigFile, programLanguage); + MainDialog* frame = new MainDialog(NULL, FreeFileSync::FfsLastConfigFile, programLanguage, globalSettings); frame->SetIcon(*globalResource.programIcon); //set application icon frame->Show(); } } +void MainDialog::readGlobalSettings() +{ + //apply window size and position at program startup ONLY + widthNotMaximized = globalSettings.gui.widthNotMaximized; + heightNotMaximized = globalSettings.gui.heightNotMaximized; + posXNotMaximized = globalSettings.gui.posXNotMaximized; + posYNotMaximized = globalSettings.gui.posYNotMaximized; + + //apply window size and position + if ( widthNotMaximized != wxDefaultCoord && + heightNotMaximized != wxDefaultCoord && + posXNotMaximized != wxDefaultCoord && + posYNotMaximized != wxDefaultCoord) + SetSize(posXNotMaximized, posYNotMaximized, widthNotMaximized, heightNotMaximized); + + Maximize(globalSettings.gui.isMaximized); + + //read column widths + for (int i = 0; i < m_grid1->GetNumberCols() && i < int(globalSettings.gui.columnWidthLeft.size()); ++i) + m_grid1->SetColSize(i, globalSettings.gui.columnWidthLeft[i]); + + for (int i = 0; i < m_grid2->GetNumberCols() && i < int(globalSettings.gui.columnWidthRight.size()); ++i) + m_grid2->SetColSize(i, globalSettings.gui.columnWidthRight[i]); +} + + +void MainDialog::writeGlobalSettings() +{ + //write global settings to (global) variable stored in application instance + globalSettings.gui.widthNotMaximized = widthNotMaximized; + globalSettings.gui.heightNotMaximized = heightNotMaximized; + globalSettings.gui.posXNotMaximized = posXNotMaximized; + globalSettings.gui.posYNotMaximized = posYNotMaximized; + globalSettings.gui.isMaximized = IsMaximized(); + + globalSettings.gui.columnWidthLeft.clear(); + for (int i = 0; i < m_grid1->GetNumberCols(); ++i) + globalSettings.gui.columnWidthLeft.push_back(m_grid1->GetColSize(i)); + + globalSettings.gui.columnWidthRight.clear(); + for (int i = 0; i < m_grid2->GetNumberCols(); ++i) + globalSettings.gui.columnWidthRight.push_back(m_grid2->GetColSize(i)); +} + + void MainDialog::onGrid1access(wxEvent& event) { if (leadingPanel != 1) @@ -307,7 +359,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View) { int gridSizeUI = gridRefUI.size(); - bool newSelection = false; //default: deselect range + bool newSelection = false; //default: deselect range //leadingRow determines de-/selection of all other rows int leadingRow = *rowsToFilterOnUI_View.begin(); @@ -315,7 +367,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View) newSelection = !currentGridData[gridRefUI[leadingRow]].selectedForSynchronization; if (hideFilteredElements) - assert (!newSelection); //if hidefiltered is active, there should be no filtered elements on screen => current element was filtered out + assert(!newSelection); //if hidefiltered is active, there should be no filtered elements on screen => current element was filtered out //get all lines that need to be filtered (e.g. if a folder is marked, then its subelements should be marked as well) @@ -340,33 +392,12 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View) m_grid1->ForceRefresh(); m_grid2->ForceRefresh(); m_grid3->ForceRefresh(); + Update(); //show changes resulting from ForceRefresh() if (hideFilteredElements) { - Update(); //show changes resulting from ForceRefresh() - - wxLongLong waitBegin = wxGetLocalTimeMillis(); - - //determine rows that are currently filtered out on current UI view (and need to be removed) - set<int> filteredOutRowsOnUI; - for (GridView::iterator i = gridRefUI.begin(); i != gridRefUI.end(); ++i) - { - const FileCompareLine& gridLine = currentGridData[*i]; - - if (!gridLine.selectedForSynchronization) - filteredOutRowsOnUI.insert(i - gridRefUI.begin()); - } - - //some delay to show user the rows he has filtered out before they are removed - unsigned long waitRemaining = max(400 - (wxGetLocalTimeMillis() - waitBegin).GetLo(), unsigned(0)); - wxMilliSleep(waitRemaining); //400 ms delay before rows are removed from UI - - //delete rows, that are filtered out: - removeRowsFromVector(gridRefUI, filteredOutRowsOnUI); - - //redraw grid necessary to update new dimensions - writeGrid(currentGridData, true); //use UI buffer, just a re-dimensioning of grids - updateStatusInformation(gridRefUI); //status information has to be recalculated! + wxMilliSleep(400); //some delay to show user the rows he has filtered out before they are removed + writeGrid(currentGridData); //redraw grid to remove excluded elements (keeping sort sequence) } } @@ -379,6 +410,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View) m_grid3->ClearSelection(); } + /*grid event choreography: 1. UI-Mouse-Down => OnGridSelectCell 2. UI-Mouse-Up => SelectRangeEvent (if at least two rows are marked) @@ -572,18 +604,18 @@ set<int> MainDialog::getSelectedRows() } -class DeleteStatusUpdater : public StatusUpdater +class DeleteErrorHandler : public ErrorHandler { public: - DeleteStatusUpdater(bool& unsolvedErrorOccured) : continueOnError(false), unsolvedErrors(unsolvedErrorOccured) {} - ~DeleteStatusUpdater() {} + DeleteErrorHandler(bool& unsolvedErrorOccured) : continueOnError(false), unsolvedErrors(unsolvedErrorOccured) {} + ~DeleteErrorHandler() {} - int reportError(const wxString& text) + Response reportError(const wxString& text) { if (continueOnError) { unsolvedErrors = true; - return StatusUpdater::continueNext; + return ErrorHandler::CONTINUE_NEXT; } wxString errorMessage = text + _("\n\nInformation: If you skip the error and continue or abort a re-compare will be necessary!"); @@ -595,12 +627,12 @@ public: switch (rv) { - case ErrorDlg::continueButtonPressed: + case ErrorDlg::BUTTON_CONTINUE: unsolvedErrors = true; - return StatusUpdater::continueNext; - case ErrorDlg::retryButtonPressed: - return StatusUpdater::retry; - case ErrorDlg::abortButtonPressed: + return ErrorHandler::CONTINUE_NEXT; + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + case ErrorDlg::BUTTON_ABORT: { unsolvedErrors = true; throw AbortThisProcess(); @@ -609,14 +641,9 @@ public: assert (false); } - return StatusUpdater::continueNext; //dummy return value + return ErrorHandler::CONTINUE_NEXT; //dummy return value } - void updateStatusText(const wxString& text) {} - void initNewProcess(int objectsTotal, double dataTotal, int processID) {} - void updateProcessedData(int objectsProcessed, double dataProcessed) {} - void forceUiRefresh() {} private: - void abortThisProcess() {} bool continueOnError; bool& unsolvedErrors; @@ -644,11 +671,11 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI) { const FileCompareLine& currentCmpLine = currentGridData[*i]; - if (currentCmpLine.fileDescrLeft.objType != TYPE_NOTHING) - filesToDelete+= currentCmpLine.fileDescrLeft.filename + wxT("\n"); + if (currentCmpLine.fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) + filesToDelete+= currentCmpLine.fileDescrLeft.fullName + wxT("\n"); - if (currentCmpLine.fileDescrRight.objType != TYPE_NOTHING) - filesToDelete+= currentCmpLine.fileDescrRight.filename + wxT("\n"); + if (currentCmpLine.fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) + filesToDelete+= currentCmpLine.fileDescrRight.fullName + wxT("\n"); filesToDelete+= wxT("\n"); } @@ -657,38 +684,35 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI) switch (confirmDeletion->ShowModal()) { - case DeleteDialog::okayButtonPressed: + case DeleteDialog::BUTTON_OKAY: { bool unsolvedErrorOccured = false; //if an error is skipped a re-compare will be necessary! try - { //class errors when deleting files/folders - DeleteStatusUpdater deleteStatusUpdater(unsolvedErrorOccured); + { //handle errors when deleting files/folders + DeleteErrorHandler errorHandler(unsolvedErrorOccured); - FreeFileSync::deleteOnGridAndHD(currentGridData, rowsToDeleteOnGrid, &deleteStatusUpdater, cfg.useRecycleBin); + FreeFileSync::deleteOnGridAndHD(currentGridData, rowsToDeleteOnGrid, &errorHandler, cfg.useRecycleBin); } catch (AbortThisProcess& theException) {} - //disable the sync button if errors occured during deletion if (unsolvedErrorOccured) enableSynchronization(false); - //redraw grid neccessary to update new dimensions and for UI-Backend data linkage - writeGrid(currentGridData); //do NOT use UI buffer here + writeGrid(currentGridData); - m_grid1->ClearSelection(); //clear selection on grid - m_grid2->ClearSelection(); //clear selection on grid - m_grid3->ClearSelection(); //clear selection on grid + m_grid1->ClearSelection(); + m_grid2->ClearSelection(); + m_grid3->ClearSelection(); } break; - case DeleteDialog::cancelButtonPressed: + case DeleteDialog::BUTTON_CANCEL: default: break; - } } } @@ -703,10 +727,9 @@ void MainDialog::openWithFileBrowser(int rowNumber, int gridNr) if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) { - wxString filename = currentGridData[gridRefUI[rowNumber]].fileDescrLeft.filename; - - if (!filename.IsEmpty()) - command = wxString(wxT("explorer /select,")) + filename; + const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrLeft; + if (fileDescr.objType != FileDescrLine::TYPE_NOTHING) + command = wxString(wxT("explorer /select,")) + fileDescr.fullName; } wxExecute(command); } @@ -716,10 +739,9 @@ void MainDialog::openWithFileBrowser(int rowNumber, int gridNr) if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) { - wxString filename = currentGridData[gridRefUI[rowNumber]].fileDescrRight.filename; - - if (!filename.IsEmpty()) - command = wxString(wxT("explorer /select,")) + filename; + const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrRight; + if (fileDescr.objType != FileDescrLine::TYPE_NOTHING) + command = wxString(wxT("explorer /select,")) + fileDescr.fullName; } wxExecute(command); } @@ -816,57 +838,13 @@ void MainDialog::onGrid3ButtonEvent(wxKeyEvent& event) } -inline -wxString getFilename(const FileDescrLine* fileDescr) -{ - if (!fileDescr || fileDescr->objType != TYPE_FILE) - return wxEmptyString; - else - return fileDescr->relFilename.AfterLast(GlobalResources::fileNameSeparator); -} - - -inline -wxString getFileExtension(const FileDescrLine* fileDescr) -{ - if (!fileDescr || fileDescr->objType != TYPE_FILE) - return wxEmptyString; - else - { - wxString filename = getFilename(fileDescr); - - if (filename.Find(wxChar('.')) != wxNOT_FOUND) //be careful: AfterLast will return the whole string if '.' is not found! - return filename.AfterLast(wxChar('.')); - else - return wxEmptyString; - } -} - - -inline -wxString getDirname(const FileDescrLine* fileDescr) -{ - if (!fileDescr || fileDescr->objType != TYPE_DIRECTORY) - return wxEmptyString; - else - return fileDescr->filename.AfterLast(GlobalResources::fileNameSeparator); -} - - -inline -wxString getRelativeName(const FileDescrLine* fileDescr) -{ - if (!fileDescr || fileDescr->objType == TYPE_NOTHING) - return wxEmptyString; - else - return fileDescr->relFilename; -} - - void MainDialog::OnOpenContextMenu(wxGridEvent& event) { set<int> selection = getSelectedRows(); + exFilterCandidateExtension.Clear(); + exFilterCandidateObj.clear(); + //####################################################### //re-create context menu delete contextMenu; @@ -875,31 +853,49 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event) //dynamic filter determination if (selection.size() > 0) { - const FileCompareLine& cmpLine = currentGridData[gridRefUI[*selection.begin()]]; + const FileCompareLine& firstLine = currentGridData[gridRefUI[*selection.begin()]]; - if (cmpLine.selectedForSynchronization) + if (firstLine.selectedForSynchronization) contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily")); else contextMenu->Append(CONTEXT_FILTER_TEMP, _("Include temporarily")); - - const FileDescrLine* fileDescr = NULL; + //get list of relative file/dir-names into vectors + FilterObject newFilterEntry; if (leadingPanel == 1) - fileDescr = &cmpLine.fileDescrLeft; + for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i) + { + const FileCompareLine& line = currentGridData[gridRefUI[*i]]; + newFilterEntry.relativeName = line.fileDescrLeft.relativeName; + newFilterEntry.type = line.fileDescrLeft.objType; + if (!newFilterEntry.relativeName.IsEmpty()) + exFilterCandidateObj.push_back(newFilterEntry); + } else if (leadingPanel == 2) - fileDescr = &cmpLine.fileDescrRight; + for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i) + { + const FileCompareLine& line = currentGridData[gridRefUI[*i]]; + newFilterEntry.relativeName = line.fileDescrRight.relativeName; + newFilterEntry.type = line.fileDescrRight.objType; + if (!newFilterEntry.relativeName.IsEmpty()) + exFilterCandidateObj.push_back(newFilterEntry); + } - exFilterCandidateExtension = getFileExtension(fileDescr); //avoid re-determination in onContextMenuSelection() - if (!exFilterCandidateExtension.IsEmpty()) - contextMenu->Append(CONTEXT_EXCLUDE_EXT, wxString(_("Add to exclude filter: ")) + wxT("*.") + exFilterCandidateExtension); - exFilterCandidateFilename = getFilename(fileDescr); - if (!exFilterCandidateFilename.IsEmpty()) - contextMenu->Append(CONTEXT_EXCLUDE_FILE, wxString(_("Add to exclude filter: ")) + exFilterCandidateFilename); + if (exFilterCandidateObj.size() > 0 && exFilterCandidateObj[0].type == FileDescrLine::TYPE_FILE) + { + const wxString filename = exFilterCandidateObj[0].relativeName.AfterLast(GlobalResources::fileNameSeparator); + if (filename.Find(wxChar('.')) != wxNOT_FOUND) //be careful: AfterLast will return the whole string if '.' is not found! + { + exFilterCandidateExtension = filename.AfterLast(wxChar('.')); + contextMenu->Append(CONTEXT_EXCLUDE_EXT, wxString(_("Add to exclude filter: ")) + wxT("*.") + exFilterCandidateExtension); + } + } - exFilterCandidateDirname = getDirname(fileDescr); - if (!exFilterCandidateDirname.IsEmpty()) - contextMenu->Append(CONTEXT_EXCLUDE_DIR, wxString(_("Add to exclude filter: ")) + exFilterCandidateDirname); + if (exFilterCandidateObj.size() == 1) + contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + exFilterCandidateObj[0].relativeName); + else if (exFilterCandidateObj.size() > 1) + contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + _("<multiple selection>")); } else contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily")); //this element should always be visible @@ -967,31 +963,26 @@ void MainDialog::onContextMenuSelection(wxCommandEvent& event) writeGrid(currentGridData); } } - else if (eventId == CONTEXT_EXCLUDE_FILE) - { - if (!exFilterCandidateFilename.IsEmpty()) - { - if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n"))) - cfg.excludeFilter+= wxT("\n"); - - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateFilename; - - cfg.filterIsActive = true; - updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - - FreeFileSync::filterCurrentGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); - writeGrid(currentGridData); - } - } - else if (eventId == CONTEXT_EXCLUDE_DIR) + else if (eventId == CONTEXT_EXCLUDE_OBJ) { - if (!exFilterCandidateDirname.IsEmpty()) + if (exFilterCandidateObj.size() > 0) //check needed to determine if filtering is needed { - if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n"))) - cfg.excludeFilter+= wxT("\n"); + for (vector<FilterObject>::const_iterator i = exFilterCandidateObj.begin(); i != exFilterCandidateObj.end(); ++i) + { + if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n"))) + cfg.excludeFilter+= wxT("\n"); - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateDirname + wxT("\n"); - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateDirname + GlobalResources::fileNameSeparator + wxT("*"); + if (i->type == FileDescrLine::TYPE_FILE) + { + cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName; + } + else if (i->type == FileDescrLine::TYPE_DIRECTORY) + { + cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName + wxT("\n"); + cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName + GlobalResources::fileNameSeparator + wxT("*"); + } + else assert(false); + } cfg.filterIsActive = true; updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); @@ -1358,161 +1349,87 @@ void MainDialog::OnQuit(wxCommandEvent &event) } -void MainDialog::loadDefaultConfiguration() -{ - //default values - cfg.syncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT; - cfg.syncConfiguration.exRightSideOnly = SYNC_DIR_RIGHT; - cfg.syncConfiguration.leftNewer = SYNC_DIR_RIGHT; - cfg.syncConfiguration.rightNewer = SYNC_DIR_RIGHT; - cfg.syncConfiguration.different = SYNC_DIR_RIGHT; - - cfg.compareVar = CMP_BY_TIME_SIZE; //compare algorithm - updateCompareButtons(); - - cfg.includeFilter = wxT("*"); //include all files/folders - cfg.excludeFilter = wxEmptyString; //exclude nothing - - //set status of filter button - cfg.filterIsActive = false; //do not filter by default - updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - - cfg.useRecycleBin = FreeFileSync::recycleBinExists(); //enable if OS supports it; else user will have to activate first and then get the error message - cfg.continueOnError = false; - - //set status of "hide filtered items" checkbox - hideFilteredElements = false; //show filtered items - m_checkBoxHideFilt->SetValue(hideFilteredElements); - - widthNotMaximized = wxDefaultCoord; - heightNotMaximized = wxDefaultCoord; - posXNotMaximized = wxDefaultCoord; - posYNotMaximized = wxDefaultCoord; -} - - bool MainDialog::readConfigurationFromXml(const wxString& filename, bool programStartup) { //load XML - XmlInput inputFile(filename, XML_GUI_CONFIG); - - if (!inputFile.loadedSuccessfully()) - { //handle error: file load - if (programStartup) - loadDefaultConfiguration(); - else - wxMessageBox(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR); - return false; + XmlGuiConfig guiCfg; //structure to receive gui settings, already defaulted!! + try + { + guiCfg = xmlAccess::readGuiConfig(filename); } - - XmlMainConfig mainCfg; //structure to receive main settings - XmlGuiConfig guiCfg; //structure to receive gui settings - if ( inputFile.readXmlMainConfig(mainCfg) && //read main configuration settings - inputFile.readXmlGuiConfig(guiCfg)) //read GUI layout configuration + catch (const FileError& error) { - //load main configuration into instance - cfg = mainCfg.cfg; + if (programStartup && filename == FreeFileSync::FfsLastConfigFile && !wxFileExists(filename)) //do not show error in this case + ; + else if (!programStartup) + { + wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR); + return false; + } + else //program startup: show error message and load defaults + wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR); + } - //update visible config on main window - updateCompareButtons(); - updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); + //load main configuration into instance + cfg = guiCfg.mainCfg; - //read folder pairs, but first: clear existing pairs: - removeFolderPair(true); + //update visible config on main window + updateCompareButtons(); + updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - //set main folder pair - if (mainCfg.directoryPairs.size() > 0) - { - vector<FolderPair>::const_iterator i = mainCfg.directoryPairs.begin(); + //read folder pairs, but first: clear existing pairs: + removeFolderPair(true); - m_directoryLeft->SetValue(i->leftDirectory); - wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(i->leftDirectory); - if (wxDirExists(leftDirFormatted)) - m_dirPicker1->SetPath(leftDirFormatted); + //set main folder pair + if (guiCfg.directoryPairs.size() > 0) + { + vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin(); - m_directoryRight->SetValue(i->rightDirectory); - wxString rightDirFormatted = FreeFileSync::getFormattedDirectoryName(i->rightDirectory); - if (wxDirExists(rightDirFormatted)) - m_dirPicker2->SetPath(rightDirFormatted); + m_directoryLeft->SetValue(i->leftDirectory); + wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(i->leftDirectory); + if (wxDirExists(leftDirFormatted)) + m_dirPicker1->SetPath(leftDirFormatted); - //set additional pairs - for (vector<FolderPair>::const_iterator i = mainCfg.directoryPairs.begin() + 1; i != mainCfg.directoryPairs.end(); ++i) - addFolderPair(i->leftDirectory, i->rightDirectory); - } + m_directoryRight->SetValue(i->rightDirectory); + wxString rightDirFormatted = FreeFileSync::getFormattedDirectoryName(i->rightDirectory); + if (wxDirExists(rightDirFormatted)) + m_dirPicker2->SetPath(rightDirFormatted); - //read GUI layout (optional!) - hideFilteredElements = guiCfg.hideFilteredElements; - m_checkBoxHideFilt->SetValue(hideFilteredElements); + //set additional pairs + for (vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin() + 1; i != guiCfg.directoryPairs.end(); ++i) + addFolderPair(i->leftDirectory, i->rightDirectory); + } - //apply window size and position at program startup ONLY - if (programStartup) - { - if ( guiCfg.widthNotMaximized != -1 && - guiCfg.heightNotMaximized != -1 && - guiCfg.posXNotMaximized != -1 && - guiCfg.posYNotMaximized != -1) - { - widthNotMaximized = guiCfg.widthNotMaximized; - heightNotMaximized = guiCfg.heightNotMaximized; - posXNotMaximized = guiCfg.posXNotMaximized; - posYNotMaximized = guiCfg.posYNotMaximized; - - //apply window size and position - SetSize(posXNotMaximized, posYNotMaximized, widthNotMaximized, heightNotMaximized); - Maximize(guiCfg.isMaximized); - } - //read column widths - for (int i = 0; i < m_grid1->GetNumberCols() && i < int(guiCfg.columnWidthLeft.size()); ++i) - m_grid1->SetColSize(i, guiCfg.columnWidthLeft[i]); + //read GUI layout (optional!) + hideFilteredElements = guiCfg.hideFilteredElements; + m_checkBoxHideFilt->SetValue(hideFilteredElements); - for (int i = 0; i < m_grid2->GetNumberCols() && i < int(guiCfg.columnWidthRight.size()); ++i) - m_grid2->SetColSize(i, guiCfg.columnWidthRight[i]); - } - //########################################################### - addCfgFileToHistory(filename); //put filename on list of last used config files - return true; - } - else - { //handle error: parsing - wxMessageBox(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR); - if (programStartup) - loadDefaultConfiguration(); - return false; - } + //########################################################### + addCfgFileToHistory(filename); //put filename on list of last used config files + return true; } bool MainDialog::writeConfigurationToXml(const wxString& filename) { - XmlOutput outputFile(filename, XML_GUI_CONFIG); + XmlGuiConfig guiCfg; //load structure with basic settings "mainCfg" - XmlMainConfig mainCfg; - mainCfg.cfg = cfg; - GetFolderPairs(mainCfg.directoryPairs); + guiCfg.mainCfg = cfg; + GetFolderPairs(guiCfg.directoryPairs); - //load structure with gui settings "guiCfg" - XmlGuiConfig guiCfg; + //load structure with gui settings guiCfg.hideFilteredElements = hideFilteredElements; - guiCfg.widthNotMaximized = widthNotMaximized; - guiCfg.heightNotMaximized = heightNotMaximized; - guiCfg.posXNotMaximized = posXNotMaximized; - guiCfg.posYNotMaximized = posYNotMaximized; - guiCfg.isMaximized = IsMaximized(); - - for (int i = 0; i < m_grid1->GetNumberCols(); ++i) - guiCfg.columnWidthLeft.push_back(m_grid1->GetColSize(i)); - for (int i = 0; i < m_grid2->GetNumberCols(); ++i) - guiCfg.columnWidthRight.push_back(m_grid2->GetColSize(i)); - - //populate and write XML tree - if ( !outputFile.writeXmlMainConfig(mainCfg) || //add basic configuration settings - !outputFile.writeXmlGuiConfig(guiCfg) || //add GUI layout configuration settings - !outputFile.writeToFile()) //save XML + //write config to XML + try + { + xmlAccess::writeGuiConfig(filename, guiCfg); + } + catch (const FileError& error) { - wxMessageBox(wxString(_("Could not write configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR); return false; } @@ -1563,7 +1480,7 @@ void MainDialog::OnConfigureFilter(wxHyperlinkEvent &event) wxString beforeImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; FilterDlg* filterDlg = new FilterDlg(this, cfg.includeFilter, cfg.excludeFilter); - if (filterDlg->ShowModal() == FilterDlg::okayButtonPressed) + if (filterDlg->ShowModal() == FilterDlg::BUTTON_OKAY) { wxString afterImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; @@ -1640,34 +1557,70 @@ void MainDialog::OnEqualFiles(wxCommandEvent& event) void MainDialog::updateViewFilterButtons() { if (leftOnlyFilesActive) - m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnly); + { + m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnlyAct); + m_bpButtonLeftOnly->SetToolTip(_("Hide files that exist on left side only")); + } else + { m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnlyDeact); + m_bpButtonLeftOnly->SetToolTip(_("Show files that exist on left side only")); + } if (leftNewerFilesActive) - m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewer); + { + m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewerAct); + m_bpButtonLeftNewer->SetToolTip(_("Hide files that are newer on left")); + } else + { m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewerDeact); + m_bpButtonLeftNewer->SetToolTip(_("Show files that are newer on left")); + } if (equalFilesActive) - m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqual); + { + m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqualAct); + m_bpButtonEqual->SetToolTip(_("Hide files that are equal")); + } else + { m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqualDeact); + m_bpButtonEqual->SetToolTip(_("Show files that are equal")); + } if (differentFilesActive) - m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferent); + { + m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferentAct); + m_bpButtonDifferent->SetToolTip(_("Hide files that are different")); + } else + { m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferentDeact); + m_bpButtonDifferent->SetToolTip(_("Show files that are different")); + } if (rightNewerFilesActive) - m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewer); + { + m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerAct); + m_bpButtonRightNewer->SetToolTip(_("Hide files that are newer on right")); + } else + { m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerDeact); + m_bpButtonRightNewer->SetToolTip(_("Show files that are newer on right")); + } if (rightOnlyFilesActive) - m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnly); + { + m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyAct); + m_bpButtonRightOnly->SetToolTip(_("Hide files that exist on right side only")); + } else + { m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyDeact); + m_bpButtonRightOnly->SetToolTip(_("Show files that exist on right side only")); + } } @@ -1772,13 +1725,10 @@ void MainDialog::OnCompare(wxCommandEvent &event) CompareStatusUpdater statusUpdater(this); cmpStatusUpdaterTmp = &statusUpdater; - //unsigned int startTime3 = GetTickCount(); - FreeFileSync::startCompareProcess(currentGridData, - directoryPairsFormatted, + FreeFileSync::startCompareProcess(directoryPairsFormatted, cfg.compareVar, + currentGridData, &statusUpdater); - //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3)); - //filter currentGridData if option is set if (cfg.filterIsActive) @@ -1802,6 +1752,10 @@ void MainDialog::OnCompare(wxCommandEvent &event) { //once compare is finished enable the sync button enableSynchronization(true); m_bpButtonSync->SetFocus(); + + //hide sort direction indicator on GUI grids + m_grid1->setSortMarker(-1); + m_grid2->setSortMarker(-1); } wxEndBusyCursor(); @@ -1817,23 +1771,17 @@ void MainDialog::OnAbortCompare(wxCommandEvent& event) } -void MainDialog::writeGrid(const FileCompareResult& gridData, bool useUI_GridCache) +void MainDialog::writeGrid(const FileCompareResult& gridData) { m_grid1->BeginBatch(); m_grid2->BeginBatch(); m_grid3->BeginBatch(); - if (!useUI_GridCache) - { - //unsigned int startTime = GetTickCount(); - mapGridDataToUI(gridRefUI, gridData); //update gridRefUI - //wxMessageBox(wxString("Benchmark: ") + numberToWxString(unsigned(GetTickCount()) - startTime) + " ms"); - - updateStatusInformation(gridRefUI); //write status information for gridRefUI - } + mapGridDataToUI(gridRefUI, gridData); //update gridRefUI + updateStatusInformation(gridRefUI); //write status information for gridRefUI - //all three grids retrieve their data directly from currentGridData!!! - //the only thing left to do is notify the grids to update their sizes (nr of rows), since this has to be communicated via messages by the grids + //all three grids retrieve their data directly via gridRefUI!!! + //the only thing left to do is notify the grids to update their sizes (nr of rows), since this has to be communicated by the grids via messages m_grid1->updateGridSizes(); m_grid2->updateGridSizes(); m_grid3->updateGridSizes(); @@ -1847,11 +1795,6 @@ void MainDialog::writeGrid(const FileCompareResult& gridData, bool useUI_GridCac m_grid2->SetRowLabelSize(nrOfDigits * 8 + 4); } - //hide sort direction indicator on UI grids - m_grid1->setSortMarker(-1); - m_grid2->setSortMarker(-1); - - m_grid1->EndBatch(); m_grid2->EndBatch(); m_grid3->EndBatch(); @@ -1884,17 +1827,13 @@ void MainDialog::OnSync(wxCommandEvent& event) wxBeginBusyCursor(); clearStatusBar(); - try { //class handling status updates and error messages SyncStatusUpdater statusUpdater(this, cfg.continueOnError); //start synchronization and return elements that were not sync'ed in currentGridData - - //unsigned int startTime3 = GetTickCount(); FreeFileSync::startSynchronizationProcess(currentGridData, cfg.syncConfiguration, &statusUpdater, cfg.useRecycleBin); - //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3)); } catch (AbortThisProcess& theException) { //do NOT disable the sync button: user might want to try to sync the REMAINING rows @@ -1912,7 +1851,6 @@ void MainDialog::OnSync(wxCommandEvent& event) enableSynchronization(false); } - wxEndBusyCursor(); } event.Skip(); @@ -1933,170 +1871,37 @@ void MainDialog::OnRightGridDoubleClick(wxGridEvent& event) } -//these three global variables are ONLY used for the sorting in the following methods -unsigned int currentSortColumn = 0; -bool sortAscending = true; -FileCompareResult* currentGridDataPtr = 0; - -inline -bool cmpString(const wxString& a, const wxString& b) -{ - if (a.IsEmpty()) - return false; // if a and b are empty: false, if a empty, b not empty: also false, since empty rows should appear at the end - else if (b.IsEmpty()) - return true; // empty rows after filled rows: return true - - //if a and b not empty: - if (sortAscending) - return (a < b); - else return (a > b); -} - - -inline -bool cmpLargeInt(const wxULongLong& a, const wxULongLong& b) -{ - if (sortAscending) - return (a < b); - - return (a > b); -} - - -bool sortGridLeft(const GridViewLine a, const GridViewLine b) -{ - const FileDescrLine& gridDataLineA = (*currentGridDataPtr)[a].fileDescrLeft; - const FileDescrLine& gridDataLineB = (*currentGridDataPtr)[b].fileDescrLeft; - - wxString stringA; - wxString stringB; - - switch (currentSortColumn) - { - case 0: - //presort types: first files, then directories then empty rows - if (gridDataLineA.objType == TYPE_NOTHING) - return false; //empty rows always last - else if (gridDataLineB.objType == TYPE_NOTHING) - return true; //empty rows always last - else if (gridDataLineA.objType == TYPE_DIRECTORY) - return false; - else if (gridDataLineB.objType == TYPE_DIRECTORY) - return true; - else - return cmpString(gridDataLineA.relFilename.AfterLast(GlobalResources::fileNameSeparator), - gridDataLineB.relFilename.AfterLast(GlobalResources::fileNameSeparator)); - case 1: - if (gridDataLineA.objType == TYPE_DIRECTORY) - stringA = gridDataLineA.relFilename; - else - stringA = gridDataLineA.relFilename.BeforeLast(GlobalResources::fileNameSeparator); - - if (gridDataLineB.objType == TYPE_DIRECTORY) - stringB = gridDataLineB.relFilename; - else - stringB = gridDataLineB.relFilename.BeforeLast(GlobalResources::fileNameSeparator); - - return cmpString(stringA, stringB); - - case 2: - //presort types: first files, then directories then empty rows - if (gridDataLineA.objType == TYPE_NOTHING) - return false; //empty rows always last - else if (gridDataLineB.objType == TYPE_NOTHING) - return true; //empty rows always last - else if (gridDataLineA.objType == TYPE_DIRECTORY) - return false; - else if (gridDataLineB.objType == TYPE_DIRECTORY) - return true; - else //use unformatted filesizes and sort by size - return cmpLargeInt(gridDataLineA.fileSize, gridDataLineB.fileSize); - - case 3: - return cmpString(gridDataLineA.lastWriteTime, gridDataLineB.lastWriteTime); - - default: - assert(false); - return true; //dummy command - } -} - - -bool sortGridRight(const GridViewLine a, const GridViewLine b) -{ - const FileDescrLine& gridDataLineA = (*currentGridDataPtr)[a].fileDescrRight; - const FileDescrLine& gridDataLineB = (*currentGridDataPtr)[b].fileDescrRight; - - wxString stringA; - wxString stringB; - - switch (currentSortColumn) - { - case 0: - //presort types: first files, then directories then empty rows - if (gridDataLineA.objType == TYPE_NOTHING) - return false; //empty rows always last - else if (gridDataLineB.objType == TYPE_NOTHING) - return true; //empty rows always last - else if (gridDataLineA.objType == TYPE_DIRECTORY) - return false; - else if (gridDataLineB.objType == TYPE_DIRECTORY) - return true; - else - return cmpString(gridDataLineA.relFilename.AfterLast(GlobalResources::fileNameSeparator), - gridDataLineB.relFilename.AfterLast(GlobalResources::fileNameSeparator)); - - case 1: - if (gridDataLineA.objType == TYPE_DIRECTORY) - stringA = gridDataLineA.relFilename; - else - stringA = gridDataLineA.relFilename.BeforeLast(GlobalResources::fileNameSeparator); - - if (gridDataLineB.objType == TYPE_DIRECTORY) - stringB = gridDataLineB.relFilename; - else - stringB = gridDataLineB.relFilename.BeforeLast(GlobalResources::fileNameSeparator); - - return cmpString(stringA, stringB); - - case 2: - //presort types: first files, then directories then empty rows - if (gridDataLineA.objType == TYPE_NOTHING) - return false; //empty rows always last - else if (gridDataLineB.objType == TYPE_NOTHING) - return true; //empty rows always last - else if (gridDataLineA.objType == TYPE_DIRECTORY) - return false; - else if (gridDataLineB.objType == TYPE_DIRECTORY) - return true; - else //use unformatted filesizes and sort by size - return cmpLargeInt(gridDataLineA.fileSize, gridDataLineB.fileSize); - - case 3: - return cmpString(gridDataLineA.lastWriteTime, gridDataLineB.lastWriteTime); - - default: - assert(false); - return true; //dummy command - } -} - - void MainDialog::OnSortLeftGrid(wxGridEvent& event) { static bool columnSortAscending[4] = {true, true, false, true}; - currentSortColumn = event.GetCol(); - currentGridDataPtr = ¤tGridData; + int currentSortColumn = event.GetCol(); if (0 <= currentSortColumn && currentSortColumn <= 3) { - sortAscending = columnSortAscending[currentSortColumn]; - columnSortAscending[currentSortColumn] = !columnSortAscending[currentSortColumn]; - sort(gridRefUI.begin(), gridRefUI.end(), sortGridLeft); + bool& sortAscending = columnSortAscending[currentSortColumn]; - m_grid1->ForceRefresh(); - m_grid2->ForceRefresh(); - m_grid3->ForceRefresh(); + if (currentSortColumn == 0) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_LEFT>); //probably faster than qsort(), since gridRefUI is vector<int> + else sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_LEFT>); + } + else if (currentSortColumn == 1) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_LEFT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_LEFT>); + } + else if (currentSortColumn == 2) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_LEFT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_LEFT>); + } + else if (currentSortColumn == 3) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_LEFT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_LEFT>); + } + + writeGrid(currentGridData); //needed to refresh gridRefUI references //set sort direction indicator on UI if (sortAscending) @@ -2104,6 +1909,8 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event) else m_grid1->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown); m_grid2->setSortMarker(-1); + + sortAscending = !sortAscending; } event.Skip(); } @@ -2113,17 +1920,33 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) { static bool columnSortAscending[4] = {true, true, false, true}; - currentSortColumn = event.GetCol(); - currentGridDataPtr = ¤tGridData; + int currentSortColumn = event.GetCol(); if (0 <= currentSortColumn && currentSortColumn <= 3) { - sortAscending = columnSortAscending[currentSortColumn]; - columnSortAscending[currentSortColumn] = !columnSortAscending[currentSortColumn]; - sort(gridRefUI.begin(), gridRefUI.end(), sortGridRight); + bool& sortAscending = columnSortAscending[currentSortColumn]; - m_grid1->ForceRefresh(); - m_grid2->ForceRefresh(); - m_grid3->ForceRefresh(); + if (currentSortColumn == 0) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_RIGHT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_RIGHT>); + } + else if (currentSortColumn == 1) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_RIGHT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_RIGHT>); + } + else if (currentSortColumn == 2) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_RIGHT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_RIGHT>); + } + else if (currentSortColumn == 3) + { + if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_RIGHT>); + else sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_RIGHT>); + } + + writeGrid(currentGridData); //needed to refresh gridRefUI references //set sort direction indicator on UI m_grid1->setSortMarker(-1); @@ -2131,6 +1954,8 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) m_grid2->setSortMarker(currentSortColumn, globalResource.bitmapSmallUp); else m_grid2->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown); + + sortAscending = !sortAscending; } event.Skip(); } @@ -2180,26 +2005,26 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) const FileCompareLine& refLine = currentGridData[*i]; //calculate total number of bytes for each side - if (refLine.fileDescrLeft.objType == TYPE_FILE) + if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE) { filesizeLeftView+= refLine.fileDescrLeft.fileSize; ++filesOnLeftView; } - else if (refLine.fileDescrLeft.objType == TYPE_DIRECTORY) + else if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) ++foldersOnLeftView; - if (refLine.fileDescrRight.objType == TYPE_FILE) + if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE) { filesizeRightView+= refLine.fileDescrRight.fileSize; ++filesOnRightView; } - else if (refLine.fileDescrRight.objType == TYPE_DIRECTORY) + else if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) ++foldersOnRightView; } //################################################# -// format numbers to text +//format numbers to text: -//show status information on "root" level. This cannot be accomplished in writeGrid since filesizes are already formatted for display there +//show status information on "root" level. if (foldersOnLeftView) { wxString folderCount = numberToWxString(foldersOnLeftView); @@ -2292,6 +2117,10 @@ void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& file unsigned int currentRow = 0; for (FileCompareResult::const_iterator i = fileCmpResult.begin(); i != fileCmpResult.end(); ++i, ++currentRow) { + //hide filtered row, if corresponding option is set + if (hideFilteredElements && !i->selectedForSynchronization) + continue; + //process UI filter settings switch (i->cmpResult) { @@ -2322,11 +2151,6 @@ void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& file default: assert (false); } - - //hide filtered row, if corresponding option is set - if (hideFilteredElements && !i->selectedForSynchronization) - continue; - output.push_back(currentRow); } @@ -2476,7 +2300,7 @@ void MainDialog::removeFolderPair(bool removeAll) CompareStatusUpdater::CompareStatusUpdater(MainDialog* dlg) : mainDialog(dlg), continueOnError(false), - currentProcess(-1) + currentProcess(StatusHandler::PROCESS_NONE) { //prevent user input during "compare", do not disable maindialog since abort-button would also be disabled //it's not nice, but works - even has the advantage that certain actions are still possible: exit, about.. @@ -2578,13 +2402,13 @@ void CompareStatusUpdater::updateStatusText(const wxString& text) } -void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID) +void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, Process processID) { currentProcess = processID; - if (currentProcess == FreeFileSync::scanningFilesProcess) + if (currentProcess == StatusHandler::PROCESS_SCANNING) ; - else if (currentProcess == FreeFileSync::compareFileContentProcess) + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) { mainDialog->compareStatus->switchToCompareBytewise(objectsTotal, dataTotal); mainDialog->Layout(); @@ -2597,18 +2421,18 @@ void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, in inline void CompareStatusUpdater::updateProcessedData(int objectsProcessed, double dataProcessed) { - if (currentProcess == FreeFileSync::scanningFilesProcess) + if (currentProcess == StatusHandler::PROCESS_SCANNING) mainDialog->compareStatus->incScannedObjects_NoUpdate(objectsProcessed); - else if (currentProcess == FreeFileSync::compareFileContentProcess) + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) mainDialog->compareStatus->incProcessedCmpData_NoUpdate(objectsProcessed, dataProcessed); else assert(false); } -int CompareStatusUpdater::reportError(const wxString& text) +ErrorHandler::Response CompareStatusUpdater::reportError(const wxString& text) { if (continueOnError) - return StatusUpdater::continueNext; + return ErrorHandler::CONTINUE_NEXT; mainDialog->compareStatus->updateStatusPanelNow(); @@ -2621,11 +2445,11 @@ int CompareStatusUpdater::reportError(const wxString& text) switch (rv) { - case ErrorDlg::continueButtonPressed: - return StatusUpdater::continueNext; - case ErrorDlg::retryButtonPressed: - return StatusUpdater::retry; - case ErrorDlg::abortButtonPressed: + case ErrorDlg::BUTTON_CONTINUE: + return ErrorHandler::CONTINUE_NEXT; + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + case ErrorDlg::BUTTON_ABORT: { abortionRequested = true; throw AbortThisProcess(); @@ -2634,7 +2458,7 @@ int CompareStatusUpdater::reportError(const wxString& text) assert (false); } - return StatusUpdater::continueNext; //dummy return value + return ErrorHandler::CONTINUE_NEXT; //dummy return value } @@ -2703,9 +2527,9 @@ void SyncStatusUpdater::updateStatusText(const wxString& text) } -void SyncStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID) +void SyncStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, Process processID) { - assert (processID == FreeFileSync::synchronizeFilesProcess); + assert (processID == StatusHandler::PROCESS_SYNCHRONIZING); syncStatusFrame->resetGauge(objectsTotal, dataTotal); syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); @@ -2719,12 +2543,12 @@ void SyncStatusUpdater::updateProcessedData(int objectsProcessed, double dataPro } -int SyncStatusUpdater::reportError(const wxString& text) +ErrorHandler::Response SyncStatusUpdater::reportError(const wxString& text) { if (continueError) { unhandledErrors.Add(text); - return StatusUpdater::continueNext; + return ErrorHandler::CONTINUE_NEXT; } wxString errorMessage = text + _("\n\nContinue with next object, retry or abort synchronization?"); @@ -2736,12 +2560,12 @@ int SyncStatusUpdater::reportError(const wxString& text) switch (rv) { - case ErrorDlg::continueButtonPressed: + case ErrorDlg::BUTTON_CONTINUE: unhandledErrors.Add(text); - return StatusUpdater::continueNext; - case ErrorDlg::retryButtonPressed: - return StatusUpdater::retry; - case ErrorDlg::abortButtonPressed: + return ErrorHandler::CONTINUE_NEXT; + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + case ErrorDlg::BUTTON_ABORT: { unhandledErrors.Add(text); abortionRequested = true; @@ -2749,7 +2573,7 @@ int SyncStatusUpdater::reportError(const wxString& text) } default: assert (false); - return StatusUpdater::continueNext; + return ErrorHandler::CONTINUE_NEXT; } } @@ -2824,7 +2648,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } else { - wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + fileName + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR); } } @@ -2832,6 +2656,15 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } +void MainDialog::OnMenuAdjustFileTimes(wxCommandEvent& event) +{ + ModifyFilesDlg* modifyDlg = new ModifyFilesDlg(this, FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()), 0); + modifyDlg->ShowModal(); + + event.Skip(); +} + + void MainDialog::OnMenuBatchJob(wxCommandEvent& event) { vector<FolderPair> folderPairs; @@ -2862,7 +2695,7 @@ void MainDialog::OnMenuQuit(wxCommandEvent& event) void MainDialog::OnMenuLangEnglish(wxCommandEvent& event) { - programLanguage->loadLanguageFile(wxLANGUAGE_ENGLISH); //language is a global attribute + programLanguage->setLanguage(wxLANGUAGE_ENGLISH); //language is a global attribute restartOnExit = true; Destroy(); event.Skip(); @@ -2871,7 +2704,7 @@ void MainDialog::OnMenuLangEnglish(wxCommandEvent& event) void MainDialog::OnMenuLangGerman(wxCommandEvent& event) { - programLanguage->loadLanguageFile(wxLANGUAGE_GERMAN); //language is a global attribute + programLanguage->setLanguage(wxLANGUAGE_GERMAN); //language is a global attribute restartOnExit = true; Destroy(); event.Skip(); @@ -2880,7 +2713,7 @@ void MainDialog::OnMenuLangGerman(wxCommandEvent& event) void MainDialog::OnMenuLangFrench(wxCommandEvent& event) { - programLanguage->loadLanguageFile(wxLANGUAGE_FRENCH); //language is a global attribute + programLanguage->setLanguage(wxLANGUAGE_FRENCH); //language is a global attribute restartOnExit = true; Destroy(); event.Skip(); @@ -2889,7 +2722,16 @@ void MainDialog::OnMenuLangFrench(wxCommandEvent& event) void MainDialog::OnMenuLangJapanese(wxCommandEvent& event) { - programLanguage->loadLanguageFile(wxLANGUAGE_JAPANESE); //language is a global attribute + programLanguage->setLanguage(wxLANGUAGE_JAPANESE); //language is a global attribute + restartOnExit = true; + Destroy(); + event.Skip(); +} + + +void MainDialog::OnMenuLangDutch(wxCommandEvent& event) +{ + programLanguage->setLanguage(wxLANGUAGE_DUTCH); //language is a global attribute restartOnExit = true; Destroy(); event.Skip(); |