diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/MainDialog.cpp | 1720 | ||||
-rw-r--r-- | ui/MainDialog.h | 200 | ||||
-rw-r--r-- | ui/SmallDialogs.cpp | 544 | ||||
-rw-r--r-- | ui/SmallDialogs.h | 160 | ||||
-rw-r--r-- | ui/SyncDialog.cpp | 163 | ||||
-rw-r--r-- | ui/SyncDialog.h | 44 | ||||
-rw-r--r-- | ui/batchStatusHandler.cpp | 596 | ||||
-rw-r--r-- | ui/batchStatusHandler.h | 83 | ||||
-rw-r--r-- | ui/checkVersion.cpp | 94 | ||||
-rw-r--r-- | ui/checkVersion.h | 4 | ||||
-rw-r--r-- | ui/dragAndDrop.cpp | 207 | ||||
-rw-r--r-- | ui/dragAndDrop.h | 63 | ||||
-rw-r--r-- | ui/gridView.cpp | 213 | ||||
-rw-r--r-- | ui/gridView.h | 108 | ||||
-rw-r--r-- | ui/guiGenerated.cpp | 925 | ||||
-rw-r--r-- | ui/guiGenerated.h | 180 | ||||
-rw-r--r-- | ui/guiStatusHandler.cpp | 402 | ||||
-rw-r--r-- | ui/guiStatusHandler.h | 60 | ||||
-rw-r--r-- | ui/sorting.h | 305 |
19 files changed, 4047 insertions, 2024 deletions
diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp index d25fe224..e8006600 100644 --- a/ui/MainDialog.cpp +++ b/ui/MainDialog.cpp @@ -1,29 +1,136 @@ -/*************************************************************** - * Purpose: Code for main dialog - * Author: ZenJu (zhnmju123@gmx.de) - * Created: 2008-07-16 - **************************************************************/ - #include "mainDialog.h" #include <wx/filename.h> #include "../library/globalFunctions.h" -#include <wx/wfstream.h> #include <wx/clipbrd.h> +#include <wx/dataobj.h> #include <wx/ffile.h> #include "../library/customGrid.h" #include "../library/customButton.h" #include <algorithm> -#include "../library/sorting.h" #include <wx/msgdlg.h> #include "../comparison.h" #include "../synchronization.h" #include "../algorithm.h" #include "checkVersion.h" +#include "guiStatusHandler.h" +#include "syncDialog.h" +#include "../library/localization.h" +#include "smallDialogs.h" +#include "dragAndDrop.h" +#include "../library/filter.h" +#include "../structures.h" + +using namespace FreeFileSync; + + +class FolderPairPanel : public FolderPairGenerated +{ +public: + FolderPairPanel(wxWindow* parent) : + FolderPairGenerated(parent), + dragDropOnLeft(new DragDropOnDlg(m_panelLeft, m_dirPickerLeft, m_directoryLeft)), + dragDropOnRight(new DragDropOnDlg(m_panelRight, m_dirPickerRight, m_directoryRight)) {} + +private: + //support for drag and drop + std::auto_ptr<DragDropOnDlg> dragDropOnLeft; + std::auto_ptr<DragDropOnDlg> dragDropOnRight; +}; + + +class MainFolderDragDrop : public DragDropOnMainDlg +{ +public: + MainFolderDragDrop(MainDialog* mainDlg, + wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName) : + + DragDropOnMainDlg(dropWindow1, dropWindow2, dirPicker, dirName), + mainDlg_(mainDlg) {} + + virtual bool AcceptDrop(const wxString& dropName) + { + const xmlAccess::XmlType fileType = xmlAccess::getXmlType(dropName); + + //test if ffs config file has been dropped + if (fileType == xmlAccess::XML_GUI_CONFIG) + { + if (mainDlg_->readConfigurationFromXml(dropName)) + mainDlg_->pushStatusInformation(_("Configuration loaded!")); + return false; + } + //...or a ffs batch file + else if (fileType == xmlAccess::XML_BATCH_CONFIG) + { + BatchDialog* batchDlg = new BatchDialog(mainDlg_, dropName); + if (batchDlg->ShowModal() == BatchDialog::BATCH_FILE_SAVED) + mainDlg_->pushStatusInformation(_("Batch file created successfully!")); + return false; + } + + //disable the sync button + mainDlg_->enableSynchronization(false); + + //clear grids + mainDlg_->currentGridData.clear(); + mainDlg_->updateGuiGrid(); + + return true; + } + +private: + MainDialog* mainDlg_; +}; + + +//workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) +class MenuItemUpdater +{ +public: + MenuItemUpdater(wxMenu* menuToUpdate) : menuToUpdate_(menuToUpdate) {} + + ~MenuItemUpdater() + { + //start updating menu icons + const wxMenuItemList& allItems = menuToUpdate_->GetMenuItems(); + + //retrieve menu item positions: unfortunately wxMenu doesn't offer a better way + MenuItemMap::iterator j; + int index = 0; + for (wxMenuItemList::const_iterator i = allItems.begin(); i != allItems.end(); ++i, ++index) + if ((j = menuItems.find(*i)) != menuItems.end()) + j->second = index; + + //finally update items + for (MenuItemMap::const_iterator i = menuItems.begin(); i != menuItems.end(); ++i) + if (i->second >= 0) + { + menuToUpdate_->Remove(i->first); //actual workaround + menuToUpdate_->Insert(i->second, i->first); // + } + } + + void addForUpdate(wxMenuItem* newEntry, const wxBitmap& newBitmap) + { + newEntry->SetBitmap(newBitmap); + menuItems.insert(std::pair<wxMenuItem*, int>(newEntry, -1)); + } + +private: + typedef std::map<wxMenuItem*, int> MenuItemMap; + wxMenu* menuToUpdate_; + MenuItemMap menuItems; +}; + +//################################################################################################################################## MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings) : MainDialogGenerated(frame), globalSettings(settings), + gridDataView(currentGridData), contextMenu(new wxMenu), //initialize right-click context menu; will be dynamically re-created on each R-mouse-click programLanguage(language), filteringInitialized(false), @@ -52,35 +159,48 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale bSizer6->Layout(); //wxButtonWithImage size might have changed - //menu icons - m_menuItem10->SetBitmap(*globalResource.bitmapCompareSmall); - m_menuItem11->SetBitmap(*globalResource.bitmapSyncSmall); - m_menuItem7->SetBitmap(*globalResource.bitmapBatchSmall); - m_menuItemGlobSett->SetBitmap(*globalResource.bitmapSettingsSmall); - m_menuItemAbout->SetBitmap(*globalResource.bitmapAboutSmall); - - //workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) - m_menu1->Remove(m_menuItem10); - m_menu1->Remove(m_menuItem11); - m_menu1->Insert(0, m_menuItem10); - m_menu1->Insert(1, m_menuItem11); - m_menu3->Remove(m_menuItemGlobSett); - m_menu3->Remove(m_menuItem7); - m_menu3->Insert(2, m_menuItemGlobSett); - m_menu3->Insert(3, m_menuItem7); - - m_menu33->Remove(m_menuItemAbout); - m_menu33->Insert(2, m_menuItemAbout); + //menu icons: workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) + MenuItemUpdater updateMenuFile(m_menuFile); + updateMenuFile.addForUpdate(m_menuItem10, *globalResource.bitmapCompareSmall); + updateMenuFile.addForUpdate(m_menuItem11, *globalResource.bitmapSyncSmall); + + MenuItemUpdater updateMenuAdv(m_menuAdvanced); + updateMenuAdv.addForUpdate(m_menuItemGlobSett, *globalResource.bitmapSettingsSmall); + updateMenuAdv.addForUpdate(m_menuItem7, *globalResource.bitmapBatchSmall); + + MenuItemUpdater updateMenuHelp(m_menuHelp); + updateMenuHelp.addForUpdate(m_menuItemAbout, *globalResource.bitmapAboutSmall); + + MenuItemUpdater updateMenuAdvLang(m_menuLanguages); + updateMenuAdvLang.addForUpdate(m_menuItemGerman, *globalResource.bitmapGermany); + updateMenuAdvLang.addForUpdate(m_menuItemEnglish, *globalResource.bitmapEngland); + updateMenuAdvLang.addForUpdate(m_menuItemSpanish, *globalResource.bitmapSpain); + updateMenuAdvLang.addForUpdate(m_menuItemFrench, *globalResource.bitmapFrance); + updateMenuAdvLang.addForUpdate(m_menuItemItalian, *globalResource.bitmapItaly); + updateMenuAdvLang.addForUpdate(m_menuItemHungarian, *globalResource.bitmapHungary); + updateMenuAdvLang.addForUpdate(m_menuItemDutch, *globalResource.bitmapHolland); + updateMenuAdvLang.addForUpdate(m_menuItemPolish, *globalResource.bitmapPoland); + updateMenuAdvLang.addForUpdate(m_menuItemPortuguese, *globalResource.bitmapPortugal); + updateMenuAdvLang.addForUpdate(m_menuItemPortugueseBrazil, *globalResource.bitmapBrazil); + updateMenuAdvLang.addForUpdate(m_menuItemSlovenian, *globalResource.bitmapSlovakia); + updateMenuAdvLang.addForUpdate(m_menuItemJapanese, *globalResource.bitmapJapan); + updateMenuAdvLang.addForUpdate(m_menuItemChineseSimple, *globalResource.bitmapChina); - //prepare drag & drop - m_panel1->SetDropTarget(new MainWindowDropTarget(this, m_panel1)); - m_panel2->SetDropTarget(new MainWindowDropTarget(this, m_panel2)); - m_panel11->SetDropTarget(new MainWindowDropTarget(this, m_panel1)); - m_panel12->SetDropTarget(new MainWindowDropTarget(this, m_panel2)); - - //redirect drag & drop event back to main window - Connect(FFS_DROP_FILE_EVENT, FfsFileDropEventHandler(MainDialog::OnFilesDropped), NULL, this); + //prepare drag & drop + dragDropOnLeft.reset(new MainFolderDragDrop( + this, + m_panelLeft, + m_panelTopLeft, + m_dirPickerLeft, + m_directoryLeft)); + + dragDropOnRight.reset(new MainFolderDragDrop( + this, + m_panelRight, + m_panelTopRight, + m_dirPickerRight, + m_directoryRight)); //support for CTRL + C and DEL m_gridLeft->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridLeftButtonEvent), NULL, this); @@ -95,58 +215,31 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale Connect(wxEVT_MOVE, wxEventHandler(MainDialog::onResizeMainWindow), NULL, this); //init grid settings - m_gridLeft->initSettings( true, globalSettings.gui.showFileIcons, m_gridLeft, m_gridRight, m_gridMiddle, &gridRefUI, ¤tGridData); - m_gridMiddle->initSettings(false, false, m_gridLeft, m_gridRight, m_gridMiddle, &gridRefUI, ¤tGridData); - m_gridRight->initSettings( true, globalSettings.gui.showFileIcons, m_gridLeft, m_gridRight, m_gridMiddle, &gridRefUI, ¤tGridData); + m_gridLeft->initSettings( globalSettings.gui.showFileIcons, + m_gridLeft, + m_gridRight, + m_gridMiddle, + &gridDataView); + + m_gridMiddle->initSettings(m_gridLeft, + m_gridRight, + m_gridMiddle, + &gridDataView); + + m_gridRight->initSettings( globalSettings.gui.showFileIcons, + m_gridLeft, + m_gridRight, + m_gridMiddle, + &gridDataView); //disable sync button as long as "compare" hasn't been triggered. enableSynchronization(false); //mainly to update row label sizes... - writeGrid(currentGridData); + updateGuiGrid(); enableSynchronization(false); - //initialize language selection - switch (programLanguage->getLanguage()) - { - case wxLANGUAGE_CHINESE_SIMPLIFIED: - m_menuItemChineseSimple->Check(); - break; - case wxLANGUAGE_DUTCH: - m_menuItemDutch->Check(); - break; - case wxLANGUAGE_FRENCH: - m_menuItemFrench->Check(); - break; - case wxLANGUAGE_GERMAN: - m_menuItemGerman->Check(); - break; - case wxLANGUAGE_HUNGARIAN: - m_menuItemHungarian->Check(); - break; - case wxLANGUAGE_ITALIAN: - m_menuItemItalian->Check(); - break; - case wxLANGUAGE_JAPANESE: - m_menuItemJapanese->Check(); - break; - case wxLANGUAGE_POLISH: - m_menuItemPolish->Check(); - break; - case wxLANGUAGE_PORTUGUESE: - m_menuItemPortuguese->Check(); - break; - case wxLANGUAGE_SLOVENIAN: - m_menuItemSlovenian->Check(); - break; - case wxLANGUAGE_SPANISH: - m_menuItemSpanish->Check(); - break; - default: - m_menuItemEnglish->Check(); - } - //create the compare status panel in hidden state compareStatus = new CompareStatus(this); bSizer1->Insert(1, compareStatus, 0, wxEXPAND | wxBOTTOM, 5 ); @@ -154,11 +247,14 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale compareStatus->Hide(); //correct width of swap button above middle grid - wxSize source = m_gridMiddle->GetSize(); - wxSize target = bSizerMiddle->GetSize(); - int spaceToAdd = source.GetX() - target.GetX(); + const wxSize source = m_gridMiddle->GetSize(); + const wxSize target = bSizerMiddle->GetSize(); + const int spaceToAdd = source.GetX() - target.GetX(); bSizerMiddle->Insert(1, spaceToAdd / 2, 0, 0); bSizerMiddle->Insert(0, spaceToAdd - (spaceToAdd / 2), 0, 0); + + //register regular check for update on next idle event + Connect(wxEVT_IDLE, wxIdleEventHandler(MainDialog::OnRegularUpdateCheck), NULL, this); } @@ -177,7 +273,7 @@ void MainDialog::cleanUp() //no need for event Disconnect() here; done automatically //save configuration - writeConfigurationToXml(FreeFileSync::LAST_CONFIG_FILE); //don't trow exceptions in destructors + writeConfigurationToXml(xmlAccess::LAST_CONFIG_FILE); //don't trow exceptions in destructors writeGlobalSettings(); } } @@ -240,12 +336,12 @@ void MainDialog::writeGlobalSettings() //write list of last used folders globalSettings.gui.folderHistoryLeft.clear(); - const wxArrayString leftFolderHistory = m_comboBoxDirLeft->GetStrings(); + const wxArrayString leftFolderHistory = m_directoryLeft->GetStrings(); for (unsigned i = 0; i < leftFolderHistory.GetCount(); ++i) globalSettings.gui.folderHistoryLeft.push_back(leftFolderHistory[i]); globalSettings.gui.folderHistoryRight.clear(); - const wxArrayString rightFolderHistory = m_comboBoxDirRight->GetStrings(); + const wxArrayString rightFolderHistory = m_directoryRight->GetStrings(); for (unsigned i = 0; i < rightFolderHistory.GetCount(); ++i) globalSettings.gui.folderHistoryRight.push_back(rightFolderHistory[i]); } @@ -272,59 +368,65 @@ void MainDialog::filterRangeManually(const std::set<int>& rowsToFilterOnUiTable) { if (rowsToFilterOnUiTable.size() > 0) { - int gridSizeUI = gridRefUI.size(); - bool newSelection = false; //default: deselect range //leadingRow determines de-/selection of all other rows - int leadingRow = *rowsToFilterOnUiTable.begin(); - if (0 <= leadingRow && leadingRow < gridSizeUI) - 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 + const int leadingRow = *rowsToFilterOnUiTable.begin(); + if (0 <= leadingRow && leadingRow < int(gridDataView.elementsOnView())) + newSelection = !gridDataView[leadingRow].selectedForSynchronization; + //if hidefiltered is active, there should be no filtered elements on screen => current element was filtered out + assert(!hideFilteredElements || !newSelection); //get all lines that need to be filtered (e.g. if a folder is marked, then its subelements should be marked as well) - std::set<int> rowsToFilterOnGridData; //rows to filter in backend + FolderCompRef compRef; + gridDataView.viewRefToFolderRef(rowsToFilterOnUiTable, compRef); + + assert(compRef.size() == currentGridData.size()); //GridView::viewRefToFolderRef() should ensure this! - for (std::set<int>::iterator i = rowsToFilterOnUiTable.begin(); i != rowsToFilterOnUiTable.end(); ++i) + for (FolderComparison::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) { - if (0 <= *i && *i < gridSizeUI) + FileComparison& fileCmp = i->fileCmp; + const std::set<int>& markedRows = compRef[i - currentGridData.begin()]; + + std::set<int> markedRowsTotal; //retrieve additional rows that need to be filtered, too + for (std::set<int>::iterator i = markedRows.begin(); i != markedRows.end(); ++i) { - unsigned int gridIndex = gridRefUI[*i]; - rowsToFilterOnGridData.insert(gridIndex); - FreeFileSync::addSubElements(currentGridData, currentGridData[gridIndex], rowsToFilterOnGridData); + markedRowsTotal.insert(*i); + FreeFileSync::addSubElements(fileCmp, fileCmp[*i], markedRowsTotal); } - } - //toggle selection of filtered rows - for (std::set<int>::iterator i = rowsToFilterOnGridData.begin(); i != rowsToFilterOnGridData.end(); ++i) - currentGridData[*i].selectedForSynchronization = newSelection; + //toggle selection of filtered rows + for (std::set<int>::iterator i = markedRowsTotal.begin(); i != markedRowsTotal.end(); ++i) + fileCmp[*i].selectedForSynchronization = newSelection; + } //signal UI that grids need to be refreshed on next Update() m_gridLeft->ForceRefresh(); - m_gridRight->ForceRefresh(); m_gridMiddle->ForceRefresh(); + m_gridRight->ForceRefresh(); Update(); //show changes resulting from ForceRefresh() if (hideFilteredElements) { 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) + updateGuiGrid(); //redraw grid to remove excluded elements (keeping sort sequence) + + m_gridLeft->ClearSelection(); + m_gridRight->ClearSelection(); + m_gridMiddle->ClearSelection(); } - } + else + { //this second call to ForceRefresh() looks strange, but it actually fixes occasional graphical artifacts on bottom right of the grid + m_gridLeft->ForceRefresh(); + m_gridMiddle->ForceRefresh(); + m_gridRight->ForceRefresh(); - //clear selection on grids - if (hideFilteredElements) - { - m_gridLeft->ClearSelection(); - m_gridRight->ClearSelection(); - } //exception for grid 3 - m_gridMiddle->ClearSelection(); + m_gridMiddle->ClearSelection(); + } + } } - /*grid event choreography: 1. UI-Mouse-Down => OnGridSelectCell 2. UI-Mouse-Up => SelectRangeEvent (if at least two rows are marked) @@ -391,7 +493,7 @@ void MainDialog::OnIdleEvent(wxEvent& event) } -void MainDialog::copySelectionToClipboard(const wxGrid* selectedGrid) +void MainDialog::copySelectionToClipboard(const CustomGrid* selectedGrid) { const std::set<int> selectedRows = getSelectedRows(selectedGrid); if (selectedRows.size() > 0) @@ -400,10 +502,10 @@ void MainDialog::copySelectionToClipboard(const wxGrid* selectedGrid) for (std::set<int>::iterator i = selectedRows.begin(); i != selectedRows.end(); ++i) { - for (int k = 0; k < const_cast<wxGrid*>(selectedGrid)->GetNumberCols(); ++k) + for (int k = 0; k < const_cast<CustomGrid*>(selectedGrid)->GetNumberCols(); ++k) { - clipboardString+= const_cast<wxGrid*>(selectedGrid)->GetCellValue(*i, k); - if (k != const_cast<wxGrid*>(selectedGrid)->GetNumberCols() - 1) + clipboardString+= const_cast<CustomGrid*>(selectedGrid)->GetCellValue(*i, k); + if (k != const_cast<CustomGrid*>(selectedGrid)->GetNumberCols() - 1) clipboardString+= '\t'; } clipboardString+= '\n'; @@ -436,7 +538,7 @@ void removeInvalidRows(std::set<int>& rows, const int currentUiTableSize) } -std::set<int> MainDialog::getSelectedRows(const wxGrid* grid) +std::set<int> MainDialog::getSelectedRows(const CustomGrid* grid) { std::set<int> output; int rowTop, rowBottom; //coords of selection @@ -450,7 +552,7 @@ std::set<int> MainDialog::getSelectedRows(const wxGrid* grid) if (!grid->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion { - for (int k = 0; k < const_cast<wxGrid*>(grid)->GetNumberRows(); ++k) //messy wxGrid implementation... + for (int k = 0; k < const_cast<CustomGrid*>(grid)->GetNumberRows(); ++k) //messy wxGrid implementation... output.insert(k); } @@ -482,10 +584,10 @@ std::set<int> MainDialog::getSelectedRows(const wxGrid* grid) } //some exception: also add current cursor row to selection if there are no others... hopefully improving usability - if (output.empty() && grid == m_gridLeft->getLeadGrid()) - output.insert(const_cast<wxGrid*>(grid)->GetCursorRow()); //messy wxGrid implementation... + if (output.empty() && grid->isLeadGrid()) + output.insert(const_cast<CustomGrid*>(grid)->GetCursorRow()); //messy wxGrid implementation... - removeInvalidRows(output, gridRefUI.size()); + removeInvalidRows(output, gridDataView.elementsOnView()); return output; } @@ -518,7 +620,7 @@ public: case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: - throw AbortThisProcess(); + throw FreeFileSync::AbortThisProcess(); default: assert (false); return ErrorHandler::IGNORE_ERROR; //dummy return value @@ -530,23 +632,26 @@ private: }; -void MainDialog::deleteFilesOnGrid(const std::set<int>& selectedRowsLeft, const std::set<int>& selectedRowsRight) +void MainDialog::deleteSelectedFiles() { - if (selectedRowsLeft.size() + selectedRowsRight.size()) + //get set of selected rows on view + const std::set<int> viewSelectionLeft = getSelectedRows(m_gridLeft); + const std::set<int> viewSelectionRight = getSelectedRows(m_gridRight); + + if (viewSelectionLeft.size() + viewSelectionRight.size()) { - //map grid lines from UI to grid lines in backend (gridData) - std::set<int> rowsOnGridLeft; - for (std::set<int>::iterator i = selectedRowsLeft.begin(); i != selectedRowsLeft.end(); ++i) - rowsOnGridLeft.insert(gridRefUI[*i]); + //map lines from GUI view to grid line references for "currentGridData" + FolderCompRef compRefLeft; + gridDataView.viewRefToFolderRef(viewSelectionLeft, compRefLeft); + + FolderCompRef compRefRight; + gridDataView.viewRefToFolderRef(viewSelectionRight, compRefRight); - std::set<int> rowsOnGridRight; - for (std::set<int>::iterator i = selectedRowsRight.begin(); i != selectedRowsRight.end(); ++i) - rowsOnGridRight.insert(gridRefUI[*i]); DeleteDialog* confirmDeletion = new DeleteDialog(this, //no destruction needed; attached to main window currentGridData, - rowsOnGridLeft, - rowsOnGridRight, + compRefLeft, + compRefRight, globalSettings.gui.deleteOnBothSides, globalSettings.gui.useRecyclerForManualDeletion); if (confirmDeletion->ShowModal() == DeleteDialog::BUTTON_OKAY) @@ -557,25 +662,37 @@ void MainDialog::deleteFilesOnGrid(const std::set<int>& selectedRowsLeft, const return; } - //Attention! Modifying the grid is highly critical! There MUST NOT BE any accesses to gridRefUI until this reference table is updated - //by writeGrid()!! This is easily missed, e.g. when ClearSelection() or ShowModal() or possibly any other wxWidgets function is called - //that might want to redraw the UI (which implicitly uses the information in gridRefUI and currentGridData (see CustomGrid) + //Attention! Modifying the grid is highly critical! There MUST NOT BE any accesses to gridDataView until this reference table is updated + //by updateGuiGrid()!! This is easily missed, e.g. when ClearSelection() or ShowModal() or possibly any other wxWidgets function is called + //that might want to redraw the UI (which implicitly uses the information in gridDataView (see CustomGrid) try { //handle errors when deleting files/folders DeleteErrorHandler errorHandler; - FreeFileSync::deleteFromGridAndHD(currentGridData, - rowsOnGridLeft, - rowsOnGridRight, - globalSettings.gui.deleteOnBothSides, - globalSettings.gui.useRecyclerForManualDeletion, - &errorHandler); + assert(compRefLeft.size() == currentGridData.size()); //GridView::viewRefToFolderRef() should ensure this! + assert(compRefRight.size() == currentGridData.size()); + + for (FolderComparison::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) + { + const int folderPairNr = i - currentGridData.begin(); + + const std::set<int>& rowsToDeleteOnLeft = compRefLeft[folderPairNr]; + const std::set<int>& rowsToDeleteOnRight = compRefRight[folderPairNr]; + + FreeFileSync::deleteFromGridAndHD(i->fileCmp, + rowsToDeleteOnLeft, + rowsToDeleteOnRight, + globalSettings.gui.deleteOnBothSides, + globalSettings.gui.useRecyclerForManualDeletion, + &errorHandler); + } + } - catch (AbortThisProcess&) {} + catch (FreeFileSync::AbortThisProcess&) {} //redraw grid neccessary to update new dimensions and for UI-Backend data linkage - writeGrid(currentGridData); //call immediately after deleteFromGridAndHD!!! + updateGuiGrid(); //call immediately after deleteFromGridAndHD!!! m_gridLeft->ClearSelection(); m_gridMiddle->ClearSelection(); @@ -585,34 +702,34 @@ void MainDialog::deleteFilesOnGrid(const std::set<int>& selectedRowsLeft, const } -void MainDialog::openWithFileManager(int rowNumber, const wxGrid* grid) +void MainDialog::openWithFileManager(const int rowNumber, const bool leftSide) { wxString command; - const FileDescrLine* fileDescr = NULL; - if (grid == m_gridLeft) - { - if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) - fileDescr = ¤tGridData[gridRefUI[rowNumber]].fileDescrLeft; -#ifdef FFS_WIN - command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_comboBoxDirLeft->GetValue().c_str()).c_str(); //default -#endif // FFS_WIN - } - else if (grid == m_gridRight) - { - if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) - fileDescr = ¤tGridData[gridRefUI[rowNumber]].fileDescrRight; -#ifdef FFS_WIN - command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_comboBoxDirRight->GetValue().c_str()).c_str(); //default -#endif // FFS_WIN - } + + wxString defaultFolder; + if (0 <= rowNumber && rowNumber < int(gridDataView.elementsOnView())) + defaultFolder = leftSide ? + gridDataView.getFolderPair(rowNumber).leftDirectory.c_str() : + gridDataView.getFolderPair(rowNumber).rightDirectory.c_str(); else - { - assert(false); - return; - } + defaultFolder = leftSide ? + FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue().c_str()).c_str() : + FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue().c_str()).c_str(); - if (fileDescr) +#ifdef FFS_WIN + command = wxString(wxT("explorer ")) + defaultFolder; //default +#elif defined FFS_LINUX + command = globalSettings.gui.commandLineFileManager; + command.Replace(wxT("%name"), defaultFolder); + command.Replace(wxT("%path"), defaultFolder); +#endif + + if (0 <= rowNumber && rowNumber < int(gridDataView.elementsOnView())) { + const FileDescrLine* fileDescr = leftSide ? + &gridDataView[rowNumber].fileDescrLeft : + &gridDataView[rowNumber].fileDescrRight; + if (fileDescr->objType == FileDescrLine::TYPE_FILE) { command = globalSettings.gui.commandLineFileManager; @@ -625,6 +742,9 @@ void MainDialog::openWithFileManager(int rowNumber, const wxGrid* grid) command.Replace(wxT("%name"), fileDescr->fullName.c_str()); command.Replace(wxT("%path"), fileDescr->fullName.c_str()); } + else if (fileDescr->objType == FileDescrLine::TYPE_NOTHING) + { + } } if (!command.empty()) @@ -689,7 +809,7 @@ void MainDialog::onGridLeftButtonEvent(wxKeyEvent& event) m_gridLeft->SelectAll(); } else if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) - deleteFilesOnGrid(getSelectedRows(m_gridLeft), getSelectedRows(m_gridRight)); + deleteSelectedFiles(); event.Skip(); } @@ -721,7 +841,7 @@ void MainDialog::onGridRightButtonEvent(wxKeyEvent& event) m_gridRight->SelectAll(); } else if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) - deleteFilesOnGrid(getSelectedRows(m_gridLeft), getSelectedRows(m_gridRight)); + deleteSelectedFiles(); event.Skip(); } @@ -747,9 +867,7 @@ void MainDialog::OnContextMenu(wxGridEvent& event) else selectionBegin = std::min(*selectionLeft.begin(), *selectionRight.begin()); - const FileCompareLine& firstLine = currentGridData[gridRefUI[selectionBegin]]; - - if (firstLine.selectedForSynchronization) + if (gridDataView[selectionBegin].selectedForSynchronization) //valid access, as getSelectedRows returns valid references only contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily")); else contextMenu->Append(CONTEXT_FILTER_TEMP, _("Include temporarily")); @@ -766,7 +884,7 @@ void MainDialog::OnContextMenu(wxGridEvent& event) FilterObject newFilterEntry; for (std::set<int>::iterator i = selectionLeft.begin(); i != selectionLeft.end(); ++i) { - const FileCompareLine& line = currentGridData[gridRefUI[*i]]; + const FileCompareLine& line = gridDataView[*i]; newFilterEntry.relativeName = line.fileDescrLeft.relativeName.c_str(); newFilterEntry.type = line.fileDescrLeft.objType; if (!newFilterEntry.relativeName.IsEmpty()) @@ -774,7 +892,7 @@ void MainDialog::OnContextMenu(wxGridEvent& event) } for (std::set<int>::iterator i = selectionRight.begin(); i != selectionRight.end(); ++i) { - const FileCompareLine& line = currentGridData[gridRefUI[*i]]; + const FileCompareLine& line = gridDataView[*i]; newFilterEntry.relativeName = line.fileDescrRight.relativeName.c_str(); newFilterEntry.type = line.fileDescrRight.objType; if (!newFilterEntry.relativeName.IsEmpty()) @@ -871,7 +989,7 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); - writeGrid(currentGridData); + updateGuiGrid(); if (hideFilteredElements) { m_gridLeft->ClearSelection(); @@ -891,14 +1009,10 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) cfg.excludeFilter+= wxT("\n"); if (i->type == FileDescrLine::TYPE_FILE) - { cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::FILE_NAME_SEPARATOR + i->relativeName; - } else if (i->type == FileDescrLine::TYPE_DIRECTORY) - { - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::FILE_NAME_SEPARATOR + i->relativeName + wxT("\n"); cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::FILE_NAME_SEPARATOR + i->relativeName + GlobalResources::FILE_NAME_SEPARATOR + wxT("*"); - } + else assert(false); } @@ -907,7 +1021,7 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); - writeGrid(currentGridData); + updateGuiGrid(); if (hideFilteredElements) { m_gridLeft->ClearSelection(); @@ -929,20 +1043,24 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) { if (m_gridLeft->isLeadGrid() || m_gridRight->isLeadGrid()) { - const wxGrid* const leadGrid = m_gridLeft->getLeadGrid(); + const CustomGrid* leadGrid = NULL; + if (m_gridLeft->isLeadGrid()) + leadGrid = m_gridLeft; + else + leadGrid = m_gridRight; std::set<int> selection = getSelectedRows(leadGrid); if (selection.size() == 1) - openWithFileManager(*selection.begin(), leadGrid); + openWithFileManager(*selection.begin(), m_gridLeft->isLeadGrid()); else if (selection.size() == 0) - openWithFileManager(-1, leadGrid); + openWithFileManager(-1, m_gridLeft->isLeadGrid()); } } else if (eventId == CONTEXT_DELETE_FILES) { - deleteFilesOnGrid(getSelectedRows(m_gridLeft), getSelectedRows(m_gridRight)); + deleteSelectedFiles(); } } @@ -953,7 +1071,7 @@ void MainDialog::OnContextMenuMiddle(wxGridEvent& event) contextMenu->Append(CONTEXT_CHECK_ALL, _("Check all")); contextMenu->Append(CONTEXT_UNCHECK_ALL, _("Uncheck all")); - if (currentGridData.size() == 0) + if (gridDataView.elementsTotal() == 0) { contextMenu->Enable(CONTEXT_CHECK_ALL, false); contextMenu->Enable(CONTEXT_UNCHECK_ALL, false); @@ -972,12 +1090,12 @@ void MainDialog::OnContextMenuMiddleSelection(wxCommandEvent& event) if (eventId == CONTEXT_CHECK_ALL) { FreeFileSync::includeAllRowsOnGrid(currentGridData); - writeGrid(currentGridData); + updateGuiGrid(); } else if (eventId == CONTEXT_UNCHECK_ALL) { FreeFileSync::excludeAllRowsOnGrid(currentGridData); - writeGrid(currentGridData); + updateGuiGrid(); } } @@ -1035,81 +1153,16 @@ void MainDialog::OnContextColumnSelection(wxCommandEvent& event) } -void MainDialog::OnWriteDirManually(wxCommandEvent& event) -{ - wxString newDir = FreeFileSync::getFormattedDirectoryName(event.GetString().c_str()).c_str(); - if (wxDirExists(newDir)) - { - wxObject* eventObj = event.GetEventObject(); - - //first check if event comes from main folder pair - if (eventObj == (wxObject*)m_comboBoxDirLeft) - m_dirPickerLeft->SetPath(newDir); - else if (eventObj == (wxObject*)m_comboBoxDirRight) - m_dirPickerRight->SetPath(newDir); - else - { - //check if event comes from additional pairs - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) - { - FolderPairGenerated* dirPair = *i; - if (eventObj == (wxObject*)(dirPair->m_directoryLeft)) - { - dirPair->m_dirPickerLeft->SetPath(newDir); - break; - } - else if (eventObj == (wxObject*)(dirPair->m_directoryRight)) - { - dirPair->m_dirPickerRight->SetPath(newDir); - break; - } - } - } - } - event.Skip(); -} - - void MainDialog::OnDirSelected(wxFileDirPickerEvent& event) { - const wxString newPath = event.GetPath(); - wxObject* eventObj = event.GetEventObject(); - - //first check if event comes from main folder pair - if (eventObj == (wxObject*)m_dirPickerLeft) - { - m_comboBoxDirLeft->SetSelection(wxNOT_FOUND); - m_comboBoxDirLeft->SetValue(newPath); - } - else if (eventObj == (wxObject*)m_dirPickerRight) - { - m_comboBoxDirRight->SetSelection(wxNOT_FOUND); - m_comboBoxDirRight->SetValue(newPath); - } - else //check if event comes from additional pairs - { - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) - { - FolderPairGenerated* dirPair = *i; - if (eventObj == (wxObject*)(dirPair->m_dirPickerLeft)) - { - dirPair->m_directoryLeft->SetValue(newPath); - break; - } - else if (eventObj == (wxObject*)(dirPair->m_dirPickerRight)) - { - dirPair->m_directoryRight->SetValue(newPath); - break; - } - } - } + //left and right directory text-control and dirpicker are synchronized by MainFolderDragDrop automatically //disable the sync button enableSynchronization(false); //clear grids currentGridData.clear(); - writeGrid(currentGridData); + updateGuiGrid(); event.Skip(); } @@ -1176,7 +1229,7 @@ void MainDialog::addFileToCfgHistory(const wxString& filename) cfgFileNames.insert(cfgFileNames.begin(), filename); //the default config file should receive another name on GUI - if (sameFileSpecified(FreeFileSync::LAST_CONFIG_FILE, filename)) + if (sameFileSpecified(xmlAccess::LAST_CONFIG_FILE, filename)) m_choiceHistory->Insert(_("<Last session>"), 0); //insert at beginning of list else m_choiceHistory->Insert(getFormattedHistoryElement(filename), 0); //insert at beginning of list @@ -1185,107 +1238,11 @@ void MainDialog::addFileToCfgHistory(const wxString& filename) } //keep maximal size of history list - if (cfgFileNames.size() > globalSettings.gui.cfgHistoryMaxItems) + if (cfgFileNames.size() > globalSettings.gui.cfgHistoryMax) { //delete last rows cfgFileNames.pop_back(); - m_choiceHistory->Delete(globalSettings.gui.cfgHistoryMaxItems); - } -} - - -bool MainWindowDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) -{ - if (!filenames.IsEmpty()) - { - const wxString droppedFileName = filenames[0]; - - //create a custom event on main window: execute event after file dropping is completed! (e.g. after mouse is released) - FfsFileDropEvent evt(droppedFileName, dropTarget); - mainDlg->GetEventHandler()->AddPendingEvent(evt); - } - return false; -} - - -template <class Ctrl> -void setDirectoryFromDrop(const wxString& elementName, Ctrl* txtCtrl, wxDirPickerCtrl* dirPicker) -{ - wxString fileName = elementName; - - if (wxDirExists(fileName)) - { - txtCtrl->SetValue(fileName); - dirPicker->SetPath(fileName); - } - else - { - fileName = wxFileName(fileName).GetPath(); - if (wxDirExists(fileName)) - { - txtCtrl->SetValue(fileName); - dirPicker->SetPath(fileName); - } - } -} - - -void MainDialog::OnFilesDropped(FfsFileDropEvent& event) -{ - const wxString droppedFileName = event.m_nameDropped; - const wxPanel* dropTarget = event.m_dropTarget; - - //disable the sync button - enableSynchronization(false); - - //clear grids - currentGridData.clear(); - writeGrid(currentGridData); - - xmlAccess::XmlType fileType = xmlAccess::getXmlType(droppedFileName); - - //test if ffs config file has been dropped - if (fileType == xmlAccess::XML_GUI_CONFIG) - { - if (readConfigurationFromXml(droppedFileName)) - pushStatusInformation(_("Configuration loaded!")); - } - //...or a ffs batch file - else if (fileType == xmlAccess::XML_BATCH_CONFIG) - { - BatchDialog* batchDlg = new BatchDialog(this, droppedFileName); - if (batchDlg->ShowModal() == BatchDialog::BATCH_FILE_SAVED) - pushStatusInformation(_("Batch file created successfully!")); - } - //test if main folder pair is drop target - else if (dropTarget == m_panel1) - { - m_comboBoxDirLeft->SetSelection(wxNOT_FOUND); - setDirectoryFromDrop<wxComboBox>(droppedFileName, m_comboBoxDirLeft, m_dirPickerLeft); - } - - else if (dropTarget == m_panel2) - { - m_comboBoxDirRight->SetSelection(wxNOT_FOUND); - setDirectoryFromDrop<wxComboBox>(droppedFileName, m_comboBoxDirRight, m_dirPickerRight); - } - - else //test if additional folder pairs are drop targets - { - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) - { - FolderPairGenerated* dirPair = *i; - if (dropTarget == (dirPair->m_panelLeft)) - { - setDirectoryFromDrop<wxTextCtrl>(droppedFileName, dirPair->m_directoryLeft, dirPair->m_dirPickerLeft); - break; - } - else if (dropTarget == (dirPair->m_panelRight)) - { - setDirectoryFromDrop<wxTextCtrl>(droppedFileName, dirPair->m_directoryRight, dirPair->m_dirPickerRight); - break; - } - } + m_choiceHistory->Delete(globalSettings.gui.cfgHistoryMax); } } @@ -1304,7 +1261,7 @@ int findTextPos(const wxArrayString& array, const wxString& text) } -void addPairToFolderHistory(wxComboBox* comboBox, const wxString& newFolder) +void addPairToFolderHistory(wxComboBox* comboBox, const wxString& newFolder, unsigned int maxHistSize) { const wxString oldVal = comboBox->GetValue(); @@ -1315,9 +1272,8 @@ void addPairToFolderHistory(wxComboBox* comboBox, const wxString& newFolder) comboBox->Insert(newFolder, 0); //keep maximal size of history list - const unsigned MAX_FOLDER_HIST_COUNT = 12; - if (comboBox->GetCount() > MAX_FOLDER_HIST_COUNT) - comboBox->Delete(MAX_FOLDER_HIST_COUNT); + if (comboBox->GetCount() > maxHistSize) + comboBox->Delete(maxHistSize); comboBox->SetSelection(wxNOT_FOUND); //don't select anything comboBox->SetValue(oldVal); //but preserve main text! @@ -1326,27 +1282,24 @@ void addPairToFolderHistory(wxComboBox* comboBox, const wxString& newFolder) void MainDialog::addLeftFolderToHistory(const wxString& leftFolder) { - addPairToFolderHistory(m_comboBoxDirLeft, leftFolder); + addPairToFolderHistory(m_directoryLeft, leftFolder, globalSettings.gui.folderHistLeftMax); } void MainDialog::addRightFolderToHistory(const wxString& rightFolder) { - addPairToFolderHistory(m_comboBoxDirRight, rightFolder); + addPairToFolderHistory(m_directoryRight, rightFolder, globalSettings.gui.folderHistRightMax); } void MainDialog::OnSaveConfig(wxCommandEvent& event) { - wxString defaultFileName = wxT("SyncSettings.ffs_gui"); - - if (!proposedConfigFileName.empty()) - defaultFileName = proposedConfigFileName; + const wxString defaultFileName = proposedConfigFileName.empty() ? wxT("SyncSettings.ffs_gui") : proposedConfigFileName; wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("FreeFileSync configuration")) + wxT(" (*.ffs_gui)|*.ffs_gui"), wxFD_SAVE); if (filePicker->ShowModal() == wxID_OK) { - wxString newFileName = filePicker->GetPath(); + const wxString newFileName = filePicker->GetPath(); if (FreeFileSync::fileExists(newFileName.c_str())) { @@ -1354,7 +1307,7 @@ void MainDialog::OnSaveConfig(wxCommandEvent& event) if (messageDlg->ShowModal() != wxID_OK) { - pushStatusInformation(_("Save aborted!")); + OnSaveConfig(event); //retry return; } } @@ -1397,7 +1350,7 @@ void MainDialog::loadConfiguration(const wxString& filename) if (!filename.IsEmpty()) { //clear grids currentGridData.clear(); - writeGrid(currentGridData); + updateGuiGrid(); if (readConfigurationFromXml(filename)) pushStatusInformation(_("Configuration loaded!")); @@ -1477,12 +1430,33 @@ void MainDialog::OnCompareByContent(wxCommandEvent& event) void MainDialog::OnClose(wxCloseEvent &event) { - Destroy(); + requestShutdown(); } void MainDialog::OnQuit(wxCommandEvent &event) { + requestShutdown(); +} + + +void MainDialog::requestShutdown() +{ + /* + if (globalSettings.gui.popupOnConfigChange) + { + if (lastConfigurationSaved != getCurrentConfiguration()) + { + ... +wxID_OK + OnSaveConfig(wxCommandEvent& event) + + ; + wxMessageBox(wxT("ji")); + } + } + */ + Destroy(); } @@ -1508,7 +1482,7 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program { if (programStartup) { - if (filename == FreeFileSync::LAST_CONFIG_FILE && !wxFileExists(filename)) //do not show error in this case + if (filename == xmlAccess::LAST_CONFIG_FILE && !wxFileExists(filename)) //do not show error in this case ; else //program startup: show error message and load defaults wxMessageBox(error.show().c_str(), _("Error"), wxOK | wxICON_ERROR); @@ -1529,11 +1503,11 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program //read folder pairs: //clear existing pairs first - m_comboBoxDirLeft->SetSelection(wxNOT_FOUND); - m_comboBoxDirLeft->SetValue(wxEmptyString); + m_directoryLeft->SetSelection(wxNOT_FOUND); + m_directoryLeft->SetValue(wxEmptyString); m_dirPickerLeft->SetPath(wxEmptyString); - m_comboBoxDirRight->SetSelection(wxNOT_FOUND); - m_comboBoxDirRight->SetValue(wxEmptyString); + m_directoryRight->SetSelection(wxNOT_FOUND); + m_directoryRight->SetValue(wxEmptyString); m_dirPickerRight->SetPath(wxEmptyString); clearFolderPairs(); @@ -1543,13 +1517,13 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program //set main folder pair std::vector<FolderPair>::const_iterator main = guiCfg.directoryPairs.begin(); - m_comboBoxDirLeft->SetValue(main->leftDirectory.c_str()); + m_directoryLeft->SetValue(main->leftDirectory.c_str()); const wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(main->leftDirectory).c_str(); if (wxDirExists(leftDirFormatted)) m_dirPickerLeft->SetPath(leftDirFormatted); addLeftFolderToHistory(main->leftDirectory.c_str()); //another hack: wxCombobox::Insert() asynchronously sends message overwriting a later wxCombobox::SetValue()!!! :( - m_comboBoxDirRight->SetValue(main->rightDirectory.c_str()); + m_directoryRight->SetValue(main->rightDirectory.c_str()); const wxString rightDirFormatted = FreeFileSync::getFormattedDirectoryName(main->rightDirectory).c_str(); if (wxDirExists(rightDirFormatted)) m_dirPickerRight->SetPath(rightDirFormatted); @@ -1571,7 +1545,9 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program //########################################################### addFileToCfgHistory(filename); //put filename on list of last used config files - if (filename == FreeFileSync::LAST_CONFIG_FILE) //set title + lastConfigurationSaved = guiCfg; + + if (filename == xmlAccess::LAST_CONFIG_FILE) //set title { SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")); proposedConfigFileName.clear(); @@ -1588,16 +1564,7 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program bool MainDialog::writeConfigurationToXml(const wxString& filename) { - xmlAccess::XmlGuiConfig guiCfg; - - //load structure with basic settings "mainCfg" - guiCfg.mainCfg = cfg; - guiCfg.directoryPairs = getFolderPairs(); - - //load structure with gui settings - guiCfg.hideFilteredElements = hideFilteredElements; - - guiCfg.ignoreErrors = ignoreErrors; + const xmlAccess::XmlGuiConfig guiCfg = getCurrentConfiguration(); //write config to XML try @@ -1613,7 +1580,9 @@ bool MainDialog::writeConfigurationToXml(const wxString& filename) //put filename on list of last used config files addFileToCfgHistory(filename); - if (filename == FreeFileSync::LAST_CONFIG_FILE) //set title + lastConfigurationSaved = guiCfg; + + if (filename == xmlAccess::LAST_CONFIG_FILE) //set title { SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")); proposedConfigFileName.clear(); @@ -1628,6 +1597,23 @@ bool MainDialog::writeConfigurationToXml(const wxString& filename) } +xmlAccess::XmlGuiConfig MainDialog::getCurrentConfiguration() const +{ + xmlAccess::XmlGuiConfig guiCfg; + + //load structure with basic settings "mainCfg" + guiCfg.mainCfg = cfg; + guiCfg.directoryPairs = getFolderPairs(); + + //load structure with gui settings + guiCfg.hideFilteredElements = hideFilteredElements; + + guiCfg.ignoreErrors = ignoreErrors; + + return guiCfg; +} + + void MainDialog::OnShowHelpDialog(wxCommandEvent &event) { HelpDlg* helpDlg = new HelpDlg(this); @@ -1646,7 +1632,7 @@ void MainDialog::OnFilterButton(wxCommandEvent &event) else FreeFileSync::includeAllRowsOnGrid(currentGridData); - writeGrid(currentGridData); + updateGuiGrid(); } @@ -1659,7 +1645,7 @@ void MainDialog::OnHideFilteredButton(wxCommandEvent &event) m_gridLeft->ClearSelection(); m_gridRight->ClearSelection(); - writeGrid(currentGridData); + updateGuiGrid(); event.Skip(); } @@ -1689,7 +1675,7 @@ void MainDialog::OnConfigureFilter(wxHyperlinkEvent &event) updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - writeGrid(currentGridData); + updateGuiGrid(); } } //no event.Skip() here, to not start browser @@ -1700,42 +1686,42 @@ void MainDialog::OnLeftOnlyFiles(wxCommandEvent& event) { leftOnlyFilesActive = !leftOnlyFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; void MainDialog::OnLeftNewerFiles(wxCommandEvent& event) { leftNewerFilesActive = !leftNewerFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; void MainDialog::OnDifferentFiles(wxCommandEvent& event) { differentFilesActive = !differentFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; void MainDialog::OnRightNewerFiles(wxCommandEvent& event) { rightNewerFilesActive = !rightNewerFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; void MainDialog::OnRightOnlyFiles(wxCommandEvent& event) { rightOnlyFilesActive = !rightOnlyFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; void MainDialog::OnEqualFiles(wxCommandEvent& event) { equalFilesActive = !equalFilesActive; updateViewFilterButtons(); - writeGrid(currentGridData); + updateGuiGrid(); }; @@ -1843,29 +1829,22 @@ void MainDialog::updateCompareButtons() //clear grids currentGridData.clear(); - writeGrid(currentGridData); + updateGuiGrid(); } -std::vector<FolderPair> MainDialog::getFolderPairs() +std::vector<FolderPair> MainDialog::getFolderPairs() const { std::vector<FolderPair> output; //add main pair - FolderPair newPair; - newPair.leftDirectory = m_comboBoxDirLeft->GetValue().c_str(); - newPair.rightDirectory = m_comboBoxDirRight->GetValue().c_str(); - output.push_back(newPair); + output.push_back(FolderPair(m_directoryLeft->GetValue().c_str(), + m_directoryRight->GetValue().c_str())); //add additional pairs - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) - { - FolderPairGenerated* dirPair = *i; - newPair.leftDirectory = dirPair->m_directoryLeft->GetValue().c_str(); - newPair.rightDirectory = dirPair->m_directoryRight->GetValue().c_str(); - output.push_back(newPair); - } - + for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + output.push_back(FolderPair((*i)->m_directoryLeft->GetValue().c_str(), + (*i)->m_directoryRight->GetValue().c_str())); return output; } @@ -1878,9 +1857,9 @@ void MainDialog::OnCompare(wxCommandEvent &event) wxBusyCursor dummy; //show hourglass cursor - //save memory by clearing old result list + //prevent temporary memory peak by clearing old result list currentGridData.clear(); - writeGrid(currentGridData); //refresh GUI grid + updateGuiGrid(); //refresh GUI grid bool aborted = false; try @@ -1900,7 +1879,8 @@ void MainDialog::OnCompare(wxCommandEvent &event) //if (output.size < 50000) statusHandler.updateStatusText(_("Sorting file list...")); statusHandler.forceUiRefresh(); //keep total number of scanned files up to date - std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_LEFT>); + + gridDataView.sortView(GridView::SORT_BY_DIRECTORY, true, true); //filter currentGridData if option is set if (cfg.filterIsActive) @@ -1936,12 +1916,12 @@ void MainDialog::OnCompare(wxCommandEvent &event) m_gridRight->ClearSelection(); //add to folder history after successful comparison only - addLeftFolderToHistory(m_comboBoxDirLeft->GetValue()); - addRightFolderToHistory(m_comboBoxDirRight->GetValue()); + addLeftFolderToHistory(m_directoryLeft->GetValue()); + addRightFolderToHistory(m_directoryRight->GetValue()); } //refresh grid in ANY case! (also on abort) - writeGrid(currentGridData); + updateGuiGrid(); } @@ -1952,28 +1932,33 @@ void MainDialog::OnAbortCompare(wxCommandEvent& event) } -void MainDialog::writeGrid(const FileCompareResult& gridData) +void MainDialog::updateGuiGrid() { - m_gridLeft->BeginBatch(); + m_gridLeft->BeginBatch(); //necessary?? m_gridMiddle->BeginBatch(); m_gridRight->BeginBatch(); - mapGridDataToUI(gridRefUI, gridData); //update gridRefUI - updateStatusInformation(gridRefUI); //write status information for gridRefUI + updateGridViewData(); //update gridDataView and write status information - //all three grids retrieve their data directly via gridRefUI!!! + //all three grids retrieve their data directly via currentGridData!!! //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_gridLeft->updateGridSizes(); m_gridMiddle->updateGridSizes(); m_gridRight->updateGridSizes(); //enlarge label width to display row numbers correctly - int nrOfRows = m_gridLeft->GetNumberRows(); + const int nrOfRows = m_gridLeft->GetNumberRows(); + if (nrOfRows >= 1) { - int nrOfDigits = int(floor(log10(double(nrOfRows)) + 1)); - m_gridLeft->SetRowLabelSize(nrOfDigits * 8 + 4); - m_gridRight->SetRowLabelSize(nrOfDigits * 8 + 4); +#ifdef FFS_WIN + const int digitWidth = 8; +#elif defined FFS_LINUX + const int digitWidth = 10; +#endif + const int nrOfDigits = int(floor(log10(double(nrOfRows)) + 1)); + m_gridLeft->SetRowLabelSize(nrOfDigits * digitWidth + 4); + m_gridRight->SetRowLabelSize(nrOfDigits * digitWidth + 4); } m_gridLeft->EndBatch(); @@ -2009,6 +1994,7 @@ void MainDialog::OnSync(wxCommandEvent& event) globalSettings.shared.copyFileSymlinks, globalSettings.shared.traverseDirectorySymlinks, globalSettings.shared.warningSignificantDifference, + globalSettings.shared.warningNotEnoughDiskSpace, &statusHandler); synchronization.startSynchronizationProcess(currentGridData, cfg.syncConfiguration); @@ -2019,14 +2005,14 @@ void MainDialog::OnSync(wxCommandEvent& event) //show remaining files that have not been processed: put DIRECTLY after startSynchronizationProcess() and DON'T call any wxWidgets functions - //in between! Else CustomGrid might access the obsolete gridRefUI! - writeGrid(currentGridData); + //in between! Else CustomGrid might access obsolete data entries in currentGridData! + updateGuiGrid(); m_gridLeft->ClearSelection(); m_gridMiddle->ClearSelection(); m_gridRight->ClearSelection(); - if (currentGridData.size() > 0) + if (gridDataView.elementsTotal() > 0) pushStatusInformation(_("Not all items were synchronized! Have a look at the list.")); else { @@ -2039,14 +2025,14 @@ void MainDialog::OnSync(wxCommandEvent& event) void MainDialog::OnLeftGridDoubleClick(wxGridEvent& event) { - openWithFileManager(event.GetRow(), m_gridLeft); + openWithFileManager(event.GetRow(), true); event.Skip(); } void MainDialog::OnRightGridDoubleClick(wxGridEvent& event) { - openWithFileManager(event.GetRow(), m_gridRight); + openWithFileManager(event.GetRow(), false); event.Skip(); } @@ -2067,35 +2053,30 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event) lastSortGrid = m_gridLeft; //start sort - xmlAccess::ColumnTypes columnType = m_gridLeft->getTypeAtPos(currentSortColumn); - if (columnType == xmlAccess::FULL_NAME) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_LEFT>); //sort by rel name here too! - else std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_LEFT>); - } - else if (columnType == xmlAccess::FILENAME) + const xmlAccess::ColumnTypes columnType = m_gridLeft->getTypeAtPos(currentSortColumn); + switch (columnType) { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_LEFT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_LEFT>); - } - else if (columnType == xmlAccess::REL_PATH) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_LEFT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_LEFT>); - } - else if (columnType == xmlAccess::SIZE) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_LEFT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_LEFT>); - } - else if (columnType == xmlAccess::DATE) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_LEFT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_LEFT>); + case xmlAccess::FULL_NAME: + gridDataView.sortView(GridView::SORT_BY_DIRECTORY, true, sortAscending); + break; + case xmlAccess::FILENAME: + gridDataView.sortView(GridView::SORT_BY_FILENAME, true, sortAscending); + break; + case xmlAccess::REL_PATH: + gridDataView.sortView(GridView::SORT_BY_REL_NAME, true, sortAscending); + break; + case xmlAccess::DIRECTORY: + gridDataView.sortView(GridView::SORT_BY_DIRECTORY, true, sortAscending); + break; + case xmlAccess::SIZE: + gridDataView.sortView(GridView::SORT_BY_FILESIZE, true, sortAscending); + break; + case xmlAccess::DATE: + gridDataView.sortView(GridView::SORT_BY_DATE, true, sortAscending); + break; } - else assert(false); - writeGrid(currentGridData); //needed to refresh gridRefUI references + updateGuiGrid(); //refresh gridDataView //set sort direction indicator on UI m_gridMiddle->setSortMarker(-1); @@ -2105,7 +2086,32 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event) else m_gridLeft->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown); } - event.Skip(); +} + + +void MainDialog::OnSortMiddleGrid(wxGridEvent& event) +{ + //determine direction for std::sort() + static bool sortAscending = true; + if (lastSortColumn != 0 || lastSortGrid != m_gridMiddle) + sortAscending = true; + else + sortAscending = !sortAscending; + lastSortColumn = 0; + lastSortGrid = m_gridMiddle; + + //start sort + gridDataView.sortView(GridView::SORT_BY_CMP_RESULT, true, sortAscending); + + updateGuiGrid(); //refresh gridDataView + + //set sort direction indicator on UI + m_gridLeft->setSortMarker(-1); + m_gridRight->setSortMarker(-1); + if (sortAscending) + m_gridMiddle->setSortMarker(0, globalResource.bitmapSmallUp); + else + m_gridMiddle->setSortMarker(0, globalResource.bitmapSmallDown); } @@ -2125,35 +2131,30 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) lastSortGrid = m_gridRight; //start sort - xmlAccess::ColumnTypes columnType = m_gridRight->getTypeAtPos(currentSortColumn); - if (columnType == xmlAccess::FULL_NAME) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_RIGHT>); //sort by rel name here too! - else std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_RIGHT>); - } - else if (columnType == xmlAccess::FILENAME) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_RIGHT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_RIGHT>); - } - else if (columnType == xmlAccess::REL_PATH) + const xmlAccess::ColumnTypes columnType = m_gridRight->getTypeAtPos(currentSortColumn); + switch (columnType) { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_RIGHT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_RIGHT>); - } - else if (columnType == xmlAccess::SIZE) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_RIGHT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_RIGHT>); - } - else if (columnType == xmlAccess::DATE) - { - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_RIGHT>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_RIGHT>); + case xmlAccess::FULL_NAME: + gridDataView.sortView(GridView::SORT_BY_DIRECTORY, false, sortAscending); + break; + case xmlAccess::FILENAME: + gridDataView.sortView(GridView::SORT_BY_FILENAME, false, sortAscending); + break; + case xmlAccess::REL_PATH: + gridDataView.sortView(GridView::SORT_BY_REL_NAME, false, sortAscending); + break; + case xmlAccess::DIRECTORY: + gridDataView.sortView(GridView::SORT_BY_DIRECTORY, false, sortAscending); + break; + case xmlAccess::SIZE: + gridDataView.sortView(GridView::SORT_BY_FILESIZE, false, sortAscending); + break; + case xmlAccess::DATE: + gridDataView.sortView(GridView::SORT_BY_DATE, false, sortAscending); + break; } - else assert(false); - writeGrid(currentGridData); //needed to refresh gridRefUI references + updateGuiGrid(); //refresh gridDataView //set sort direction indicator on UI m_gridLeft->setSortMarker(-1); @@ -2163,55 +2164,25 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) else m_gridRight->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown); } - event.Skip(); -} - - -void MainDialog::OnSortMiddleGrid(wxGridEvent& event) -{ - //determine direction for std::sort() - static bool sortAscending = true; - if (lastSortColumn != 0 || lastSortGrid != m_gridMiddle) - sortAscending = true; - else - sortAscending = !sortAscending; - lastSortColumn = 0; - lastSortGrid = m_gridMiddle; - - //start sort - if (sortAscending) std::sort(currentGridData.begin(), currentGridData.end(), sortByCmpResult<true>); - else std::sort(currentGridData.begin(), currentGridData.end(), sortByCmpResult<false>); - - writeGrid(currentGridData); //needed to refresh gridRefUI references - - //set sort direction indicator on UI - m_gridLeft->setSortMarker(-1); - m_gridRight->setSortMarker(-1); - if (sortAscending) - m_gridMiddle->setSortMarker(0, globalResource.bitmapSmallUp); - else - m_gridMiddle->setSortMarker(0, globalResource.bitmapSmallDown); - - event.Skip(); } void MainDialog::OnSwapDirs( wxCommandEvent& event ) { - //swap directory names : main pair - const wxString leftDir = m_comboBoxDirLeft->GetValue(); - const wxString rightDir = m_comboBoxDirRight->GetValue(); - m_comboBoxDirLeft->SetSelection(wxNOT_FOUND); - m_comboBoxDirRight->SetSelection(wxNOT_FOUND); + //swap directory names: main pair + const wxString leftDir = m_directoryLeft->GetValue(); + const wxString rightDir = m_directoryRight->GetValue(); + m_directoryLeft->SetSelection(wxNOT_FOUND); + m_directoryRight->SetSelection(wxNOT_FOUND); - m_comboBoxDirLeft->SetValue(rightDir); - m_comboBoxDirRight->SetValue(leftDir); + m_directoryLeft->SetValue(rightDir); + m_directoryRight->SetValue(leftDir); //additional pairs wxString tmp; - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) { - FolderPairGenerated* dirPair = *i; + FolderPairPanel* dirPair = *i; tmp = dirPair->m_directoryLeft->GetValue(); dirPair->m_directoryLeft->SetValue(dirPair->m_directoryRight->GetValue()); dirPair->m_directoryRight->SetValue(tmp); @@ -2224,87 +2195,117 @@ void MainDialog::OnSwapDirs( wxCommandEvent& event ) //swap grid information FreeFileSync::swapGrids(currentGridData); - writeGrid(currentGridData); + updateGuiGrid(); event.Skip(); } -void MainDialog::updateStatusInformation(const GridView& visibleGrid) +void MainDialog::updateGridViewData() { + const GridView::StatusInfo result = gridDataView.update( + leftOnlyFilesActive, + rightOnlyFilesActive, + leftNewerFilesActive, + rightNewerFilesActive, + differentFilesActive, + equalFilesActive, + hideFilteredElements); + + //hide or enable view filter buttons + if (result.existsLeftOnly) + m_bpButtonLeftOnly->Show(); + else + m_bpButtonLeftOnly->Hide(); + + if (result.existsRightOnly) + m_bpButtonRightOnly->Show(); + else + m_bpButtonRightOnly->Hide(); + + if (result.existsLeftNewer) + m_bpButtonLeftNewer->Show(); + else + m_bpButtonLeftNewer->Hide(); + + if (result.existsRightNewer) + m_bpButtonRightNewer->Show(); + else + m_bpButtonRightNewer->Hide(); + + if (result.existsDifferent) + m_bpButtonDifferent->Show(); + else + m_bpButtonDifferent->Hide(); + + if (result.existsEqual) + m_bpButtonEqual->Show(); + else + m_bpButtonEqual->Hide(); + + if ( result.existsLeftOnly || + result.existsRightOnly || + result.existsLeftNewer || + result.existsRightNewer || + result.existsDifferent || + result.existsEqual) + { + m_panel112->Show(); + m_panel112->Layout(); + } + else + m_panel112->Hide(); + + bSizer3->Layout(); + + + //update status information while (stackObjects.size() > 0) stackObjects.pop(); - unsigned int filesOnLeftView = 0; - unsigned int foldersOnLeftView = 0; - unsigned int filesOnRightView = 0; - unsigned int foldersOnRightView = 0; - wxULongLong filesizeLeftView; - wxULongLong filesizeRightView; - wxString statusLeftNew; wxString statusMiddleNew; wxString statusRightNew; - for (GridView::const_iterator i = visibleGrid.begin(); i != visibleGrid.end(); ++i) - { - const FileCompareLine& refLine = currentGridData[*i]; - - //calculate total number of bytes for each side - if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE) - { - filesizeLeftView+= refLine.fileDescrLeft.fileSize; - ++filesOnLeftView; - } - else if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) - ++foldersOnLeftView; - - if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE) - { - filesizeRightView+= refLine.fileDescrRight.fileSize; - ++filesOnRightView; - } - else if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) - ++foldersOnRightView; - } //################################################# //format numbers to text: //show status information on "root" level. - if (foldersOnLeftView) + if (result.foldersOnLeftView) { - if (foldersOnLeftView == 1) - statusLeftNew+= _("1 directory"); + if (result.foldersOnLeftView == 1) + statusLeftNew += _("1 directory"); else { - wxString folderCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(foldersOnLeftView)); + wxString folderCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(result.foldersOnLeftView)); wxString outputString = _("%x directories"); outputString.Replace(wxT("%x"), folderCount, false); - statusLeftNew+= outputString; + statusLeftNew += outputString; } - if (filesOnLeftView) - statusLeftNew+= wxT(", "); + if (result.filesOnLeftView) + statusLeftNew += wxT(", "); } - if (filesOnLeftView) + if (result.filesOnLeftView) { - if (filesOnLeftView == 1) - statusLeftNew+= _("1 file,"); + if (result.filesOnLeftView == 1) + statusLeftNew += _("1 file,"); else { - wxString fileCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(filesOnLeftView)); + wxString fileCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(result.filesOnLeftView)); wxString outputString = _("%x files,"); outputString.Replace(wxT("%x"), fileCount, false); - statusLeftNew+= outputString; + statusLeftNew += outputString; } - statusLeftNew+= wxT(" "); - statusLeftNew+= FreeFileSync::formatFilesizeToShortString(filesizeLeftView); + statusLeftNew += wxT(" "); + statusLeftNew += FreeFileSync::formatFilesizeToShortString(result.filesizeLeftView); } - wxString objectsView = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(visibleGrid.size())); - if (currentGridData.size() == 1) + const wxString objectsView = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(gridDataView.elementsOnView())); + const unsigned int objCount = gridDataView.elementsTotal(); + if (objCount == 1) { wxString outputString = _("%x of 1 row in view"); outputString.Replace(wxT("%x"), objectsView, false); @@ -2312,7 +2313,7 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) } else { - wxString objectsTotal = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(currentGridData.size())); + const wxString objectsTotal = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objCount)); wxString outputString = _("%x of %y rows in view"); outputString.Replace(wxT("%x"), objectsView, false); @@ -2320,38 +2321,38 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) statusMiddleNew = outputString; } - if (foldersOnRightView) + if (result.foldersOnRightView) { - if (foldersOnRightView == 1) - statusRightNew+= _("1 directory"); + if (result.foldersOnRightView == 1) + statusRightNew += _("1 directory"); else { - wxString folderCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(foldersOnRightView)); + wxString folderCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(result.foldersOnRightView)); wxString outputString = _("%x directories"); outputString.Replace(wxT("%x"), folderCount, false); - statusRightNew+= outputString; + statusRightNew += outputString; } - if (filesOnRightView) - statusRightNew+= wxT(", "); + if (result.filesOnRightView) + statusRightNew += wxT(", "); } - if (filesOnRightView) + if (result.filesOnRightView) { - if (filesOnRightView == 1) - statusRightNew+= _("1 file,"); + if (result.filesOnRightView == 1) + statusRightNew += _("1 file,"); else { - wxString fileCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(filesOnRightView)); + wxString fileCount = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(result.filesOnRightView)); wxString outputString = _("%x files,"); outputString.Replace(wxT("%x"), fileCount, false); - statusRightNew+= outputString; + statusRightNew += outputString; } - statusRightNew+= wxT(" "); - statusRightNew+= FreeFileSync::formatFilesizeToShortString(filesizeRightView); + statusRightNew += wxT(" "); + statusRightNew += FreeFileSync::formatFilesizeToShortString(result.filesizeRightView); } @@ -2367,97 +2368,6 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) } -void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& fileCmpResult) -{ - output.clear(); - - //only show those view filter buttons that really need to be displayed - bool leftOnly, rightOnly, leftNewer, rightNewer, different, equal; - leftOnly = rightOnly = leftNewer = rightNewer = different = equal = false; - - 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) - { - case FILE_LEFT_SIDE_ONLY: - leftOnly = true; - if (!leftOnlyFilesActive) continue; - break; - case FILE_RIGHT_SIDE_ONLY: - rightOnly = true; - if (!rightOnlyFilesActive) continue; - break; - case FILE_LEFT_NEWER: - leftNewer = true; - if (!leftNewerFilesActive) continue; - break; - case FILE_RIGHT_NEWER: - rightNewer = true; - if (!rightNewerFilesActive) continue; - break; - case FILE_DIFFERENT: - different = true; - if (!differentFilesActive) continue; - break; - case FILE_EQUAL: - equal = true; - if (!equalFilesActive) continue; - break; - default: - assert (false); - } - output.push_back(currentRow); - } - - //hide or enable view filter buttons - if (leftOnly) - m_bpButtonLeftOnly->Show(); - else - m_bpButtonLeftOnly->Hide(); - - if (rightOnly) - m_bpButtonRightOnly->Show(); - else - m_bpButtonRightOnly->Hide(); - - if (leftNewer) - m_bpButtonLeftNewer->Show(); - else - m_bpButtonLeftNewer->Hide(); - - if (rightNewer) - m_bpButtonRightNewer->Show(); - else - m_bpButtonRightNewer->Hide(); - - if (different) - m_bpButtonDifferent->Show(); - else - m_bpButtonDifferent->Hide(); - - if (equal) - m_bpButtonEqual->Show(); - else - m_bpButtonEqual->Hide(); - - if (leftOnly || rightOnly || leftNewer || rightNewer || different || equal) - { - m_panel112->Show(); - m_panel112->Layout(); - } - else - m_panel112->Hide(); - - bSizer3->Layout(); -} - - void MainDialog::OnAddFolderPair(wxCommandEvent& event) { addFolderPair(wxEmptyString, wxEmptyString); @@ -2467,7 +2377,7 @@ void MainDialog::OnAddFolderPair(wxCommandEvent& event) //clear grids currentGridData.clear(); - writeGrid(currentGridData); + updateGuiGrid(); } @@ -2475,7 +2385,7 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) { //find folder pair originating the event const wxObject* const eventObj = event.GetEventObject(); - for (std::vector<FolderPairGenerated*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) { if (eventObj == static_cast<wxObject*>((*i)->m_bpButtonRemovePair)) { @@ -2486,7 +2396,7 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) //clear grids currentGridData.clear(); - writeGrid(currentGridData); + updateGuiGrid(); return; } } @@ -2513,7 +2423,7 @@ void MainDialog::addFolderPair(const std::vector<FolderPair>& newPairs) for (std::vector<FolderPair>::const_iterator i = newPairs.begin(); i != newPairs.end(); ++i) { //add new folder pair - FolderPairGenerated* newPair = new FolderPairGenerated(m_scrolledWindowFolderPairs); + FolderPairPanel* newPair = new FolderPairPanel(m_scrolledWindowFolderPairs); newPair->m_bitmap23->SetBitmap(*globalResource.bitmapLink); newPair->m_bpButtonRemovePair->SetBitmapLabel(*globalResource.bitmapRemoveFolderPair); @@ -2530,18 +2440,8 @@ void MainDialog::addFolderPair(const std::vector<FolderPair>& newPairs) m_scrolledWindowFolderPairs->Fit(); //register events - newPair->m_dirPickerLeft->Connect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(MainDialog::OnDirSelected), NULL, this); - newPair->m_dirPickerRight->Connect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(MainDialog::OnDirSelected), NULL, this); - - newPair->m_directoryLeft->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(MainDialog::OnWriteDirManually), NULL, this ); - newPair->m_directoryRight->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(MainDialog::OnWriteDirManually), NULL, this ); - newPair->m_bpButtonRemovePair->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainDialog::OnRemoveFolderPair), NULL, this ); - //prepare drag & drop - newPair->m_panelLeft->SetDropTarget(new MainWindowDropTarget(this, newPair->m_panelLeft)); //ownership passed - newPair->m_panelRight->SetDropTarget(new MainWindowDropTarget(this, newPair->m_panelRight)); - //insert directory names if provided newPair->m_directoryLeft->SetValue(i->leftDirectory.c_str()); const wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(i->leftDirectory).c_str(); @@ -2579,7 +2479,7 @@ void MainDialog::removeFolderPair(const int pos, bool refreshLayout) { wxSize pairSize; //remove folder pairs from window - FolderPairGenerated* pairToDelete = additionalFolderPairs[pos]; + FolderPairPanel* pairToDelete = additionalFolderPairs[pos]; pairSize = pairToDelete->GetSize(); bSizerFolderPairs->Detach(pairToDelete); //Remove() does not work on Window*, so do it manually @@ -2620,404 +2520,6 @@ void MainDialog::clearFolderPairs() //######################################################################################################## -CompareStatusHandler::CompareStatusHandler(MainDialog* dlg) : - mainDialog(dlg), - ignoreErrors(false), - 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.. - mainDialog->m_radioBtnSizeDate->Disable(); - mainDialog->m_radioBtnContent->Disable(); - mainDialog->m_bpButtonFilter->Disable(); - mainDialog->m_hyperlinkCfgFilter->Disable(); - mainDialog->m_checkBoxHideFilt->Disable(); - mainDialog->m_buttonSync->Disable(); - mainDialog->m_dirPickerLeft->Disable(); - mainDialog->m_dirPickerRight->Disable(); - mainDialog->m_bpButtonSwap->Disable(); - mainDialog->m_bpButtonLeftOnly->Disable(); - mainDialog->m_bpButtonLeftNewer->Disable(); - mainDialog->m_bpButtonEqual->Disable(); - mainDialog->m_bpButtonDifferent->Disable(); - mainDialog->m_bpButtonRightNewer->Disable(); - mainDialog->m_bpButtonRightOnly->Disable(); - mainDialog->m_panel1->Disable(); - mainDialog->m_panel2->Disable(); - mainDialog->m_panel3->Disable(); - mainDialog->m_panel11->Disable(); - mainDialog->m_panel12->Disable(); - mainDialog->m_panel13->Disable(); - mainDialog->m_bpButtonSave->Disable(); - mainDialog->m_bpButtonLoad->Disable(); - mainDialog->m_choiceHistory->Disable(); - mainDialog->m_bpButton10->Disable(); - mainDialog->m_bpButton14->Disable(); - mainDialog->m_scrolledWindowFolderPairs->Disable(); - mainDialog->m_menubar1->EnableTop(0, false); - mainDialog->m_menubar1->EnableTop(1, false); - mainDialog->m_menubar1->EnableTop(2, false); - - //show abort button - mainDialog->m_buttonAbort->Enable(); - mainDialog->m_buttonAbort->Show(); - mainDialog->m_buttonCompare->Disable(); - mainDialog->m_buttonCompare->Hide(); - mainDialog->m_buttonAbort->SetFocus(); - - //display status panel during compare - mainDialog->compareStatus->init(); //clear old values - mainDialog->compareStatus->Show(); - - //updateUiNow(); - mainDialog->bSizer1->Layout(); //both sizers need to recalculate! - mainDialog->bSizer6->Layout(); //adapt layout for wxBitmapWithImage - mainDialog->Refresh(); -} - - -CompareStatusHandler::~CompareStatusHandler() -{ - updateUiNow(); //ui update before enabling buttons again: prevent strange behaviour of delayed button clicks - - //reenable complete main dialog - mainDialog->m_radioBtnSizeDate->Enable(); - mainDialog->m_radioBtnContent->Enable(); - mainDialog->m_bpButtonFilter->Enable(); - mainDialog->m_hyperlinkCfgFilter->Enable(); - mainDialog->m_checkBoxHideFilt->Enable(); - mainDialog->m_buttonSync->Enable(); - mainDialog->m_dirPickerLeft->Enable(); - mainDialog->m_dirPickerRight->Enable(); - mainDialog->m_bpButtonSwap->Enable(); - mainDialog->m_bpButtonLeftOnly->Enable(); - mainDialog->m_bpButtonLeftNewer->Enable(); - mainDialog->m_bpButtonEqual->Enable(); - mainDialog->m_bpButtonDifferent->Enable(); - mainDialog->m_bpButtonRightNewer->Enable(); - mainDialog->m_bpButtonRightOnly->Enable(); - mainDialog->m_panel1->Enable(); - mainDialog->m_panel2->Enable(); - mainDialog->m_panel3->Enable(); - mainDialog->m_panel11->Enable(); - mainDialog->m_panel12->Enable(); - mainDialog->m_panel13->Enable(); - mainDialog->m_bpButtonSave->Enable(); - mainDialog->m_bpButtonLoad->Enable(); - mainDialog->m_choiceHistory->Enable(); - mainDialog->m_bpButton10->Enable(); - mainDialog->m_bpButton14->Enable(); - mainDialog->m_scrolledWindowFolderPairs->Enable(); - mainDialog->m_menubar1->EnableTop(0, true); - mainDialog->m_menubar1->EnableTop(1, true); - mainDialog->m_menubar1->EnableTop(2, true); - - if (abortRequested) - mainDialog->pushStatusInformation(_("Operation aborted!")); - - mainDialog->m_buttonAbort->Disable(); - mainDialog->m_buttonAbort->Hide(); - mainDialog->m_buttonCompare->Enable(); //enable compare button - mainDialog->m_buttonCompare->Show(); - - //hide status panel from main window - mainDialog->compareStatus->Hide(); - - mainDialog->bSizer6->Layout(); //adapt layout for wxBitmapWithImage - - mainDialog->Layout(); - mainDialog->Refresh(); -} - - -inline -void CompareStatusHandler::updateStatusText(const Zstring& text) -{ - mainDialog->compareStatus->setStatusText_NoUpdate(text); -} - - -void CompareStatusHandler::initNewProcess(int objectsTotal, double dataTotal, Process processID) -{ - currentProcess = processID; - - if (currentProcess == StatusHandler::PROCESS_SCANNING) - ; - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) - { - mainDialog->compareStatus->switchToCompareBytewise(objectsTotal, dataTotal); - mainDialog->Layout(); - } - - else assert(false); -} - - -inline -void CompareStatusHandler::updateProcessedData(int objectsProcessed, double dataProcessed) -{ - if (currentProcess == StatusHandler::PROCESS_SCANNING) - mainDialog->compareStatus->incScannedObjects_NoUpdate(objectsProcessed); - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) - mainDialog->compareStatus->incProcessedCmpData_NoUpdate(objectsProcessed, dataProcessed); - else assert(false); -} - - -ErrorHandler::Response CompareStatusHandler::reportError(const Zstring& text) -{ - if (ignoreErrors) - return ErrorHandler::IGNORE_ERROR; - - mainDialog->compareStatus->updateStatusPanelNow(); - - bool ignoreNextErrors = false; - wxString errorMessage = wxString(text.c_str()) + wxT("\n\n") + _("Ignore this error, retry or abort?"); - ErrorDlg* errorDlg = new ErrorDlg(mainDialog, - ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, - errorMessage, ignoreNextErrors); - int rv = errorDlg->ShowModal(); - switch (rv) - { - case ErrorDlg::BUTTON_IGNORE: - ignoreErrors = ignoreNextErrors; - return ErrorHandler::IGNORE_ERROR; - - case ErrorDlg::BUTTON_RETRY: - return ErrorHandler::RETRY; - - case ErrorDlg::BUTTON_ABORT: - abortThisProcess(); - } - - assert(false); - return ErrorHandler::IGNORE_ERROR; //dummy return value -} - - -void CompareStatusHandler::reportFatalError(const Zstring& errorMessage) -{ - mainDialog->compareStatus->updateStatusPanelNow(); - - bool dummy = false; - ErrorDlg* errorDlg = new ErrorDlg(mainDialog, - ErrorDlg::BUTTON_ABORT, - errorMessage.c_str(), dummy); - errorDlg->ShowModal(); - abortThisProcess(); -} - - -void CompareStatusHandler::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) -{ - if (ignoreErrors) //if errors are ignored, then warnings should also - return; - - mainDialog->compareStatus->updateStatusPanelNow(); - - //show popup and ask user how to handle warning - bool dontWarnAgain = false; - WarningDlg* warningDlg = new WarningDlg(mainDialog, - WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, - warningMessage.c_str(), - dontWarnAgain); - switch (warningDlg->ShowModal()) - { - case WarningDlg::BUTTON_ABORT: - abortThisProcess(); - - case WarningDlg::BUTTON_IGNORE: - dontShowAgain = dontWarnAgain; - return; - } - - assert(false); -} - - -inline -void CompareStatusHandler::forceUiRefresh() -{ - mainDialog->compareStatus->updateStatusPanelNow(); -} - - -void CompareStatusHandler::abortThisProcess() -{ - abortRequested = true; - throw AbortThisProcess(); //abort can be triggered by syncStatusFrame -} -//######################################################################################################## - - -SyncStatusHandler::SyncStatusHandler(wxWindow* dlg, bool ignoreAllErrors) : - ignoreErrors(ignoreAllErrors) -{ - syncStatusFrame = new SyncStatus(this, dlg); - syncStatusFrame->Show(); - updateUiNow(); -} - - -SyncStatusHandler::~SyncStatusHandler() -{ - //print the results list - unsigned int failedItems = unhandledErrors.GetCount(); - wxString result; - if (failedItems) - { - result = wxString(_("Warning: Synchronization failed for %x item(s):")) + wxT("\n\n"); - result.Replace(wxT("%x"), globalFunctions::numberToWxString(failedItems), false); - - for (unsigned int j = 0; j < failedItems; ++j) - { //remove linebreaks - wxString errorMessage = unhandledErrors[j]; - for (wxString::iterator i = errorMessage.begin(); i != errorMessage.end(); ++i) - if (*i == wxChar('\n')) - *i = wxChar(' '); - - result += errorMessage + wxT("\n"); - } - result+= wxT("\n"); - } - - //notify to syncStatusFrame that current process has ended - if (abortRequested) - { - result+= wxString(_("Synchronization aborted!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); - syncStatusFrame->setStatusText_NoUpdate(result.c_str()); - syncStatusFrame->processHasFinished(SyncStatus::ABORTED); //enable okay and close events - } - else if (failedItems) - { - result+= wxString(_("Synchronization completed with errors!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); - syncStatusFrame->setStatusText_NoUpdate(result.c_str()); - syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_ERROR); - } - else - { - result+= _("Synchronization completed successfully!"); - syncStatusFrame->setStatusText_NoUpdate(result.c_str()); - syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS); - } -} - - -inline -void SyncStatusHandler::updateStatusText(const Zstring& text) -{ - syncStatusFrame->setStatusText_NoUpdate(text); -} - - -void SyncStatusHandler::initNewProcess(int objectsTotal, double dataTotal, Process processID) -{ - assert (processID == StatusHandler::PROCESS_SYNCHRONIZING); - - syncStatusFrame->resetGauge(objectsTotal, dataTotal); - syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); -} - - -inline -void SyncStatusHandler::updateProcessedData(int objectsProcessed, double dataProcessed) -{ - syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); -} - - -ErrorHandler::Response SyncStatusHandler::reportError(const Zstring& text) -{ - //add current time before error message - wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + text.c_str(); - - if (ignoreErrors) - { - unhandledErrors.Add(errorWithTime); - return ErrorHandler::IGNORE_ERROR; - } - - syncStatusFrame->updateStatusDialogNow(); - - bool ignoreNextErrors = false; - ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, - ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, - wxString(text) + wxT("\n\n") + _("Ignore this error, retry or abort synchronization?"), - ignoreNextErrors); - int rv = errorDlg->ShowModal(); - switch (rv) - { - case ErrorDlg::BUTTON_IGNORE: - ignoreErrors = ignoreNextErrors; - unhandledErrors.Add(errorWithTime); - return ErrorHandler::IGNORE_ERROR; - - case ErrorDlg::BUTTON_RETRY: - return ErrorHandler::RETRY; - - case ErrorDlg::BUTTON_ABORT: - unhandledErrors.Add(errorWithTime); - abortThisProcess(); - } - - assert (false); - unhandledErrors.Add(errorWithTime); - return ErrorHandler::IGNORE_ERROR; -} - - -void SyncStatusHandler::reportFatalError(const Zstring& errorMessage) -{ //add current time before error message - wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); - - unhandledErrors.Add(errorWithTime); - abortThisProcess(); -} - - -void SyncStatusHandler::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) -{ //add current time before warning message - wxString warningWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + warningMessage.c_str(); - - if (ignoreErrors) //if errors are ignored, then warnings should also - return; //no unhandled error situation! - - syncStatusFrame->updateStatusDialogNow(); - - //show popup and ask user how to handle warning - bool dontWarnAgain = false; - WarningDlg* warningDlg = new WarningDlg(syncStatusFrame, - WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, - warningMessage.c_str(), - dontWarnAgain); - switch (warningDlg->ShowModal()) - { - case WarningDlg::BUTTON_IGNORE: //no unhandled error situation! - dontShowAgain = dontWarnAgain; - return; - - case WarningDlg::BUTTON_ABORT: - unhandledErrors.Add(warningWithTime); - abortThisProcess(); - } - - assert(false); -} - - -void SyncStatusHandler::forceUiRefresh() -{ - syncStatusFrame->updateStatusDialogNow(); -} - - -void SyncStatusHandler::abortThisProcess() -{ - abortRequested = true; - throw AbortThisProcess(); //abort can be triggered by syncStatusFrame -} -//######################################################################################################## - //menu events void MainDialog::OnMenuGlobalSettings(wxCommandEvent& event) @@ -3032,26 +2534,26 @@ void MainDialog::OnMenuGlobalSettings(wxCommandEvent& event) void MainDialog::OnMenuExportFileList(wxCommandEvent& event) { //get a filename - wxString fileName = wxT("FileList.csv"); //proposal - wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, fileName, wxString(_("Comma separated list")) + wxT(" (*.csv)|*.csv"), wxFD_SAVE); + const wxString defaultFileName = wxT("FileList.csv"); //proposal + wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("Comma separated list")) + wxT(" (*.csv)|*.csv"), wxFD_SAVE); if (filePicker->ShowModal() == wxID_OK) { - fileName = filePicker->GetPath(); - if (FreeFileSync::fileExists(fileName.c_str())) + const wxString newFileName = filePicker->GetPath(); + if (FreeFileSync::fileExists(newFileName.c_str())) { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + fileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); + wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) { - pushStatusInformation(_("Save aborted!")); + OnMenuExportFileList(event); //retry return; } } //begin work wxString exportString; - for (unsigned int i = 0; i < gridRefUI.size(); ++i) + for (int i = 0; i < m_gridLeft->GetNumberRows(); ++i) { for (int k = 0; k < m_gridLeft->GetNumberCols(); ++k) { @@ -3075,7 +2577,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } //write export file - wxFFile output(fileName.c_str(), wxT("w")); //don't write in binary mode + wxFFile output(newFileName.c_str(), wxT("w")); //don't write in binary mode if (output.IsOpened()) { output.Write(exportString); @@ -3083,7 +2585,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } else { - wxMessageBox(wxString(_("Error writing file:")) + wxT(" \"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Error writing file:")) + wxT(" \"") + newFileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR); } } } @@ -3110,7 +2612,16 @@ void MainDialog::OnMenuBatchJob(wxCommandEvent& event) void MainDialog::OnMenuCheckVersion(wxCommandEvent& event) { - FreeFileSync::checkForNewVersion(); + FreeFileSync::checkForUpdateNow(); +} + + +void MainDialog::OnRegularUpdateCheck(wxIdleEvent& event) +{ + //execute just once per startup! + Disconnect(wxEVT_IDLE, wxIdleEventHandler(MainDialog::OnRegularUpdateCheck), NULL, this); + + FreeFileSync::checkForUpdatePeriodically(globalSettings.shared.lastUpdateCheck); } @@ -3123,7 +2634,7 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event) void MainDialog::OnMenuQuit(wxCommandEvent& event) { - Destroy(); + requestShutdown(); } @@ -3138,7 +2649,7 @@ void MainDialog::switchProgramLanguage(const int langID) cleanUp(); //destructor's code: includes writing settings to HD //create new dialog with respect to new language - MainDialog* frame = new MainDialog(NULL, FreeFileSync::LAST_CONFIG_FILE, programLanguage, globalSettings); + MainDialog* frame = new MainDialog(NULL, xmlAccess::LAST_CONFIG_FILE, programLanguage, globalSettings); frame->SetIcon(*globalResource.programIcon); //set application icon frame->Show(); @@ -3206,6 +2717,12 @@ void MainDialog::OnMenuLangPortuguese(wxCommandEvent& event) } +void MainDialog::OnMenuLangPortugueseBrazil(wxCommandEvent& event) +{ + switchProgramLanguage(wxLANGUAGE_PORTUGUESE_BRAZILIAN); +} + + void MainDialog::OnMenuLangSlovenian(wxCommandEvent& event) { switchProgramLanguage(wxLANGUAGE_SLOVENIAN); @@ -3217,3 +2734,4 @@ void MainDialog::OnMenuLangSpanish(wxCommandEvent& event) switchProgramLanguage(wxLANGUAGE_SPANISH); } + diff --git a/ui/MainDialog.h b/ui/MainDialog.h index 6e60fab3..49d5ceee 100644 --- a/ui/MainDialog.h +++ b/ui/MainDialog.h @@ -1,6 +1,6 @@ /*************************************************************** * Name: mainDialog.h - * Purpose: Defines Application Frame + * Purpose: Main Application Dialog * Author: ZenJu (zhnmju123@gmx.de) * Created: 2008-07-16 **************************************************************/ @@ -9,48 +9,47 @@ #define MAINDIALOG_H #include "guiGenerated.h" -#include "syncDialog.h" -#include "smallDialogs.h" -#include "../library/resources.h" -#include "../library/misc.h" -#include <wx/dnd.h> #include <stack> #include "../library/processXml.h" -#include <wx/event.h> +#include "gridView.h" #include <memory> +class CompareStatusHandler; +class CompareStatus; +class CustomLocale; +class MainFolderDragDrop; +class FolderPairPanel; +class CustomGrid; -//IDs for context menu items -enum //context menu for left and right grids -{ - CONTEXT_FILTER_TEMP = 10, - CONTEXT_EXCLUDE_EXT, - CONTEXT_EXCLUDE_OBJ, - CONTEXT_CLIPBOARD, - CONTEXT_EXPLORER, - CONTEXT_DELETE_FILES, -}; -enum //context menu for middle grid +class MainDialog : public MainDialogGenerated { - CONTEXT_CHECK_ALL, - CONTEXT_UNCHECK_ALL -}; + friend class CompareStatusHandler; + friend class MainFolderDragDrop; -enum //context menu for column settings -{ - CONTEXT_CUSTOMIZE_COLUMN_LEFT, - CONTEXT_CUSTOMIZE_COLUMN_RIGHT -}; +//IDs for context menu items + enum //context menu for left and right grids + { + CONTEXT_FILTER_TEMP = 10, + CONTEXT_EXCLUDE_EXT, + CONTEXT_EXCLUDE_OBJ, + CONTEXT_CLIPBOARD, + CONTEXT_EXPLORER, + CONTEXT_DELETE_FILES, + }; -class CompareStatusHandler; -class FileDropEvent; -class FfsFileDropEvent; + enum //context menu for middle grid + { + CONTEXT_CHECK_ALL, + CONTEXT_UNCHECK_ALL + }; + + enum //context menu for column settings + { + CONTEXT_CUSTOMIZE_COLUMN_LEFT, + CONTEXT_CUSTOMIZE_COLUMN_RIGHT + }; -class MainDialog : public MainDialogGenerated -{ - friend class CompareStatusHandler; - friend class FileDropEvent; public: MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings); @@ -62,6 +61,9 @@ private: //configuration load/save bool readConfigurationFromXml(const wxString& filename, bool programStartup = false); bool writeConfigurationToXml(const wxString& filename); + xmlAccess::XmlGuiConfig getCurrentConfiguration() const; + + xmlAccess::XmlGuiConfig lastConfigurationSaved; //support for: "Save changed configuration?" dialog void readGlobalSettings(); void writeGlobalSettings(); @@ -75,21 +77,21 @@ private: void addRightFolderToHistory(const wxString& rightFolder); void addFolderPair(const Zstring& leftDir, const Zstring& rightDir); - void addFolderPair(const std::vector<FolderPair>& newPairs); + void addFolderPair(const std::vector<FreeFileSync::FolderPair>& newPairs); void removeFolderPair(const int pos, bool refreshLayout = true); //keep it an int, allow negative values! void clearFolderPairs(); - //main method for putting gridData on UI: maps data respecting current view settings - void writeGrid(const FileCompareResult& gridData); - void mapGridDataToUI(GridView& output, const FileCompareResult& fileCmpResult); - void updateStatusInformation(const GridView& output); + //main method for putting gridDataView on UI: updates data respecting current view settings + void updateGuiGrid(); + + void updateGridViewData(); //context menu functions - std::set<int> getSelectedRows(const wxGrid* grid); + std::set<int> getSelectedRows(const CustomGrid* grid); void filterRangeManually(const std::set<int>& rowsToFilterOnUiTable); - void copySelectionToClipboard(const wxGrid* selectedGrid); - void openWithFileManager(int rowNumber, const wxGrid* grid); - void deleteFilesOnGrid(const std::set<int>& selectedRowsLeft, const std::set<int>& selectedRowsRight); + void copySelectionToClipboard(const CustomGrid* selectedGrid); + void openWithFileManager(const int rowNumber, const bool leftSide); + void deleteSelectedFiles(); //work to be done in idle time void OnIdleEvent(wxEvent& event); @@ -110,9 +112,10 @@ private: void OnContextColumnRight(wxGridEvent& event); void OnContextColumnSelection(wxCommandEvent& event); - void OnWriteDirManually(wxCommandEvent& event); void OnDirSelected(wxFileDirPickerEvent& event); + void requestShutdown(); //try to exit application + //manual filtering of rows: void OnGridSelectCell(wxGridEvent& event); void OnGrid3LeftMouseUp(wxEvent& event); @@ -121,8 +124,8 @@ private: void OnLeftGridDoubleClick( wxGridEvent& event); void OnRightGridDoubleClick(wxGridEvent& event); void OnSortLeftGrid( wxGridEvent& event); - void OnSortRightGrid( wxGridEvent& event); void OnSortMiddleGrid( wxGridEvent& event); + void OnSortRightGrid( wxGridEvent& event); void OnLeftOnlyFiles( wxCommandEvent& event); void OnLeftNewerFiles( wxCommandEvent& event); @@ -137,8 +140,8 @@ private: void loadConfiguration(const wxString& filename); void OnCfgHistoryKeyEvent( wxKeyEvent& event); void OnFolderHistoryKeyEvent(wxKeyEvent& event); + void OnRegularUpdateCheck( wxIdleEvent& event); - void OnFilesDropped( FfsFileDropEvent& event); void onResizeMainWindow( wxEvent& event); void OnAbortCompare( wxCommandEvent& event); void OnFilterButton( wxCommandEvent& event); @@ -175,6 +178,7 @@ private: void OnMenuLangJapanese( wxCommandEvent& event); void OnMenuLangPolish( wxCommandEvent& event); void OnMenuLangPortuguese( wxCommandEvent& event); + void OnMenuLangPortugueseBrazil(wxCommandEvent& event); void OnMenuLangSlovenian( wxCommandEvent& event); void OnMenuLangSpanish( wxCommandEvent& event); @@ -188,18 +192,18 @@ private: xmlAccess::XmlGlobalSettings& globalSettings; //technical representation of grid-data - FileCompareResult currentGridData; + FreeFileSync::FolderComparison currentGridData; //UI view of currentGridData - GridView gridRefUI; + FreeFileSync::GridView gridDataView; //------------------------------------- //functional configuration - MainConfiguration cfg; + FreeFileSync::MainConfiguration cfg; //folder pairs: //m_directoryLeft, m_directoryRight - std::vector<FolderPairGenerated*> additionalFolderPairs; //additional pairs to the standard pair + std::vector<FolderPairPanel*> additionalFolderPairs; //additional pairs to the standard pair //gui settings int widthNotMaximized; @@ -211,7 +215,7 @@ private: //------------------------------------- //convenience method to get all folder pairs (unformatted) - std::vector<FolderPair> getFolderPairs(); + std::vector<FreeFileSync::FolderPair> getFolderPairs() const; //UI View Filter settings bool leftOnlyFilesActive; @@ -248,7 +252,7 @@ private: struct FilterObject { wxString relativeName; - FileDescrLine::ObjectType type; + FreeFileSync::FileDescrLine::ObjectType type; }; std::vector<FilterObject> exFilterCandidateObj; @@ -261,98 +265,10 @@ private: //remember last sort executed (for determination of sort order) int lastSortColumn; const wxGrid* lastSortGrid; -}; - -//###################################################################################### - -//define new event type -const wxEventType FFS_DROP_FILE_EVENT = wxNewEventType(); -typedef void (wxEvtHandler::*FffsFileDropEventFunction)(FfsFileDropEvent&); -#define FfsFileDropEventHandler(func) \ - (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FffsFileDropEventFunction, &func) - -class FfsFileDropEvent : public wxCommandEvent -{ -public: - FfsFileDropEvent(const wxString& nameDropped, const wxPanel* dropTarget) : - wxCommandEvent(FFS_DROP_FILE_EVENT), - m_nameDropped(nameDropped), - m_dropTarget(dropTarget) {} - - virtual wxEvent* Clone() const - { - return new FfsFileDropEvent(m_nameDropped, m_dropTarget); - } - - const wxString m_nameDropped; - const wxPanel* m_dropTarget; -}; - -class MainWindowDropTarget : public wxFileDropTarget -{ -public: - MainWindowDropTarget(MainDialog* dlg, const wxPanel* obj) : - mainDlg(dlg), - dropTarget(obj) {} - - virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames); - -private: - MainDialog* mainDlg; - const wxPanel* dropTarget; + //support for drag and drop + std::auto_ptr<MainFolderDragDrop> dragDropOnLeft; + std::auto_ptr<MainFolderDragDrop> dragDropOnRight; }; -//###################################################################################### - -//classes handling sync and compare error as well as status information - -class CompareStatusHandler : public StatusHandler -{ -public: - CompareStatusHandler(MainDialog* dlg); - ~CompareStatusHandler(); - - virtual void updateStatusText(const Zstring& text); - virtual void initNewProcess(int objectsTotal, double dataTotal, Process processID); - virtual void updateProcessedData(int objectsProcessed, double dataProcessed); - virtual void forceUiRefresh(); - - virtual ErrorHandler::Response reportError(const Zstring& text); - virtual void reportFatalError(const Zstring& errorMessage); - virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); - -private: - virtual void abortThisProcess(); - - MainDialog* mainDialog; - bool ignoreErrors; - Process currentProcess; -}; - - -class SyncStatusHandler : public StatusHandler -{ -public: - SyncStatusHandler(wxWindow* dlg, bool ignoreAllErrors); - ~SyncStatusHandler(); - - virtual void updateStatusText(const Zstring& text); - virtual void initNewProcess(int objectsTotal, double dataTotal, Process processID); - virtual void updateProcessedData(int objectsProcessed, double dataProcessed); - virtual void forceUiRefresh(); - - virtual ErrorHandler::Response reportError(const Zstring& text); - virtual void reportFatalError(const Zstring& errorMessage); - virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); - -private: - virtual void abortThisProcess(); - - SyncStatus* syncStatusFrame; - bool ignoreErrors; - wxArrayString unhandledErrors; //list of non-resolved errors -}; - - #endif // MAINDIALOG_H diff --git a/ui/SmallDialogs.cpp b/ui/SmallDialogs.cpp index c32f8ce6..b553dff7 100644 --- a/ui/SmallDialogs.cpp +++ b/ui/SmallDialogs.cpp @@ -5,6 +5,7 @@ #include <wx/msgdlg.h> #include "../library/customGrid.h" #include "../library/customButton.h" +#include "../library/statistics.h" using namespace FreeFileSync; @@ -16,14 +17,26 @@ AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) m_bitmap11->SetBitmap(*globalResource.bitmapLogo); m_bitmap13->SetBitmap(*globalResource.bitmapGPL); + //flag bitmaps + m_bitmapFrench ->SetBitmap(*globalResource.bitmapFrance); + m_bitmapJapanese ->SetBitmap(*globalResource.bitmapJapan); + m_bitmapDutch ->SetBitmap(*globalResource.bitmapHolland); + m_bitmapChineseSimple ->SetBitmap(*globalResource.bitmapChina); + m_bitmapPolish ->SetBitmap(*globalResource.bitmapPoland); + m_bitmapPortuguese ->SetBitmap(*globalResource.bitmapPortugal); + m_bitmapItalian ->SetBitmap(*globalResource.bitmapItaly); + m_bitmapSlovenian ->SetBitmap(*globalResource.bitmapSlovakia); + m_bitmapHungarian ->SetBitmap(*globalResource.bitmapHungary); + m_bitmapSpanish ->SetBitmap(*globalResource.bitmapSpain); + m_bitmapPortugueseBrazil->SetBitmap(*globalResource.bitmapBrazil); + //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build+= wxT(" - Unicode"); + build+= wxT(" - Unicode)"); #else - build+= wxT(" - ANSI"); + build+= wxT(" - ANSI)"); #endif //wxUSE_UNICODE - build+= + wxT(")"); m_build->SetLabel(build); m_animationControl1->SetAnimation(*globalResource.animationMoney); @@ -35,9 +48,6 @@ AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) } -AboutDlg::~AboutDlg() {} - - void AboutDlg::OnClose(wxCloseEvent& event) { EndModal(0); @@ -124,8 +134,6 @@ FilterDlg::FilterDlg(wxWindow* window, wxString& filterIncl, wxString& filterExc Fit(); } -FilterDlg::~FilterDlg() {} - void FilterDlg::OnHelp(wxCommandEvent& event) { @@ -173,13 +181,13 @@ void FilterDlg::OnClose(wxCloseEvent& event) //######################################################################################## DeleteDialog::DeleteDialog(wxWindow* main, - const FileCompareResult& grid, - const std::set<int>& rowsOnLeft, - const std::set<int>& rowsOnRight, + const FreeFileSync::FolderComparison& folderCmp, + const FreeFileSync::FolderCompRef& rowsOnLeft, + const FreeFileSync::FolderCompRef& rowsOnRight, bool& deleteOnBothSides, bool& useRecycleBin) : DeleteDlgGenerated(main), - mainGrid(grid), + m_folderCmp(folderCmp), rowsToDeleteOnLeft(rowsOnLeft), rowsToDeleteOnRight(rowsOnRight), m_deleteOnBothSides(deleteOnBothSides), @@ -208,10 +216,24 @@ void DeleteDialog::updateTexts() } m_staticTextHeader->SetLabel(headerText); - wxString filesToDelete = FreeFileSync::deleteFromGridAndHDPreview(mainGrid, - rowsToDeleteOnLeft, - rowsToDeleteOnRight, + assert(m_folderCmp.size() == rowsToDeleteOnLeft.size()); + assert(m_folderCmp.size() == rowsToDeleteOnRight.size()); + + wxString filesToDelete; + for (FolderComparison::const_iterator j = m_folderCmp.begin(); j != m_folderCmp.end(); ++j) + { + const FileComparison& fileCmp = j->fileCmp; + + const int pairIndex = j - m_folderCmp.begin(); + if ( pairIndex < int(rowsToDeleteOnLeft.size()) && //just to be sure + pairIndex < int(rowsToDeleteOnRight.size())) + { + filesToDelete += FreeFileSync::deleteFromGridAndHDPreview(fileCmp, + rowsToDeleteOnLeft[pairIndex], + rowsToDeleteOnRight[pairIndex], m_checkBoxDeleteBothSides->GetValue()); + } + } m_textCtrlMessage->SetValue(filesToDelete); Layout(); @@ -262,6 +284,7 @@ ErrorDlg::ErrorDlg(wxWindow* parentWindow, const int activeButtons, const wxStri { m_bitmap10->SetBitmap(*globalResource.bitmapError); m_textCtrl8->SetValue(messageText); + m_checkBoxIgnoreErrors->SetValue(ignoreNextErrors); if (~activeButtons & BUTTON_IGNORE) { @@ -322,6 +345,7 @@ WarningDlg::WarningDlg(wxWindow* parentWindow, int activeButtons, const wxStrin { m_bitmap10->SetBitmap(*globalResource.bitmapWarning); m_textCtrl8->SetValue(messageText); + m_checkBoxDontShowAgain->SetValue(dontShowAgain); if (~activeButtons & BUTTON_IGNORE) { @@ -333,7 +357,7 @@ WarningDlg::WarningDlg(wxWindow* parentWindow, int activeButtons, const wxStrin m_buttonAbort->Hide(); //set button focus precedence - else if (activeButtons & BUTTON_IGNORE) + if (activeButtons & BUTTON_IGNORE) m_buttonIgnore->SetFocus(); else if (activeButtons & BUTTON_ABORT) m_buttonAbort->SetFocus(); @@ -363,6 +387,70 @@ void WarningDlg::OnAbort(wxCommandEvent& event) } //######################################################################################## + + +QuestionDlg::QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxString messageText, bool& dontShowDlgAgain) : + QuestionDlgGenerated(parentWindow), + dontShowAgain(dontShowDlgAgain) +{ + m_bitmap10->SetBitmap(*globalResource.bitmapQuestion); + m_textCtrl8->SetValue(messageText); + m_checkBoxDontAskAgain->SetValue(dontShowAgain); + + if (~activeButtons & BUTTON_YES) + m_buttonYes->Hide(); + + if (~activeButtons & BUTTON_NO) + { + m_buttonNo->Hide(); + m_checkBoxDontAskAgain->Hide(); + } + + if (~activeButtons & BUTTON_CANCEL) + m_buttonCancel->Hide(); + + //set button focus precedence + if (activeButtons & BUTTON_YES) + m_buttonYes->SetFocus(); + else if (activeButtons & BUTTON_CANCEL) + m_buttonCancel->SetFocus(); + else if (activeButtons & BUTTON_NO) + m_buttonNo->SetFocus(); +} + + +QuestionDlg::~QuestionDlg() {} + + +void QuestionDlg::OnClose(wxCloseEvent& event) +{ + dontShowAgain = m_checkBoxDontAskAgain->GetValue(); + EndModal(BUTTON_CANCEL); +} + + +void QuestionDlg::OnCancel(wxCommandEvent& event) +{ + dontShowAgain = m_checkBoxDontAskAgain->GetValue(); + EndModal(BUTTON_CANCEL); +} + + +void QuestionDlg::OnYes(wxCommandEvent& event) +{ + dontShowAgain = m_checkBoxDontAskAgain->GetValue(); + EndModal(BUTTON_YES); +} + +void QuestionDlg::OnNo(wxCommandEvent& event) +{ + dontShowAgain = m_checkBoxDontAskAgain->GetValue(); + EndModal(BUTTON_NO); +} + +//######################################################################################## + + CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes& attr) : CustomizeColsDlgGenerated(window), output(attr) @@ -376,7 +464,7 @@ CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes for (xmlAccess::ColumnAttributes::const_iterator i = columnSettings.begin(); i != columnSettings.end(); ++i) //love these iterators! { - m_checkListColumns->Append(CustomGrid::getTypeName(i->type)); + m_checkListColumns->Append(CustomGridRim::getTypeName(i->type)); m_checkListColumns->Check(i - columnSettings.begin(), i->visible); } @@ -392,7 +480,7 @@ void CustomizeColsDlg::OnOkay(wxCommandEvent& event) const wxString label = m_checkListColumns->GetString(i); for (xmlAccess::ColumnAttributes::iterator j = output.begin(); j != output.end(); ++j) { - if (CustomGrid::getTypeName(j->type) == label) //not nice but short and no performance issue + if (CustomGridRim::getTypeName(j->type) == label) //not nice but short and no performance issue { j->position = i; j->visible = m_checkListColumns->IsChecked(i);; @@ -407,12 +495,12 @@ void CustomizeColsDlg::OnOkay(wxCommandEvent& event) void CustomizeColsDlg::OnDefault(wxCommandEvent& event) { - xmlAccess::ColumnAttributes defaultColumnAttr = CustomGrid::getDefaultColumnAttributes(); + xmlAccess::ColumnAttributes defaultColumnAttr = CustomGridRim::getDefaultColumnAttributes(); m_checkListColumns->Clear(); for (xmlAccess::ColumnAttributes::const_iterator i = defaultColumnAttr.begin(); i != defaultColumnAttr.end(); ++i) { - m_checkListColumns->Append(CustomGrid::getTypeName(i->type)); + m_checkListColumns->Append(CustomGridRim::getTypeName(i->type)); m_checkListColumns->Check(i - defaultColumnAttr.begin(), i->visible); } } @@ -521,96 +609,166 @@ void GlobalSettingsDlg::OnClose(wxCloseEvent& event) //######################################################################################## -/* -class for calculation of remaining time: ----------------------------------------- -"filesize |-> time" is an affine linear function f(x) = z_1 + z_2 x -For given n measurements, sizes x_0, ..., x_n and times f_0, ..., f_n, the function f (as a polynom of degree 1) can be lineary approximated by +CompareStatus::CompareStatus(wxWindow* parentWindow) : + CompareStatusGenerated(parentWindow), + scannedObjects(0), + totalObjects(0), + totalData(0), + currentObjects(0), + currentData(0), + scalingFactor(0), + statistics(NULL), + lastStatCallSpeed(-1000000), //some big number + lastStatCallRemTime(-1000000) +{ + init(); +} -z_1 = (r - s * q / p) / ((n + 1) - s * s / p) -z_2 = (q - s * z_1) / p = (r - (n + 1) z_1) / s -with -p := x_0^2 + ... + x_n^2 -q := f_0 x_0 + ... + f_n x_n -r := f_0 + ... + f_n -s := x_0 + ... + x_n +void CompareStatus::init() +{ + //initialize gauge + m_gauge2->SetRange(50000); + m_gauge2->SetValue(0); -=> the time to process N files with amount of data D is: N * z_1 + D * z_2 + //initially hide status that's relevant for comparing bytewise only + bSizer42->Hide(sbSizer13); + m_gauge2->Hide(); + bSizer42->Layout(); -Problem: --------- -Times f_0, ..., f_n can be very small so that precision of the PC clock is poor. -=> Times have to be accumulated to enhance precision: -Copying of m files with sizes x_i and times f_i (i = 1, ..., m) takes sum_i f(x_i) := m * z_1 + z_2 * sum x_i = sum f_i -With X defined as the accumulated sizes and F the accumulated times this gives: (in theory...) -m * z_1 + z_2 * X = F <=> -z_1 + z_2 * X / m = F / m + scannedObjects = 0; -=> we optain a new (artificial) measurement with size X / m and time F / m to be used in the linear approximation above + totalObjects = 0; + totalData = 0; + currentObjects = 0; + currentData = 0; + scalingFactor = 0; + statistics.reset(); + + timeElapsed.Start(); //measure total time + + updateStatusPanelNow(); +} -RemainingTime::RemainingTime() : n(0), m(0), X(0), F(0), p(0), q(0), r(0), s(0), z_1(0), z_2(0), lastExec(0) {} -RemainingTime::~RemainingTime() +void CompareStatus::switchToCompareBytewise(int totalObjectsToProcess, wxLongLong totalDataToProcess) { - ofstream output("test.txt"); - for (unsigned i = 0; i < x.size(); ++i) - { - output<<x[i]<<" "<<f[i]<<'\n'; - } - output<<'\n'<<z_1<<" "<<z_2<<'\n'; - output.close(); + currentData = 0; + totalData = totalDataToProcess; + + currentObjects = 0; + totalObjects = totalObjectsToProcess; + + if (totalData != 0) + scalingFactor = 50000 / totalData.ToDouble(); //let's normalize to 50000 + else + scalingFactor = 0; + + //set new statistics handler: 10 seconds "window" for remaining time, 5 seconds for speed + statistics.reset(new Statistics(totalObjectsToProcess, totalDataToProcess.ToDouble(), 10000, 5000)); + lastStatCallSpeed = -1000000; //some big number + lastStatCallRemTime = -1000000; + + //show status for comparing bytewise + bSizer42->Show(sbSizer13); + m_gauge2->Show(); + bSizer42->Layout(); } -wxLongLong RemainingTime::getRemainingTime(double processedDataSinceLastCall, int remainingFiles, double remainingData) //returns the remaining time in seconds +void CompareStatus::incScannedObjects_NoUpdate(int number) { - wxLongLong newExec = wxGetLocalTimeMillis(); + scannedObjects += number; +} - if (lastExec != 0) - { - X+= processedDataSinceLastCall; - F = (newExec - lastExec).ToDouble(); - ++m; - if (F > 1000) //add new measurement only if F is accumulated to a certain degree - { - lastExec = newExec; - ++n; +void CompareStatus::incProcessedCmpData_NoUpdate(int objectsProcessed, wxLongLong dataProcessed) +{ + currentData += dataProcessed; + currentObjects += objectsProcessed; +} + + +void CompareStatus::setStatusText_NoUpdate(const Zstring& text) +{ + currentStatusText = text; +} - double x_i = X / m; - double f_i = F / m; - X = 0; - F = 0; - m = 0; - x.push_back(x_i); - f.push_back(f_i); +void CompareStatus::updateStatusPanelNow() +{ + //static RetrieveStatistics statistic; + //statistic.writeEntry(currentData, currentObjects); + + bool screenChanged = false; //avoid screen flicker by calling layout() only if necessary + + //remove linebreaks from currentStatusText + wxString formattedStatusText = currentStatusText.c_str(); + for (wxString::iterator i = formattedStatusText.begin(); i != formattedStatusText.end(); ++i) + if (*i == wxChar('\n')) + *i = wxChar(' '); + + //status texts + if (m_textCtrlFilename->GetValue() != formattedStatusText && (screenChanged = true)) //avoid screen flicker + m_textCtrlFilename->SetValue(formattedStatusText); + + //nr of scanned objects + const wxString scannedObjTmp = globalFunctions::numberToWxString(scannedObjects); + if (m_staticTextScanned->GetLabel() != scannedObjTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextScanned->SetLabel(scannedObjTmp); - p+= x_i * x_i; - q+= f_i * x_i; - r+= f_i; - s+= x_i; + //progress indicator for "compare file content" + m_gauge2->SetValue(int(currentData.ToDouble() * scalingFactor)); + + //remaining files left for file comparison + const wxString filesToCompareTmp = globalFunctions::numberToWxString(totalObjects - currentObjects); + if (m_staticTextFilesRemaining->GetLabel() != filesToCompareTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextFilesRemaining->SetLabel(filesToCompareTmp); - if (p != 0) + //remaining bytes left for file comparison + const wxString remainingBytesTmp = FreeFileSync::formatFilesizeToShortString(totalData - currentData); + if (m_staticTextDataRemaining->GetLabel() != remainingBytesTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextDataRemaining->SetLabel(remainingBytesTmp); + + if (statistics.get()) + { + if (timeElapsed.Time() - lastStatCallSpeed >= 500) //call method every 500 ms + { + lastStatCallSpeed = timeElapsed.Time(); + + statistics->addMeasurement(currentObjects, currentData.ToDouble()); + + //current speed + const wxString speedTmp = statistics->getBytesPerSecond(); + if (m_staticTextSpeed->GetLabel() != speedTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextSpeed->SetLabel(speedTmp); + + if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //call method every two seconds only { - double tmp = (n - s * s / p); - if (tmp != 0 && s != 0) - { //recalculate coefficients for affine-linear function - z_1 = (r - s * q / p) / tmp; - z_2 = (r - n * z_1) / s; //not (n + 1) here, since n already is the number of measurements - } + lastStatCallRemTime = timeElapsed.Time(); + + //remaining time + const wxString timeRemainingTmp = statistics->getRemainingTime(); + if (m_staticTextTimeRemaining->GetLabel() != timeRemainingTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextTimeRemaining->SetLabel(timeRemainingTmp); } } - - return int(remainingFiles * z_1 + remainingData * z_2); } - //else - lastExec = newExec; - return 0; -}*/ + + //time elapsed + const wxString timeElapsedTmp = (wxTimeSpan::Milliseconds(timeElapsed.Time())).Format(); + if (m_staticTextTimeElapsed->GetLabel() != timeElapsedTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextTimeElapsed->SetLabel(timeElapsedTmp); + + //do the ui update + if (screenChanged) + bSizer42->Layout(); + + updateUiNow(); +} + //######################################################################################## @@ -619,13 +777,16 @@ SyncStatus::SyncStatus(StatusHandler* updater, wxWindow* parentWindow) : currentStatusHandler(updater), windowToDis(parentWindow), currentProcessIsRunning(true), + totalObjects(0), totalData(0), + currentObjects(0), currentData(0), scalingFactor(0), - currentObjects(0), - totalObjects(0), processPaused(false), - currentStatus(SyncStatus::ABORTED) + currentStatus(SyncStatus::ABORTED), + statistics(NULL), + lastStatCallSpeed(-1000000), //some big number + lastStatCallRemTime(-1000000) { m_animationControl1->SetAnimation(*globalResource.animationSync); m_animationControl1->Play(); @@ -654,7 +815,7 @@ SyncStatus::~SyncStatus() } -void SyncStatus::resetGauge(int totalObjectsToProcess, double totalDataToProcess) +void SyncStatus::resetGauge(int totalObjectsToProcess, wxLongLong totalDataToProcess) { currentData = 0; totalData = totalDataToProcess; @@ -663,16 +824,21 @@ void SyncStatus::resetGauge(int totalObjectsToProcess, double totalDataToProcess totalObjects = totalObjectsToProcess; if (totalData != 0) - scalingFactor = 50000 / totalData; //let's normalize to 50000 + scalingFactor = 50000 / totalData.ToDouble(); //let's normalize to 50000 else scalingFactor = 0; + + //set new statistics handler: 10 seconds "window" for remaining time, 5 seconds for speed + statistics.reset(new Statistics(totalObjectsToProcess, totalDataToProcess.ToDouble(), 10000, 5000)); + lastStatCallSpeed = -1000000; //some big number + lastStatCallRemTime = -1000000; } -void SyncStatus::incProgressIndicator_NoUpdate(int objectsProcessed, double dataProcessed) +void SyncStatus::incProgressIndicator_NoUpdate(int objectsProcessed, wxLongLong dataProcessed) { - currentData+= dataProcessed; - currentObjects+= objectsProcessed; + currentData += dataProcessed; + currentObjects += objectsProcessed; } @@ -684,10 +850,16 @@ void SyncStatus::setStatusText_NoUpdate(const Zstring& text) void SyncStatus::updateStatusDialogNow() { + + //static RetrieveStatistics statistic; + //statistic.writeEntry(currentData, currentObjects); + + + bool screenChanged = false; //avoid screen flicker by calling layout() only if necessary //progress indicator - m_gauge1->SetValue(globalFunctions::round(currentData * scalingFactor)); + m_gauge1->SetValue(globalFunctions::round(currentData.ToDouble() * scalingFactor)); //status text if (m_textCtrlInfo->GetValue() != wxString(currentStatusText.c_str()) && (screenChanged = true)) //avoid screen flicker @@ -703,11 +875,37 @@ void SyncStatus::updateStatusDialogNow() if (m_staticTextDataRemaining->GetLabel() != remainingBytesTmp && (screenChanged = true)) //avoid screen flicker m_staticTextDataRemaining->SetLabel(remainingBytesTmp); + if (statistics.get()) + { + if (timeElapsed.Time() - lastStatCallSpeed >= 500) //call method every 500 ms + { + lastStatCallSpeed = timeElapsed.Time(); + + statistics->addMeasurement(currentObjects, currentData.ToDouble()); + + //current speed + const wxString speedTmp = statistics->getBytesPerSecond(); + if (m_staticTextSpeed->GetLabel() != speedTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextSpeed->SetLabel(speedTmp); + + if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //call method every two seconds only + { + lastStatCallRemTime = timeElapsed.Time(); + + //remaining time + const wxString timeRemainingTmp = statistics->getRemainingTime(); + if (m_staticTextTimeRemaining->GetLabel() != timeRemainingTmp && (screenChanged = true)) //avoid screen flicker + m_staticTextTimeRemaining->SetLabel(timeRemainingTmp); + } + } + } + //time elapsed const wxString timeElapsedTmp = (wxTimeSpan::Milliseconds(timeElapsed.Time())).Format(); if (m_staticTextTimeElapsed->GetLabel() != timeElapsedTmp && (screenChanged = true)) //avoid screen flicker m_staticTextTimeElapsed->SetLabel(timeElapsedTmp); + //do the ui update if (screenChanged) { @@ -746,7 +944,7 @@ void SyncStatus::setCurrentStatus(SyncStatusID id) case PAUSE: m_bitmapStatus->SetBitmap(*globalResource.bitmapStatusPause); - m_staticTextStatus->SetLabel(_("Pause")); + m_staticTextStatus->SetLabel(_("Paused")); break; case SCANNING: @@ -772,7 +970,7 @@ void SyncStatus::setCurrentStatus(SyncStatusID id) void SyncStatus::processHasFinished(SyncStatusID id) //essential to call this in StatusHandler derived class destructor { //at the LATEST(!) to prevent access to currentStatusHandler - currentProcessIsRunning = false; //enable okay and close events; may be set ONLY in this method + currentProcessIsRunning = false; //enable okay and close events; may be set in this method ONLY setCurrentStatus(id); @@ -784,9 +982,11 @@ void SyncStatus::processHasFinished(SyncStatusID id) //essential to call this in m_buttonOK->SetFocus(); m_animationControl1->Stop(); - //m_animationControl1->SetInactiveBitmap(*globalResource.bitmapFinished); m_animationControl1->Hide(); + bSizerSpeed->Show(false); + bSizerRemTime->Show(false); + updateStatusDialogNow(); //keep this sequence to avoid display distortion, if e.g. only 1 item is sync'ed Layout(); // } @@ -808,7 +1008,11 @@ void SyncStatus::OnPause(wxCommandEvent& event) processPaused = false; m_buttonPause->SetLabel(_("Pause")); m_animationControl1->Play(); + + //resume timers timeElapsed.Resume(); + if (statistics.get()) + statistics->resumeTimer(); } else { @@ -818,7 +1022,11 @@ void SyncStatus::OnPause(wxCommandEvent& event) processPaused = true; m_buttonPause->SetLabel(_("Continue")); m_animationControl1->Stop(); + + //pause timers timeElapsed.Pause(); + if (statistics.get()) + statistics->pauseTimer(); } } @@ -849,143 +1057,3 @@ void SyncStatus::OnClose(wxCloseEvent& event) else Destroy(); } -//######################################################################################## - - -CompareStatus::CompareStatus(wxWindow* parentWindow) : - CompareStatusGenerated(parentWindow), - scannedObjects(0), - scalingFactorCmp(0), - totalCmpData(0), - processedCmpData(0), - totalCmpObjects(0), - processedCmpObjects(0) - /*timeRemaining(0), - timeRemainingTimeStamp(0)*/ -{ - init(); -} - - -CompareStatus::~CompareStatus() {} - - -void CompareStatus::init() -{ - //initialize gauge - m_gauge2->SetRange(50000); - m_gauge2->SetValue(0); - - //initially hide status that's relevant for comparing bytewise only - bSizer42->Hide(sbSizer13); - m_gauge2->Hide(); - bSizer42->Layout(); - - scannedObjects = 0; - scalingFactorCmp = 0; - - totalCmpData = 0; - processedCmpData = 0; - totalCmpObjects = 0; - processedCmpObjects = 0; - - timeElapsed.Start(); //measure total time - - updateStatusPanelNow(); -} - - -void CompareStatus::switchToCompareBytewise(int totalCmpObjectsToProcess, double totalCmpDataToProcess) -{ - processedCmpData = 0; - totalCmpData = totalCmpDataToProcess; - - processedCmpObjects = 0; - totalCmpObjects = totalCmpObjectsToProcess; - - if (totalCmpData != 0) - scalingFactorCmp = 50000 / totalCmpData; //let's normalize to 50000 - else - scalingFactorCmp = 0; - - //show status for comparing bytewise - bSizer42->Show(sbSizer13); - m_gauge2->Show(); - bSizer42->Layout(); -} - - -void CompareStatus::incScannedObjects_NoUpdate(int number) -{ - scannedObjects+= number; -} - - -void CompareStatus::incProcessedCmpData_NoUpdate(int objectsProcessed, double dataProcessed) -{ - processedCmpData+= dataProcessed; - processedCmpObjects+= objectsProcessed; - - /* timeRemaining = calcTimeLeft.getRemainingTime(dataProcessed, totalCmpObjects - processedCmpObjects, totalCmpData - processedCmpData); - timeRemainingTimeStamp = wxGetLocalTimeMillis();*/ -} - - -void CompareStatus::setStatusText_NoUpdate(const Zstring& text) -{ - currentStatusText = text; -} - - -void CompareStatus::updateStatusPanelNow() -{ - bool screenChanged = false; //avoid screen flicker by calling layout() only if necessary - - //remove linebreaks from currentStatusText - wxString formattedStatusText = currentStatusText.c_str(); - for (wxString::iterator i = formattedStatusText.begin(); i != formattedStatusText.end(); ++i) - if (*i == wxChar('\n')) - *i = wxChar(' '); - - //status texts - if (m_textCtrlFilename->GetValue() != formattedStatusText && (screenChanged = true)) //avoid screen flicker - m_textCtrlFilename->SetValue(formattedStatusText); - - //nr of scanned objects - const wxString scannedObjTmp = globalFunctions::numberToWxString(scannedObjects); - if (m_staticTextScanned->GetLabel() != scannedObjTmp && (screenChanged = true)) //avoid screen flicker - m_staticTextScanned->SetLabel(scannedObjTmp); - - //progress indicator for "compare file content" - m_gauge2->SetValue(int(processedCmpData * scalingFactorCmp)); - - //remaining files left for file comparison - const wxString filesToCompareTmp = globalFunctions::numberToWxString(totalCmpObjects - processedCmpObjects); - if (m_staticTextFilesToCompare->GetLabel() != filesToCompareTmp && (screenChanged = true)) //avoid screen flicker - m_staticTextFilesToCompare->SetLabel(filesToCompareTmp); - - //remaining bytes left for file comparison - const wxString remainingBytesTmp = FreeFileSync::formatFilesizeToShortString(totalCmpData - processedCmpData); - if (m_staticTextDataToCompare->GetLabel() != remainingBytesTmp && (screenChanged = true)) //avoid screen flicker - m_staticTextDataToCompare->SetLabel(remainingBytesTmp); - - /* - //remaining time in seconds - if (timeRemaining != 0) - { - int time = ((timeRemaining - (wxGetLocalTimeMillis() - timeRemainingTimeStamp)) / 1000).GetLo(); - m_staticTextRemainingTime->SetLabel(numberToWxString(time) + " s"); - } - */ - - //time elapsed - const wxString timeElapsedTmp = (wxTimeSpan::Milliseconds(timeElapsed.Time())).Format(); - if (m_staticTextTimeElapsed->GetLabel() != timeElapsedTmp && (screenChanged = true)) //avoid screen flicker - m_staticTextTimeElapsed->SetLabel(timeElapsedTmp); - - //do the ui update - if (screenChanged) - bSizer42->Layout(); - - updateUiNow(); -} diff --git a/ui/SmallDialogs.h b/ui/SmallDialogs.h index 0e310d94..a2d2c752 100644 --- a/ui/SmallDialogs.h +++ b/ui/SmallDialogs.h @@ -1,17 +1,21 @@ #ifndef SMALLDIALOGS_H_INCLUDED #define SMALLDIALOGS_H_INCLUDED -#include "../FreeFileSync.h" +#include "../structures.h" #include "../library/statusHandler.h" #include "../library/processXml.h" #include "guiGenerated.h" #include <wx/stopwatch.h> +#include <memory> + +class Statistics; + class AboutDlg : public AboutDlgGenerated { public: AboutDlg(wxWindow* window); - ~AboutDlg(); + ~AboutDlg() {} private: void OnClose(wxCloseEvent& event); @@ -35,7 +39,7 @@ class FilterDlg : public FilterDlgGenerated { public: FilterDlg(wxWindow* window, wxString& filterIncl, wxString& filterExcl); - ~FilterDlg(); + ~FilterDlg() {} enum { @@ -58,9 +62,9 @@ class DeleteDialog : public DeleteDlgGenerated { public: DeleteDialog(wxWindow* main, - const FileCompareResult& grid, - const std::set<int>& rowsOnLeft, - const std::set<int>& rowsOnRight, + const FreeFileSync::FolderComparison& folderCmp, + const FreeFileSync::FolderCompRef& rowsOnLeft, + const FreeFileSync::FolderCompRef& rowsOnRight, bool& deleteOnBothSides, bool& useRecycleBin); @@ -81,9 +85,9 @@ private: void updateTexts(); - const FileCompareResult& mainGrid; - const std::set<int>& rowsToDeleteOnLeft; - const std::set<int>& rowsToDeleteOnRight; + const FreeFileSync::FolderComparison& m_folderCmp; + const FreeFileSync::FolderCompRef& rowsToDeleteOnLeft; + const FreeFileSync::FolderCompRef& rowsToDeleteOnRight; bool& m_deleteOnBothSides; bool& m_useRecycleBin; }; @@ -135,6 +139,29 @@ private: }; +class QuestionDlg : public QuestionDlgGenerated +{ +public: + QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxString messageText, bool& dontShowAgain); + ~QuestionDlg(); + + enum + { + BUTTON_YES = 1, + BUTTON_NO = 2, + BUTTON_CANCEL = 4 + }; + +private: + void OnClose(wxCloseEvent& event); + void OnCancel(wxCommandEvent& event); + void OnYes(wxCommandEvent& event); + void OnNo(wxCommandEvent& event); + + bool& dontShowAgain; +}; + + class CustomizeColsDlg : public CustomizeColsDlgGenerated { public: @@ -181,10 +208,44 @@ private: }; +class CompareStatus : public CompareStatusGenerated +{ +public: + CompareStatus(wxWindow* parentWindow); + + void init(); //initialize all status values + + void switchToCompareBytewise(int totalObjectsToProcess, wxLongLong totalDataToProcess); + void incScannedObjects_NoUpdate(int number); + void incProcessedCmpData_NoUpdate(int objectsProcessed, wxLongLong dataProcessed); + void setStatusText_NoUpdate(const Zstring& text); + void updateStatusPanelNow(); + +private: + //status variables + unsigned int scannedObjects; + Zstring currentStatusText; + + wxStopWatch timeElapsed; + + //gauge variables + int totalObjects; + wxLongLong totalData; //each data element represents one byte for proper progress indicator scaling + int currentObjects; //each object represents a file or directory processed + wxLongLong currentData; + double scalingFactor; //nr of elements has to be normalized to smaller nr. because of range of int limitation + + //remaining time + std::auto_ptr<Statistics> statistics; + long lastStatCallSpeed; //used for calculating intervals between statistics update + long lastStatCallRemTime; // +}; + + class SyncStatus : public SyncStatusDlgGenerated { public: - SyncStatus(StatusHandler* updater, wxWindow* parentWindow = NULL); + SyncStatus(StatusHandler* updater, wxWindow* parentWindow); ~SyncStatus(); enum SyncStatusID @@ -198,8 +259,8 @@ public: SYNCHRONIZING }; - void resetGauge(int totalObjectsToProcess, double totalDataToProcess); - void incProgressIndicator_NoUpdate(int objectsProcessed, double dataProcessed); + void resetGauge(int totalObjectsToProcess, wxLongLong totalDataToProcess); + void incProgressIndicator_NoUpdate(int objectsProcessed, wxLongLong dataProcessed); void setStatusText_NoUpdate(const Zstring& text); void updateStatusDialogNow(); @@ -219,77 +280,20 @@ private: bool currentProcessIsRunning; //gauge variables - double totalData; //each data element represents one byte for proper progress indicator scaling - double currentData; - double scalingFactor; //nr of elements has to be normalized to smaller nr. because of range of int limitation - int currentObjects; //each object represents a file or directory processed - int totalObjects; + int totalObjects; + wxLongLong totalData; + int currentObjects; //each object represents a file or directory processed + wxLongLong currentData; //each data element represents one byte for proper progress indicator scaling + double scalingFactor; //nr of elements has to be normalized to smaller nr. because of range of int limitation Zstring currentStatusText; bool processPaused; SyncStatusID currentStatus; -}; -/* -class RemainingTime -{ -public: - RemainingTime(); - ~RemainingTime(); - wxLongLong getRemainingTime(double processedDataSinceLastCall, int remainingFiles, double remainingData); //returns the remaining time in milliseconds - -private: - double n; - double m; - double X; - double F; - double p; - double q; - double r; - double s; - double z_1; - double z_2; - wxLongLong lastExec; - - vector<double> x; //dummy: DELETE asap! - vector<double> f; + //remaining time + std::auto_ptr<Statistics> statistics; + long lastStatCallSpeed; //used for calculating intervals between statistics update + long lastStatCallRemTime; // }; -*/ - -class CompareStatus : public CompareStatusGenerated -{ -public: - CompareStatus(wxWindow* parentWindow); - ~CompareStatus(); - - void init(); //initialize all status values - - void switchToCompareBytewise(int totalCmpObjectsToProcess, double totalCmpDataToProcess); - void incScannedObjects_NoUpdate(int number); - void incProcessedCmpData_NoUpdate(int objectsProcessed, double dataProcessed); - void setStatusText_NoUpdate(const Zstring& text); - void updateStatusPanelNow(); - -private: - //status variables - unsigned int scannedObjects; - Zstring currentStatusText; - - wxStopWatch timeElapsed; - - //gauge variables - double scalingFactorCmp; //nr of elements has to be normalized to smaller nr. because of range of int limitation - double totalCmpData; //each data element represents one byte for proper progress indicator scaling - double processedCmpData; - int totalCmpObjects; - int processedCmpObjects; //each object represents a file or directory processed - /* - //remaining time - RemainingTime calcTimeLeft; - wxLongLong timeRemaining; //time in milliseconds - wxLongLong timeRemainingTimeStamp; //time in milliseconds - */ -}; - #endif // SMALLDIALOGS_H_INCLUDED diff --git a/ui/SyncDialog.cpp b/ui/SyncDialog.cpp index fe36d751..3c684700 100644 --- a/ui/SyncDialog.cpp +++ b/ui/SyncDialog.cpp @@ -8,15 +8,18 @@ #include "../synchronization.h" #include "../algorithm.h" #include <wx/dnd.h> +#include "dragAndDrop.h" + +using namespace FreeFileSync; SyncDialog::SyncDialog(wxWindow* window, - const FileCompareResult& gridDataRef, + const FolderComparison& folderCmpRef, MainConfiguration& config, bool& ignoreErrors, bool synchronizationEnabled) : SyncDlgGenerated(window), - gridData(gridDataRef), + folderCmp(folderCmpRef), cfg(config), m_ignoreErrors(ignoreErrors) { @@ -180,16 +183,15 @@ void SyncDialog::updateConfigIcons(wxBitmapButton* button1, void SyncDialog::adjustToolTips(wxStaticBitmap* bitmap, const CompareVariant var) { //set tooltip for ambivalent category "different" - if (var == CMP_BY_TIME_SIZE) + switch (var) { + case CMP_BY_TIME_SIZE: bitmap->SetToolTip(_("Files that exist on both sides, have same date but different filesizes")); - } - else if (var == CMP_BY_CONTENT) - { + break; + case CMP_BY_CONTENT: bitmap->SetToolTip(_("Files that exist on both sides and have different content")); + break; } - else - assert(false); } @@ -199,18 +201,18 @@ void SyncDialog::calculatePreview() int objectsToCreate = 0; int objectsToOverwrite = 0; int objectsToDelete = 0; - double dataToProcess = 0; - FreeFileSync::calcTotalBytesToSync(gridData, + wxULongLong dataToProcess; + FreeFileSync::calcTotalBytesToSync(folderCmp, localSyncConfiguration, objectsToCreate, objectsToOverwrite, objectsToDelete, dataToProcess); - wxString toCreate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToCreate)); - wxString toUpdate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToOverwrite)); - wxString toDelete = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToDelete)); - wxString data = FreeFileSync::formatFilesizeToShortString(dataToProcess); + const wxString toCreate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToCreate)); + const wxString toUpdate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToOverwrite)); + const wxString toDelete = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToDelete)); + const wxString data = FreeFileSync::formatFilesizeToShortString(dataToProcess); m_textCtrlCreate->SetValue(toCreate); m_textCtrlUpdate->SetValue(toUpdate); @@ -377,6 +379,23 @@ void SyncDialog::OnDifferent( wxCommandEvent& event ) //################################################################################################################################### +class BatchFolderPairPanel : public BatchFolderPairGenerated +{ +public: + BatchFolderPairPanel(wxWindow* parent) : + BatchFolderPairGenerated(parent), + dragDropOnLeft(m_panelLeft, m_dirPickerLeft, m_directoryLeft), + dragDropOnRight(m_panelRight, m_dirPickerRight, m_directoryRight) {} + +private: + //support for drag and drop + DragDropOnDlg dragDropOnLeft; + DragDropOnDlg dragDropOnRight; +}; + +//################################################################################################################################### + + class BatchFileDropEvent : public wxFileDropTarget { public: @@ -394,6 +413,12 @@ public: //test if ffs batch file has been dropped if (fileType == xmlAccess::XML_BATCH_CONFIG) batchDlg->loadBatchFile(droppedFileName); + else + { + wxString errorMessage = _("%x is not a valid FreeFileSync batch file!"); + errorMessage.Replace(wxT("%x"), wxString(wxT("\"")) + droppedFileName + wxT("\""), false); + wxMessageBox(errorMessage, _("Error"), wxOK | wxICON_ERROR); + } } return false; } @@ -421,9 +446,11 @@ BatchDialog::BatchDialog(wxWindow* window, const wxString& filename) : void BatchDialog::init() { - //prepare drag & drop + //prepare drag & drop for loading of *.ffs_batch files SetDropTarget(new BatchFileDropEvent(this)); + dragDropOnLogfileDir.reset(new DragDropOnDlg(m_panelLogging, m_dirPickerLogfileDir, m_textCtrlLogfileDir)); + //set icons for this dialog m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnly); m_bitmap14->SetBitmap(*globalResource.bitmapRightOnly); @@ -436,27 +463,6 @@ void BatchDialog::init() } -void BatchDialog::updateFilterButton() -{ - if (filterIsActive) - { - m_bpButtonFilter->SetBitmapLabel(*globalResource.bitmapFilterOn); - m_bpButtonFilter->SetToolTip(_("Filter active: Press again to deactivate")); - - m_textCtrlInclude->Enable(); - m_textCtrlExclude->Enable(); - } - else - { - m_bpButtonFilter->SetBitmapLabel(*globalResource.bitmapFilterOff); - m_bpButtonFilter->SetToolTip(_("Press button to activate filter")); - - m_textCtrlInclude->Disable(); - m_textCtrlExclude->Disable(); - } -} - - xmlAccess::OnError BatchDialog::getSelectionHandleError() { switch (m_choiceHandleError->GetSelection()) @@ -562,10 +568,52 @@ void BatchDialog::OnDifferent(wxCommandEvent& event) } -void BatchDialog::OnFilterButton(wxCommandEvent& event) +void BatchDialog::OnCheckFilter(wxCommandEvent& event) +{ + updateVisibleTabs(); +} + + +void BatchDialog::OnCheckLogging(wxCommandEvent& event) +{ + updateVisibleTabs(); +} + + +void BatchDialog::updateVisibleTabs() { - filterIsActive = !filterIsActive; - updateFilterButton(); + showNotebookpage(m_panelFilter, _("Filter"), m_checkBoxFilter->GetValue()); + showNotebookpage(m_panelLogging, _("Logging"), m_checkBoxSilent->GetValue()); +} + + +void BatchDialog::showNotebookpage(wxWindow* page, const wxString& pageName, bool show) +{ + int windowPosition = -1; + for (size_t i = 0; i < m_notebookSettings->GetPageCount(); ++i) + if ( static_cast<wxWindow*>(m_notebookSettings->GetPage(i)) == + static_cast<wxWindow*>(page)) + { + windowPosition = i; + break; + } + + if (show) + { + if (windowPosition == -1) + m_notebookSettings->AddPage(page, pageName, false); + } + else + { + if (windowPosition != -1) + { + //do not delete currently selected tab!! + if (m_notebookSettings->GetCurrentPage() == m_notebookSettings->GetPage(windowPosition)) + m_notebookSettings->ChangeSelection(0); + + m_notebookSettings->RemovePage(windowPosition); + } + } } @@ -615,26 +663,25 @@ void BatchDialog::OnCancel(wxCommandEvent& event) void BatchDialog::OnSaveBatchJob(wxCommandEvent& event) { //get a filename - wxString fileName = wxT("SyncJob.ffs_batch"); //proposal - - if (!proposedBatchFileName.empty()) - fileName = proposedBatchFileName; - - wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, fileName, wxString(_("FreeFileSync batch file")) + wxT(" (*.ffs_batch)|*.ffs_batch"), wxFD_SAVE); + const wxString defaultFileName = proposedBatchFileName.empty() ? wxT("SyncJob.ffs_batch") : proposedBatchFileName; + wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("FreeFileSync batch file")) + wxT(" (*.ffs_batch)|*.ffs_batch"), wxFD_SAVE); if (filePicker->ShowModal() == wxID_OK) { - fileName = filePicker->GetPath(); - if (FreeFileSync::fileExists(fileName.c_str())) + const wxString newFileName = filePicker->GetPath(); + if (FreeFileSync::fileExists(newFileName.c_str())) { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + fileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); + wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) + { + OnSaveBatchJob(event); //retry return; + } } //create batch file - if (saveBatchFile(fileName)) + if (saveBatchFile(newFileName)) EndModal(BATCH_FILE_SAVED); } } @@ -661,7 +708,7 @@ bool BatchDialog::saveBatchFile(const wxString& filename) return false; batchCfg.mainCfg.syncConfiguration = localSyncConfiguration; - batchCfg.mainCfg.filterIsActive = filterIsActive; + batchCfg.mainCfg.filterIsActive = m_checkBoxFilter->GetValue(); batchCfg.mainCfg.includeFilter = m_textCtrlInclude->GetValue(); batchCfg.mainCfg.excludeFilter = m_textCtrlExclude->GetValue(); batchCfg.mainCfg.useRecycleBin = m_checkBoxUseRecycler->GetValue(); @@ -678,6 +725,7 @@ bool BatchDialog::saveBatchFile(const wxString& filename) //load structure with batch settings "batchCfg" batchCfg.silent = m_checkBoxSilent->GetValue(); + batchCfg.logFileDirectory = m_textCtrlLogfileDir->GetValue(); //write config to XML try @@ -741,13 +789,12 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) //adjust toolTip SyncDialog::adjustToolTips(m_bitmap17, batchCfg.mainCfg.compareVar); - filterIsActive = batchCfg.mainCfg.filterIsActive; - updateFilterButton(); - + m_checkBoxFilter->SetValue(batchCfg.mainCfg.filterIsActive); m_textCtrlInclude->SetValue(batchCfg.mainCfg.includeFilter); m_textCtrlExclude->SetValue(batchCfg.mainCfg.excludeFilter); m_checkBoxSilent->SetValue(batchCfg.silent); + m_textCtrlLogfileDir->SetValue(batchCfg.logFileDirectory); //remove existing folder pairs localFolderPairs.clear(); @@ -757,7 +804,7 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) int scrWindowHeight = 0; for (std::vector<FolderPair>::const_iterator i = batchCfg.directoryPairs.begin(); i != batchCfg.directoryPairs.end(); ++i) { - BatchFolderPairGenerated* newPair = new BatchFolderPairGenerated(m_scrolledWindow6); + BatchFolderPairPanel* newPair = new BatchFolderPairPanel(m_scrolledWindow6); newPair->m_directoryLeft->SetValue(i->leftDirectory.c_str()); newPair->m_directoryRight->SetValue(i->rightDirectory.c_str()); @@ -771,10 +818,12 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) int pairCount = std::min(localFolderPairs.size(), size_t(3)); //up to 3 additional pairs shall be shown m_scrolledWindow6->SetMinSize(wxSize( -1, scrWindowHeight * pairCount)); - m_scrolledWindow6->Layout(); - //m_scrolledWindow6->Fit(); + updateVisibleTabs(); + + m_scrolledWindow6->Layout(); //needed + m_panelOverview->Layout(); //needed - Fit(); + Fit(); //needed Centre(); m_buttonSave->SetFocus(); } diff --git a/ui/SyncDialog.h b/ui/SyncDialog.h index 05a2d65b..2c705122 100644 --- a/ui/SyncDialog.h +++ b/ui/SyncDialog.h @@ -1,19 +1,26 @@ #ifndef SYNCDIALOG_H_INCLUDED #define SYNCDIALOG_H_INCLUDED -#include "../FreeFileSync.h" +#include "../structures.h" #include "guiGenerated.h" #include "../library/processXml.h" +#include <memory> -using namespace FreeFileSync; +class BatchFileDropEvent; +class BatchFolderPairPanel; + +namespace FreeFileSync +{ + class DragDropOnDlg; +} class SyncDialog: public SyncDlgGenerated { public: SyncDialog(wxWindow* window, - const FileCompareResult& gridDataRef, - MainConfiguration& config, + const FreeFileSync::FolderComparison& folderCmpRef, + FreeFileSync::MainConfiguration& config, bool& ignoreErrors, bool synchronizationEnabled); @@ -29,9 +36,9 @@ public: wxBitmapButton* button3, wxBitmapButton* button4, wxBitmapButton* button5, - const SyncConfiguration& syncConfig); + const FreeFileSync::SyncConfiguration& syncConfig); - static void adjustToolTips(wxStaticBitmap* bitmap, const CompareVariant var); + static void adjustToolTips(wxStaticBitmap* bitmap, const FreeFileSync::CompareVariant var); private: void calculatePreview(); @@ -54,16 +61,13 @@ private: void OnSelectRecycleBin(wxCommandEvent& event); //temporal copy of maindialog.cfg.syncConfiguration - SyncConfiguration localSyncConfiguration; - const FileCompareResult& gridData; - MainConfiguration& cfg; + FreeFileSync::SyncConfiguration localSyncConfiguration; + const FreeFileSync::FolderComparison& folderCmp; + FreeFileSync::MainConfiguration& cfg; bool& m_ignoreErrors; }; -class BatchFileDropEvent; - - class BatchDialog: public BatchDlgGenerated { friend class BatchFileDropEvent; @@ -89,16 +93,19 @@ private: void OnRightNewer( wxCommandEvent& event); void OnDifferent( wxCommandEvent& event); - void OnFilterButton( wxCommandEvent& event); + void OnCheckFilter( wxCommandEvent& event); + void OnCheckLogging( wxCommandEvent& event); void OnSelectRecycleBin(wxCommandEvent& event); void OnChangeCompareVar(wxCommandEvent& event); + void updateVisibleTabs(); + void showNotebookpage(wxWindow* page, const wxString& pageName, bool show); + void OnClose( wxCloseEvent& event); void OnCancel( wxCommandEvent& event); void OnSaveBatchJob( wxCommandEvent& event); void OnLoadBatchJob( wxCommandEvent& event); - void updateFilterButton(); xmlAccess::OnError getSelectionHandleError(); void setSelectionHandleError(const xmlAccess::OnError value); @@ -106,13 +113,14 @@ private: void loadBatchFile(const wxString& filename); void loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg); - SyncConfiguration localSyncConfiguration; - std::vector<BatchFolderPairGenerated*> localFolderPairs; - - bool filterIsActive; + FreeFileSync::SyncConfiguration localSyncConfiguration; + std::vector<BatchFolderPairPanel*> localFolderPairs; //used when saving batch file wxString proposedBatchFileName; + + //add drag & drop support when selecting logfile directory + std::auto_ptr<FreeFileSync::DragDropOnDlg> dragDropOnLogfileDir; }; #endif // SYNCDIALOG_H_INCLUDED diff --git a/ui/batchStatusHandler.cpp b/ui/batchStatusHandler.cpp new file mode 100644 index 00000000..462b1921 --- /dev/null +++ b/ui/batchStatusHandler.cpp @@ -0,0 +1,596 @@ +#include "batchStatusHandler.h" +#include "smallDialogs.h" +#include <wx/stopwatch.h> +#include <wx/taskbar.h> +#include "../algorithm.h" +#include <wx/ffile.h> +#include <wx/msgdlg.h> +#include "../library/globalFunctions.h" + + +class LogFile +{ +public: + LogFile(const wxString& logfileDirectory) + { + //create logfile directory + const Zstring logfileDir = logfileDirectory.empty() ? wxT("Logs") : logfileDirectory.c_str(); + if (!wxDirExists(logfileDir)) + try + { + FreeFileSync::createDirectory(logfileDir, Zstring(), false); + } + catch (FileError&) + { + readyToWrite = false; + return; + } + + //assemble logfile name + wxString logfileName = logfileDir.c_str(); + if (!FreeFileSync::endsWithPathSeparator(logfileName.c_str())) + logfileName += GlobalResources::FILE_NAME_SEPARATOR; + wxString timeNow = wxDateTime::Now().FormatISOTime(); + timeNow.Replace(wxT(":"), wxEmptyString); + logfileName += wxT("FFS_") + wxDateTime::Now().FormatISODate() + wxChar('_') + timeNow + wxT(".log"); + + + logFile.Open(logfileName.c_str(), wxT("w")); + readyToWrite = logFile.IsOpened(); + if (readyToWrite) + { + wxString headerLine = wxString(wxT("FreeFileSync - ")) + + _("Batch execution") + wxT(" (") + + _("Date") + wxT(": ") + wxDateTime::Now().FormatDate() + wxT(" ") + //"Date" is used at other places too + _("Time") + wxT(":") + wxT(" ") + wxDateTime::Now().FormatTime() + wxT(")"); + logFile.Write(headerLine + wxChar('\n')); + logFile.Write(wxString().Pad(headerLine.Len(), wxChar('-')) + wxChar('\n') + wxChar('\n')); + + wxString caption = _("Log-messages:"); + logFile.Write(caption + wxChar('\n')); + logFile.Write(wxString().Pad(caption.Len(), wxChar('-')) + wxChar('\n')); + + write(_("Start")); //attention: write() replaces '\n'-characters + logFile.Write(wxChar('\n')); // + + totalTime.Start(); //measure total time + } + } + + ~LogFile() + { + if (readyToWrite) + close(); + } + + bool isOkay() + { + return readyToWrite; + } + + void write(const wxString& logText, const wxString& problemType = wxEmptyString) + { + logFile.Write(wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ")); + + if (problemType != wxEmptyString) + logFile.Write(problemType + wxT(": ")); + + //remove linebreaks + wxString formattedText = logText; + for (wxString::iterator i = formattedText.begin(); i != formattedText.end(); ++i) + if (*i == wxChar('\n')) + *i = wxChar(' '); + + logFile.Write(formattedText + wxChar('\n')); + } + +private: + + void close() + { + logFile.Write(wxChar('\n')); + + long time = totalTime.Time(); //retrieve total time + + logFile.Write(wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ")); + logFile.Write(wxString(_("Stop")) + wxT(" (") + _("Total time:") + wxT(" ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")")); + + //logFile.close(); <- not needed + } + + bool readyToWrite; + wxFFile logFile; + wxStopWatch totalTime; +}; + + +class FfsTrayIcon : public wxTaskBarIcon +{ +public: + FfsTrayIcon(StatusHandler* statusHandler) : + m_statusHandler(statusHandler), + processPaused(false) + { + running.reset(new wxIcon(*globalResource.programIcon)); + paused.reset(new wxIcon); + paused->CopyFromBitmap(*globalResource.bitmapFFSPaused); + + wxTaskBarIcon::SetIcon(*running); + } + + ~FfsTrayIcon() {} + + enum + { + CONTEXT_PAUSE, + CONTEXT_ABORT, + CONTEXT_ABOUT + }; + + virtual wxMenu* CreatePopupMenu() + { + wxMenu* contextMenu = new wxMenu; + contextMenu->Append(CONTEXT_PAUSE, _("&Pause"), wxEmptyString, wxITEM_CHECK); + contextMenu->Check(CONTEXT_PAUSE, processPaused); + contextMenu->Append(CONTEXT_ABORT, _("&Abort")); + contextMenu->AppendSeparator(); + contextMenu->Append(CONTEXT_ABOUT, _("&About...")); + //event handling + contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(FfsTrayIcon::onContextMenuSelection), NULL, this); + + return contextMenu; //ownership transferred to library + } + + void onContextMenuSelection(wxCommandEvent& event) + { + int eventId = event.GetId(); + if (eventId == CONTEXT_PAUSE) + { + processPaused = !processPaused; + if (processPaused) + wxTaskBarIcon::SetIcon(*paused); + else + wxTaskBarIcon::SetIcon(*running); + } + else if (eventId == CONTEXT_ABORT) + { + processPaused = false; + wxTaskBarIcon::SetIcon(*running); + m_statusHandler->requestAbortion(); + } + else if (eventId == CONTEXT_ABOUT) + { + AboutDlg* aboutDlg = new AboutDlg(NULL); + aboutDlg->ShowModal(); + aboutDlg->Destroy(); + } + } + + void updateSysTray() + { + updateUiNow(); + + //support for pause button + while (processPaused) + { + wxMilliSleep(UI_UPDATE_INTERVAL); + updateUiNow(); + } + } + +private: + StatusHandler* m_statusHandler; + bool processPaused; + std::auto_ptr<wxIcon> running; + std::auto_ptr<wxIcon> paused; +}; + + +//############################################################################################################################## + +BatchStatusHandlerSilent::BatchStatusHandlerSilent(const xmlAccess::OnError handleError, const wxString& logfileDirectory, int& returnVal) : + m_handleError(handleError), + currentProcess(StatusHandler::PROCESS_NONE), + returnValue(returnVal), + trayIcon(new FfsTrayIcon(this)), + m_log(new LogFile(logfileDirectory)) +{ + //test if log was instantiated successfully + if (!m_log->isOkay()) + { //handle error: file load + wxMessageBox(_("Unable to create logfile!"), _("Error"), wxOK | wxICON_ERROR); + throw FreeFileSync::AbortThisProcess(); + } +} + + +BatchStatusHandlerSilent::~BatchStatusHandlerSilent() +{ + unsigned int failedItems = unhandledErrors.GetCount(); + + //write result + if (abortRequested) + { + returnValue = -4; + m_log->write(_("Synchronization aborted!"), _("Error")); + } + else if (failedItems) + { + returnValue = -5; + m_log->write(_("Synchronization completed with errors!"), _("Info")); + } + else + m_log->write(_("Synchronization completed successfully!"), _("Info")); +} + + +inline +void BatchStatusHandlerSilent::updateStatusText(const Zstring& text) +{ + if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) + m_log->write(text.c_str(), _("Info")); +} + + +inline +void BatchStatusHandlerSilent::initNewProcess(int objectsTotal, wxLongLong dataTotal, StatusHandler::Process processID) +{ + currentProcess = processID; +} + + +ErrorHandler::Response BatchStatusHandlerSilent::reportError(const Zstring& errorMessage) +{ + switch (m_handleError) + { + case xmlAccess::ON_ERROR_POPUP: + { + bool ignoreNextErrors = false; + ErrorDlg* errorDlg = new ErrorDlg(NULL, + ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, + wxString(errorMessage) + wxT("\n\n") + _("Ignore this error, retry or abort?"), + ignoreNextErrors); + const int rv = errorDlg->ShowModal(); + errorDlg->Destroy(); + switch (rv) + { + case ErrorDlg::BUTTON_IGNORE: + if (ignoreNextErrors) //falsify only + m_handleError = xmlAccess::ON_ERROR_IGNORE; + unhandledErrors.Add(errorMessage.c_str()); + m_log->write(errorMessage.c_str(), _("Error")); + return ErrorHandler::IGNORE_ERROR; + + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + + case ErrorDlg::BUTTON_ABORT: + unhandledErrors.Add(errorMessage.c_str()); + m_log->write(errorMessage.c_str(), _("Error")); + abortThisProcess(); + } + } + break; //used if last switch didn't find a match + + case xmlAccess::ON_ERROR_EXIT: //abort + unhandledErrors.Add(errorMessage.c_str()); + m_log->write(errorMessage.c_str(), _("Error")); + abortThisProcess(); + + case xmlAccess::ON_ERROR_IGNORE: + unhandledErrors.Add(errorMessage.c_str()); + m_log->write(errorMessage.c_str(), _("Error")); + return ErrorHandler::IGNORE_ERROR; + } + + assert(false); + return ErrorHandler::IGNORE_ERROR; //dummy value +} + + +void BatchStatusHandlerSilent::reportFatalError(const Zstring& errorMessage) +{ + switch (m_handleError) + { + case xmlAccess::ON_ERROR_POPUP: + { + bool dummy = false; + ErrorDlg* errorDlg = new ErrorDlg(NULL, + ErrorDlg::BUTTON_ABORT, + errorMessage.c_str(), dummy); + errorDlg->ShowModal(); + errorDlg->Destroy(); + } + break; + + case xmlAccess::ON_ERROR_EXIT: + break; + + case xmlAccess::ON_ERROR_IGNORE: + break; + } + + unhandledErrors.Add(errorMessage.c_str()); + m_log->write(errorMessage.c_str(), _("Error")); + abortThisProcess(); +} + + +void BatchStatusHandlerSilent::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) +{ + switch (m_handleError) + { + case xmlAccess::ON_ERROR_POPUP: + { + //show popup and ask user how to handle warning + bool dontWarnAgain = false; + WarningDlg* warningDlg = new WarningDlg(NULL, + WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, + warningMessage.c_str(), + dontWarnAgain); + const int rv = warningDlg->ShowModal(); + warningDlg->Destroy(); + switch (rv) + { + case WarningDlg::BUTTON_ABORT: + unhandledErrors.Add(warningMessage.c_str()); + m_log->write(warningMessage.c_str(), _("Warning")); + abortThisProcess(); + case WarningDlg::BUTTON_IGNORE: //no unhandled error situation! + dontShowAgain = dontWarnAgain; + m_log->write(warningMessage.c_str(), _("Warning")); + return; + } + } + break; //keep it! last switch might not find match + + case xmlAccess::ON_ERROR_EXIT: //abort + unhandledErrors.Add(warningMessage.c_str()); + m_log->write(warningMessage.c_str(), _("Warning")); + abortThisProcess(); + + case xmlAccess::ON_ERROR_IGNORE: //no unhandled error situation! + m_log->write(warningMessage.c_str(), _("Warning")); + return; + } + + assert(false); +} + + +void BatchStatusHandlerSilent::addFinalInfo(const Zstring& infoMessage) +{ + m_log->write(infoMessage.c_str(), _("Info")); +} + + +void BatchStatusHandlerSilent::forceUiRefresh() +{ + trayIcon->updateSysTray(); //needed by sys-tray icon only +} + + +void BatchStatusHandlerSilent::abortThisProcess() //used by sys-tray menu +{ + abortRequested = true; + throw FreeFileSync::AbortThisProcess(); +} + +//###################################################################################################### + + +BatchStatusHandlerGui::BatchStatusHandlerGui(const xmlAccess::OnError handleError, int& returnVal) : + m_handleError(handleError), + currentProcess(StatusHandler::PROCESS_NONE), + returnValue(returnVal) +{ + syncStatusFrame = new SyncStatus(this, NULL); + syncStatusFrame->Show(); +} + + +BatchStatusHandlerGui::~BatchStatusHandlerGui() +{ + //display result + wxString finalMessage; + + unsigned int failedItems = unhandledErrors.GetCount(); + if (failedItems) + { + finalMessage = wxString(_("Warning: Synchronization failed for %x item(s):")) + wxT("\n\n"); + finalMessage.Replace(wxT("%x"), globalFunctions::numberToWxString(failedItems), false); + + for (unsigned int j = 0; j < failedItems; ++j) + { //remove linebreaks + wxString errorMessage = unhandledErrors[j]; + for (wxString::iterator i = errorMessage.begin(); i != errorMessage.end(); ++i) + if (*i == wxChar('\n')) + *i = wxChar(' '); + + finalMessage += errorMessage + wxT("\n"); + } + finalMessage += wxT("\n"); + } + + if (!finalInfo.IsEmpty()) + finalMessage += finalInfo + wxT("\n\n"); + + //notify to syncStatusFrame that current process has ended + if (abortRequested) + { + returnValue = -4; + finalMessage += _("Synchronization aborted!"); + syncStatusFrame->setStatusText_NoUpdate(finalMessage.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::ABORTED); //enable okay and close events + } + else if (failedItems) + { + returnValue = -5; + finalMessage += _("Synchronization completed with errors!"); + syncStatusFrame->setStatusText_NoUpdate(finalMessage.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_ERROR); + } + else + { + finalMessage += _("Synchronization completed successfully!"); + syncStatusFrame->setStatusText_NoUpdate(finalMessage.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS); + } +} + + +inline +void BatchStatusHandlerGui::updateStatusText(const Zstring& text) +{ + syncStatusFrame->setStatusText_NoUpdate(text); +} + + +void BatchStatusHandlerGui::initNewProcess(int objectsTotal, wxLongLong dataTotal, StatusHandler::Process processID) +{ + currentProcess = processID; + + if (currentProcess == StatusHandler::PROCESS_SCANNING) + syncStatusFrame->setCurrentStatus(SyncStatus::SCANNING); + + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + { + syncStatusFrame->resetGauge(objectsTotal, dataTotal); + syncStatusFrame->setCurrentStatus(SyncStatus::COMPARING); + } + + else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) + { + syncStatusFrame->resetGauge(objectsTotal, dataTotal); + syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); + } + else assert(false); +} + + +inline +void BatchStatusHandlerGui::updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) +{ + if (currentProcess == StatusHandler::PROCESS_SCANNING) + ; + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); + else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) + syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); + else assert(false); +} + + +ErrorHandler::Response BatchStatusHandlerGui::reportError(const Zstring& errorMessage) +{ + //add current time before error message + wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); + + switch (m_handleError) + { + case xmlAccess::ON_ERROR_POPUP: + { + syncStatusFrame->updateStatusDialogNow(); + + bool ignoreNextErrors = false; + ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, + ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, + wxString(errorMessage) + wxT("\n\n") + _("Ignore this error, retry or abort?"), + ignoreNextErrors); + switch (errorDlg->ShowModal()) + { + case ErrorDlg::BUTTON_IGNORE: + if (ignoreNextErrors) //falsify only + m_handleError = xmlAccess::ON_ERROR_IGNORE; + unhandledErrors.Add(errorWithTime); + return ErrorHandler::IGNORE_ERROR; + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + case ErrorDlg::BUTTON_ABORT: + unhandledErrors.Add(errorWithTime); + abortThisProcess(); + } + } + break; //used IF last switch didn't find a match + + case xmlAccess::ON_ERROR_EXIT: //abort + unhandledErrors.Add(errorWithTime); + abortThisProcess(); + + case xmlAccess::ON_ERROR_IGNORE: + unhandledErrors.Add(errorWithTime); + return ErrorHandler::IGNORE_ERROR; + } + + assert(false); + return ErrorHandler::IGNORE_ERROR; //dummy value +} + + +void BatchStatusHandlerGui::reportFatalError(const Zstring& errorMessage) +{ //add current time before error message + wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); + + unhandledErrors.Add(errorWithTime); + abortThisProcess(); +} + + +void BatchStatusHandlerGui::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) +{ //add current time before warning message + wxString warningWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + warningMessage.c_str(); + + switch (m_handleError) + { + case xmlAccess::ON_ERROR_POPUP: + case xmlAccess::ON_ERROR_EXIT: //show popup in this case also + { + //show popup and ask user how to handle warning + bool dontWarnAgain = false; + WarningDlg* warningDlg = new WarningDlg(NULL, + WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, + warningMessage.c_str(), + dontWarnAgain); + const int rv = warningDlg->ShowModal(); + warningDlg->Destroy(); + switch (rv) + { + case WarningDlg::BUTTON_IGNORE: //no unhandled error situation! + dontShowAgain = dontWarnAgain; + return; + case WarningDlg::BUTTON_ABORT: + unhandledErrors.Add(warningWithTime); + abortThisProcess(); + } + } + break; //keep it! last switch might not find match + + case xmlAccess::ON_ERROR_IGNORE: //no unhandled error situation! + return; + } + + assert(false); +} + + +inline +void BatchStatusHandlerGui::forceUiRefresh() +{ + if (currentProcess == StatusHandler::PROCESS_SCANNING) + syncStatusFrame->m_gauge1->Pulse(); //expensive! So put it here! + + syncStatusFrame->updateStatusDialogNow(); +} + + +void BatchStatusHandlerGui::abortThisProcess() +{ + abortRequested = true; + throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame +} + + +void BatchStatusHandlerGui::addFinalInfo(const Zstring& infoMessage) +{ + finalInfo = infoMessage.c_str(); +} diff --git a/ui/batchStatusHandler.h b/ui/batchStatusHandler.h new file mode 100644 index 00000000..7087d3c9 --- /dev/null +++ b/ui/batchStatusHandler.h @@ -0,0 +1,83 @@ +#ifndef BATCHSTATUSHANDLER_H_INCLUDED +#define BATCHSTATUSHANDLER_H_INCLUDED + +#include "../library/statusHandler.h" +#include <memory> +#include "../library/processXml.h" +#include <wx/arrstr.h> + +class LogFile; +class FfsTrayIcon; +class SyncStatus; + + +class BatchStatusHandler : public StatusHandler +{ +public: + BatchStatusHandler() {} + virtual ~BatchStatusHandler() {} + + virtual void addFinalInfo(const Zstring& infoMessage) = 0; +}; + + +class BatchStatusHandlerSilent : public BatchStatusHandler +{ +public: + BatchStatusHandlerSilent(const xmlAccess::OnError handleError, const wxString& logfileDirectory, int& returnVal); + ~BatchStatusHandlerSilent(); + + + virtual void updateStatusText(const Zstring& text); + virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); + virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) {} + virtual void forceUiRefresh(); + + virtual ErrorHandler::Response reportError(const Zstring& errorMessage); + virtual void reportFatalError(const Zstring& errorMessage); + virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); + virtual void addFinalInfo(const Zstring& infoMessage); + +private: + virtual void abortThisProcess(); + + xmlAccess::OnError m_handleError; + wxArrayString unhandledErrors; //list of non-resolved errors + Process currentProcess; + int& returnValue; + std::auto_ptr<FfsTrayIcon> trayIcon; + + std::auto_ptr<LogFile> m_log; +}; + + +class BatchStatusHandlerGui : public BatchStatusHandler +{ +public: + BatchStatusHandlerGui(const xmlAccess::OnError handleError, int& returnVal); + ~BatchStatusHandlerGui(); + + virtual void updateStatusText(const Zstring& text); + virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); + virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void forceUiRefresh(); + + virtual ErrorHandler::Response reportError(const Zstring& errorMessage); + virtual void reportFatalError(const Zstring& errorMessage); + virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); + virtual void addFinalInfo(const Zstring& infoMessage); + +private: + virtual void abortThisProcess(); + + xmlAccess::OnError m_handleError; + wxArrayString unhandledErrors; //list of non-resolved errors + Process currentProcess; + int& returnValue; + + SyncStatus* syncStatusFrame; + wxString finalInfo; //workaround to display "Nothing to synchronize..." +}; + + +#endif // BATCHSTATUSHANDLER_H_INCLUDED diff --git a/ui/checkVersion.cpp b/ui/checkVersion.cpp index 5344b45e..914e5e09 100644 --- a/ui/checkVersion.cpp +++ b/ui/checkVersion.cpp @@ -5,6 +5,8 @@ #include "../version/version.h" #include <wx/msgdlg.h> #include <wx/utils.h> +#include <wx/timer.h> +#include "../library/globalFunctions.h" class CloseConnectionOnExit @@ -26,7 +28,7 @@ private: }; -void FreeFileSync::checkForNewVersion() +bool getOnlineVersion(wxString& version) { wxHTTP webAccess; wxInputStream* httpStream = NULL; @@ -50,21 +52,85 @@ void FreeFileSync::checkForNewVersion() httpStream->Read(out_stream); if (!newestVersion.empty()) { - if (FreeFileSync::currentVersion == newestVersion) - { - wxMessageBox(_("FreeFileSync is up to date!"), _("Information"), wxICON_INFORMATION); - return; - } - else - { - const int rv = wxMessageBox(wxString(_("A newer version is available:")) + wxT(" v") + newestVersion + wxT(". ") + _("Download now?"), _("Information"), wxYES_NO | wxICON_QUESTION); - if (rv == wxYES) - wxLaunchDefaultBrowser(wxT("http://sourceforge.net/project/showfiles.php?group_id=234430")); - return; - } + version = newestVersion; + return true; } } } - wxMessageBox(_("Unable to connect to sourceforge.net!"), _("Error"), wxOK | wxICON_ERROR); + return false; } + + +bool newerVersionExists(const wxString& onlineVersion) +{ + const wxString currentMajor = FreeFileSync::currentVersion.BeforeLast(wxT('.')); + const wxString onlineMajor = onlineVersion.BeforeLast(wxT('.')); + + if (currentMajor != onlineMajor) + return globalFunctions::wxStringToInt(currentMajor) < globalFunctions::wxStringToInt(onlineMajor); + + const wxString currentMinor = FreeFileSync::currentVersion.AfterLast(wxT('.')); + const wxString onlineMinor = onlineVersion.AfterLast(wxT('.')); + + return globalFunctions::wxStringToInt(currentMinor) < globalFunctions::wxStringToInt(onlineMinor); +} + + +void FreeFileSync::checkForUpdateNow() +{ + wxString onlineVersion; + if (!getOnlineVersion(onlineVersion)) + { + wxMessageBox(_("Unable to connect to sourceforge.net!"), _("Error"), wxOK | wxICON_ERROR); + return; + } + + if (newerVersionExists(onlineVersion)) + { + const int rv = wxMessageBox(wxString(_("A newer version of FreeFileSync is available:")) + wxT(" v") + onlineVersion + wxT(". ") + _("Download now?"), _("Information"), wxYES_NO | wxICON_QUESTION); + if (rv == wxYES) + wxLaunchDefaultBrowser(wxT("http://sourceforge.net/project/showfiles.php?group_id=234430")); + } + else + wxMessageBox(_("FreeFileSync is up to date!"), _("Information"), wxICON_INFORMATION); +} + + +void FreeFileSync::checkForUpdatePeriodically(long& lastUpdateCheck) +{ + if (lastUpdateCheck != -1) + { + if (lastUpdateCheck == 0) + { + const int rv = wxMessageBox(_("Do you want FreeFileSync to automatically check for updates every week?"), _("Information"), wxYES_NO | wxICON_QUESTION); + if (rv == wxYES) + { + lastUpdateCheck = 123; //some old date (few seconds after 1970) + + checkForUpdatePeriodically(lastUpdateCheck); //check for updates now + } + else + lastUpdateCheck = -1; //don't check for updates anymore + } + else if (wxGetLocalTime() >= lastUpdateCheck + 7 * 24 * 3600) //check weekly + { + wxString onlineVersion; + if (!getOnlineVersion(onlineVersion)) + return; //do not handle error + + lastUpdateCheck = wxGetLocalTime(); + + if (newerVersionExists(onlineVersion)) + { + const int rv = wxMessageBox(wxString(_("A newer version of FreeFileSync is available:")) + wxT(" v") + onlineVersion + wxT(". ") + _("Download now?"), _("Information"), wxYES_NO | wxICON_QUESTION); + if (rv == wxYES) + wxLaunchDefaultBrowser(wxT("http://sourceforge.net/project/showfiles.php?group_id=234430")); + } + } + } +} + + + + diff --git a/ui/checkVersion.h b/ui/checkVersion.h index e6705774..e59235f4 100644 --- a/ui/checkVersion.h +++ b/ui/checkVersion.h @@ -4,7 +4,9 @@ namespace FreeFileSync { - void checkForNewVersion(); + void checkForUpdateNow(); + + void checkForUpdatePeriodically(long& lastUpdateCheck); } #endif // UPDATEVERSION_H_INCLUDED diff --git a/ui/dragAndDrop.cpp b/ui/dragAndDrop.cpp new file mode 100644 index 00000000..c7aea906 --- /dev/null +++ b/ui/dragAndDrop.cpp @@ -0,0 +1,207 @@ +#include "dragAndDrop.h" +#include <wx/dnd.h> +#include <wx/window.h> +#include <wx/combobox.h> +#include <wx/textctrl.h> +#include <wx/filepicker.h> +#include <wx/filename.h> +#include "../algorithm.h" + + +//define new event type +const wxEventType FFS_DROP_FILE_EVENT = wxNewEventType(); + +typedef void (wxEvtHandler::*FFSFileDropEventFunction)(FFSFileDropEvent&); + +#define FFSFileDropEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSFileDropEventFunction, &func) + +class FFSFileDropEvent : public wxCommandEvent +{ +public: + FFSFileDropEvent(const wxString& nameDropped, const wxWindow* dropWindow) : + wxCommandEvent(FFS_DROP_FILE_EVENT), + nameDropped_(nameDropped), + dropWindow_(dropWindow) {} + + virtual wxEvent* Clone() const + { + return new FFSFileDropEvent(nameDropped_, dropWindow_); + } + + const wxString nameDropped_; + const wxWindow* dropWindow_; +}; + +//############################################################################################################## + + +class WindowDropTarget : public wxFileDropTarget +{ +public: + WindowDropTarget(wxWindow* dropWindow) : + dropWindow_(dropWindow) {} + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) + { + if (!filenames.IsEmpty()) + { + const wxString droppedFileName = filenames[0]; + + //create a custom event on drop window: execute event after file dropping is completed! (e.g. after mouse is released) + FFSFileDropEvent evt(droppedFileName, dropWindow_); + dropWindow_->GetEventHandler()->AddPendingEvent(evt); + } + return false; + } + +private: + wxWindow* dropWindow_; +}; + + + +//############################################################################################################## + +using FreeFileSync::DragDropOnMainDlg; + +DragDropOnMainDlg::DragDropOnMainDlg(wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName) : + dropWindow1_(dropWindow1), + dropWindow2_(dropWindow2), + dirPicker_(dirPicker), + dirName_(dirName) +{ + //prepare drag & drop + dropWindow1->SetDropTarget(new WindowDropTarget(dropWindow1)); //takes ownership + dropWindow2->SetDropTarget(new WindowDropTarget(dropWindow2)); //takes ownership + + //redirect drag & drop event back to this class + dropWindow1->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnMainDlg::OnFilesDropped), NULL, this); + dropWindow2->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnMainDlg::OnFilesDropped), NULL, this); + + //keep dirPicker and dirName synchronous + dirName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DragDropOnMainDlg::OnWriteDirManually ), NULL, this ); + dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( DragDropOnMainDlg::OnDirSelected ), NULL, this ); +} + + +void DragDropOnMainDlg::OnFilesDropped(FFSFileDropEvent& event) +{ + if ( this->dropWindow1_ == event.dropWindow_ || //file may be dropped on window 1 or 2 + this->dropWindow2_ == event.dropWindow_) + { + if (AcceptDrop(event.nameDropped_)) + { + wxString fileName = event.nameDropped_; + if (wxDirExists(fileName)) + { + dirName_->SetSelection(wxNOT_FOUND); + dirName_->SetValue(fileName); + dirPicker_->SetPath(fileName); + } + else + { + fileName = wxFileName(fileName).GetPath(); + if (wxDirExists(fileName)) + { + dirName_->SetSelection(wxNOT_FOUND); + dirName_->SetValue(fileName); + dirPicker_->SetPath(fileName); + } + } + } + } + else //should never be reached + event.Skip(); +}; + + +void DragDropOnMainDlg::OnWriteDirManually(wxCommandEvent& event) +{ + const wxString newDir = FreeFileSync::getFormattedDirectoryName(event.GetString().c_str()).c_str(); + if (wxDirExists(newDir)) + dirPicker_->SetPath(newDir); + + event.Skip(); +} + + +void DragDropOnMainDlg::OnDirSelected(wxFileDirPickerEvent& event) +{ + const wxString newPath = event.GetPath(); + dirName_->SetSelection(wxNOT_FOUND); + dirName_->SetValue(newPath); + + event.Skip(); +} + +//############################################################################################################## + + +using FreeFileSync::DragDropOnDlg; + +DragDropOnDlg::DragDropOnDlg(wxWindow* dropWindow, + wxDirPickerCtrl* dirPicker, + wxTextCtrl* dirName) : + dropWindow_(dropWindow), + dirPicker_(dirPicker), + dirName_(dirName) +{ + //prepare drag & drop + dropWindow->SetDropTarget(new WindowDropTarget(dropWindow)); //takes ownership + + //redirect drag & drop event back to this class + dropWindow->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnDlg::OnFilesDropped), NULL, this); + + //keep dirPicker and dirName synchronous + dirName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DragDropOnDlg::OnWriteDirManually ), NULL, this ); + dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( DragDropOnDlg::OnDirSelected ), NULL, this ); +} + + +void DragDropOnDlg::OnFilesDropped(FFSFileDropEvent& event) +{ + if (this->dropWindow_ == event.dropWindow_) + { + wxString fileName = event.nameDropped_; + if (wxDirExists(fileName)) + { + dirName_->SetValue(fileName); + dirPicker_->SetPath(fileName); + } + else + { + fileName = wxFileName(fileName).GetPath(); + if (wxDirExists(fileName)) + { + dirName_->SetValue(fileName); + dirPicker_->SetPath(fileName); + } + } + } + else //should never be reached + event.Skip(); +}; + + +void DragDropOnDlg::OnWriteDirManually(wxCommandEvent& event) +{ + const wxString newDir = FreeFileSync::getFormattedDirectoryName(event.GetString().c_str()).c_str(); + if (wxDirExists(newDir)) + dirPicker_->SetPath(newDir); + + event.Skip(); +} + + +void DragDropOnDlg::OnDirSelected(wxFileDirPickerEvent& event) +{ + const wxString newPath = event.GetPath(); + dirName_->SetValue(newPath); + + event.Skip(); +} + diff --git a/ui/dragAndDrop.h b/ui/dragAndDrop.h new file mode 100644 index 00000000..cca6f865 --- /dev/null +++ b/ui/dragAndDrop.h @@ -0,0 +1,63 @@ +#ifndef DRAGANDDROP_H_INCLUDED +#define DRAGANDDROP_H_INCLUDED + +#include <wx/event.h> + +class wxWindow; +class wxDirPickerCtrl; +class wxComboBox; +class wxTextCtrl; +class wxString; +class FFSFileDropEvent; +class wxCommandEvent; +class wxFileDirPickerEvent; + + +namespace FreeFileSync +{ + //add drag and drop functionality, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl + + class DragDropOnMainDlg : public wxEvtHandler + { + public: + DragDropOnMainDlg(wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName); + + virtual ~DragDropOnMainDlg() {} + + virtual bool AcceptDrop(const wxString& dropName) = 0; //return true if drop should be processed + + private: + void OnFilesDropped(FFSFileDropEvent& event); + void OnWriteDirManually(wxCommandEvent& event); + void OnDirSelected(wxFileDirPickerEvent& event); + + const wxWindow* dropWindow1_; + const wxWindow* dropWindow2_; + wxDirPickerCtrl* dirPicker_; + wxComboBox* dirName_; + }; + + + class DragDropOnDlg: public wxEvtHandler + { + public: + DragDropOnDlg(wxWindow* dropWindow, + wxDirPickerCtrl* dirPicker, + wxTextCtrl* dirName); + + private: + void OnFilesDropped(FFSFileDropEvent& event); + void OnWriteDirManually(wxCommandEvent& event); + void OnDirSelected(wxFileDirPickerEvent& event); + + const wxWindow* dropWindow_; + wxDirPickerCtrl* dirPicker_; + wxTextCtrl* dirName_; + }; +} + + +#endif // DRAGANDDROP_H_INCLUDED diff --git a/ui/gridView.cpp b/ui/gridView.cpp new file mode 100644 index 00000000..ed950c15 --- /dev/null +++ b/ui/gridView.cpp @@ -0,0 +1,213 @@ +#include "gridView.h" +#include "sorting.h" + +using FreeFileSync::GridView; + + +GridView::StatusInfo GridView::update( + const bool includeLeftOnly, + const bool includeRightOnly, + const bool includeLeftNewer, + const bool includeRightNewer, + const bool includeDifferent, + const bool includeEqual, + const bool hideFiltered) +{ + StatusInfo output; + output.existsLeftOnly = false; + output.existsRightOnly = false; + output.existsLeftNewer = false; + output.existsRightNewer = false; + output.existsDifferent = false; + output.existsEqual = false; + + output.filesOnLeftView = 0; + output.foldersOnLeftView = 0; + output.filesOnRightView = 0; + output.foldersOnRightView = 0; + + refView.clear(); + + for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) + { + const FileComparison& fileCmp = j->fileCmp; + + RefIndex newEntry; + newEntry.folderIndex = j - folderCmp.begin(); + + for (FileComparison::const_iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) + { + //hide filtered row, if corresponding option is set + if (hideFiltered && !i->selectedForSynchronization) + continue; + + //process UI filter settings + switch (i->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + output.existsLeftOnly = true; + if (!includeLeftOnly) continue; + break; + case FILE_RIGHT_SIDE_ONLY: + output.existsRightOnly = true; + if (!includeRightOnly) continue; + break; + case FILE_LEFT_NEWER: + output.existsLeftNewer = true; + if (!includeLeftNewer) continue; + break; + case FILE_RIGHT_NEWER: + output.existsRightNewer = true; + if (!includeRightNewer) continue; + break; + case FILE_DIFFERENT: + output.existsDifferent = true; + if (!includeDifferent) continue; + break; + case FILE_EQUAL: + output.existsEqual = true; + if (!includeEqual) continue; + break; + default: + assert (false); + } + + //calculate total number of bytes for each side + if (i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE) + { + output.filesizeLeftView += i->fileDescrLeft.fileSize; + ++output.filesOnLeftView; + } + else if (i->fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) + ++output.foldersOnLeftView; + + if (i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) + { + output.filesizeRightView += i->fileDescrRight.fileSize; + ++output.filesOnRightView; + } + else if (i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) + ++output.foldersOnRightView; + + + newEntry.rowIndex = i - fileCmp.begin(); + refView.push_back(newEntry); + } + +// //add some empty line after each folder pair +// RefIndex emptyLine; +// emptyLine.folderIndex = -1; +// emptyLine.rowIndex = 0; +// refView.push_back(emptyLine); + } + + return output; +} + + +void GridView::viewRefToFolderRef(const std::set<int>& viewRef, FolderCompRef& output) +{ + output.clear(); + for (int i = 0; i < int(folderCmp.size()); ++i) + output.push_back(std::set<int>()); //avoid copy by value for full set<int> + + for (std::set<int>::iterator i = viewRef.begin(); i != viewRef.end(); ++i) + { + const unsigned int folder = refView[*i].folderIndex; + const unsigned int row = refView[*i].rowIndex; + + output[folder].insert(row); + } +} + + +unsigned int GridView::elementsTotal() const +{ + unsigned int total = 0; + for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) + total += j->fileCmp.size(); + + return total; +} + + +template <typename CompareFct> +void bubbleSort(FreeFileSync::FolderComparison& folderCmp, CompareFct compare) +{ + for (int i = folderCmp.size() - 2; i >= 0; --i) + { + bool swapped = false; + for (int j = 0; j <= i; ++j) + if (compare(folderCmp[j + 1], folderCmp[j])) + { + std::swap(folderCmp[j + 1].syncPair, folderCmp[j].syncPair); + folderCmp[j + 1].fileCmp.swap(folderCmp[j].fileCmp); + + swapped = true; + } + + if (!swapped) + return; + } +} + + +void GridView::sortView(const SortType type, const bool onLeft, const bool ascending) +{ + using namespace FreeFileSync; + + if (type == SORT_BY_DIRECTORY) + { + //specialization: use own sorting function based on vector<FileCompareLine>::swap() + //bubble sort is no performance issue since number of folder pairs should be "small" + if (ascending && onLeft) bubbleSort(folderCmp, sortByDirectory<ASCENDING, SORT_ON_LEFT>); + else if (ascending && !onLeft) bubbleSort(folderCmp, sortByDirectory<ASCENDING, SORT_ON_RIGHT>); + else if (!ascending && onLeft) bubbleSort(folderCmp, sortByDirectory<DESCENDING, SORT_ON_LEFT>); + else if (!ascending && !onLeft) bubbleSort(folderCmp, sortByDirectory<DESCENDING, SORT_ON_RIGHT>); + + //then sort by relative name + GridView::sortView(SORT_BY_REL_NAME, onLeft, ascending); + return; + } + + + for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) + { + FileComparison& fileCmp = j->fileCmp; + + switch (type) + { + case SORT_BY_REL_NAME: + if ( ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByRelativeName<ASCENDING, SORT_ON_LEFT>); + else if ( ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByRelativeName<ASCENDING, SORT_ON_RIGHT>); + else if (!ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByRelativeName<DESCENDING, SORT_ON_LEFT>); + else if (!ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByRelativeName<DESCENDING, SORT_ON_RIGHT>); + break; + case SORT_BY_FILENAME: + if ( ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileName<ASCENDING, SORT_ON_LEFT>); + else if ( ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileName<ASCENDING, SORT_ON_RIGHT>); + else if (!ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileName<DESCENDING, SORT_ON_LEFT>); + else if (!ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileName<DESCENDING, SORT_ON_RIGHT>); + break; + case SORT_BY_FILESIZE: + if ( ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileSize<ASCENDING, SORT_ON_LEFT>); + else if ( ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileSize<ASCENDING, SORT_ON_RIGHT>); + else if (!ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileSize<DESCENDING, SORT_ON_LEFT>); + else if (!ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByFileSize<DESCENDING, SORT_ON_RIGHT>); + break; + case SORT_BY_DATE: + if ( ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByDate<ASCENDING, SORT_ON_LEFT>); + else if ( ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByDate<ASCENDING, SORT_ON_RIGHT>); + else if (!ascending && onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByDate<DESCENDING, SORT_ON_LEFT>); + else if (!ascending && !onLeft) std::sort(fileCmp.begin(), fileCmp.end(), sortByDate<DESCENDING, SORT_ON_RIGHT>); + break; + case SORT_BY_CMP_RESULT: + if ( ascending) std::sort(fileCmp.begin(), fileCmp.end(), sortByCmpResult<ASCENDING>); + else if (!ascending) std::sort(fileCmp.begin(), fileCmp.end(), sortByCmpResult<DESCENDING>); + break; + default: + assert(false); + } + } +} + diff --git a/ui/gridView.h b/ui/gridView.h new file mode 100644 index 00000000..b4101da7 --- /dev/null +++ b/ui/gridView.h @@ -0,0 +1,108 @@ +#ifndef GRIDVIEW_H_INCLUDED +#define GRIDVIEW_H_INCLUDED + +#include "../structures.h" + + +namespace FreeFileSync +{ + //gui view of FolderComparison + class GridView + { + public: + GridView(FolderComparison& results) : folderCmp(results) {} + + const FileCompareLine& operator[] (unsigned row) const; + + //unsigned getResultsIndex(const unsigned viewIndex); //convert index on GridView to index on FolderComparison + + unsigned int elementsOnView() const; + + unsigned int elementsTotal() const; + + //convert view references to FolderCompRef + void viewRefToFolderRef(const std::set<int>& viewRef, FolderCompRef& output); + + const FolderPair getFolderPair(const unsigned int row) const; + + struct StatusInfo + { + bool existsLeftOnly; + bool existsRightOnly; + bool existsLeftNewer; + bool existsRightNewer; + bool existsDifferent; + bool existsEqual; + + unsigned int filesOnLeftView; + unsigned int foldersOnLeftView; + unsigned int filesOnRightView; + unsigned int foldersOnRightView; + + wxULongLong filesizeLeftView; + wxULongLong filesizeRightView; + }; + + StatusInfo update(const bool includeLeftOnly, + const bool includeRightOnly, + const bool includeLeftNewer, + const bool includeRightNewer, + const bool includeDifferent, + const bool includeEqual, + const bool hideFiltered); + + //sorting... + enum SortType + { + SORT_BY_REL_NAME, + SORT_BY_FILENAME, + SORT_BY_FILESIZE, + SORT_BY_DATE, + SORT_BY_CMP_RESULT, + SORT_BY_DIRECTORY + }; + + void sortView(const SortType type, const bool onLeft, const bool ascending); + + private: + struct RefIndex + { + unsigned int folderIndex; + unsigned int rowIndex; + }; + + std::vector<RefIndex> refView; + FolderComparison& folderCmp; + }; + + +//############################################################################ +//inline implementation + inline + const FileCompareLine& GridView::operator[] (unsigned row) const + { + const unsigned int folderInd = refView[row].folderIndex; + const unsigned int rowInd = refView[row].rowIndex; + + return folderCmp[folderInd].fileCmp[rowInd]; + } + + + inline + unsigned int GridView::elementsOnView() const + { + return refView.size(); + } + + + inline + const FolderPair GridView::getFolderPair(const unsigned int row) const + { + const unsigned int folderInd = refView[row].folderIndex; + const FolderCompareLine& folderCmpLine = folderCmp[folderInd]; + return folderCmpLine.syncPair; + } +} + + +#endif // GRIDVIEW_H_INCLUDED diff --git a/ui/guiGenerated.cpp b/ui/guiGenerated.cpp index c7188b38..c56fafbb 100644 --- a/ui/guiGenerated.cpp +++ b/ui/guiGenerated.cpp @@ -17,96 +17,99 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const this->SetSizeHints( wxDefaultSize, wxDefaultSize ); m_menubar1 = new wxMenuBar( 0 ); - m_menu1 = new wxMenu(); - m_menuItem10 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("1. &Compare") ) + wxT('\t') + wxT("ALT-C"), wxEmptyString, wxITEM_NORMAL ); - m_menu1->Append( m_menuItem10 ); + m_menuFile = new wxMenu(); + m_menuItem10 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("1. &Compare") ) + wxT('\t') + wxT("ALT-C"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItem10 ); - m_menuItem11 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("2. &Synchronize...") ) + wxT('\t') + wxT("ALT-S"), wxEmptyString, wxITEM_NORMAL ); - m_menu1->Append( m_menuItem11 ); + m_menuItem11 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("2. &Synchronize...") ) + wxT('\t') + wxT("ALT-S"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItem11 ); - m_menu1->AppendSeparator(); + m_menuFile->AppendSeparator(); wxMenuItem* m_menuItem14; - m_menuItem14 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("S&ave configuration") ) + wxT('\t') + wxT("CTRL-S"), wxEmptyString, wxITEM_NORMAL ); - m_menu1->Append( m_menuItem14 ); + m_menuItem14 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("S&ave configuration") ) + wxT('\t') + wxT("CTRL-S"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItem14 ); wxMenuItem* m_menuItem13; - m_menuItem13 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("&Load configuration") ) + wxT('\t') + wxT("CTRL-L"), wxEmptyString, wxITEM_NORMAL ); - m_menu1->Append( m_menuItem13 ); + m_menuItem13 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("&Load configuration") ) + wxT('\t') + wxT("CTRL-L"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItem13 ); - m_menu1->AppendSeparator(); + m_menuFile->AppendSeparator(); wxMenuItem* m_menuItem4; - m_menuItem4 = new wxMenuItem( m_menu1, wxID_EXIT, wxString( _("&Quit") ) + wxT('\t') + wxT("CTRL-Q"), wxEmptyString, wxITEM_NORMAL ); - m_menu1->Append( m_menuItem4 ); + m_menuItem4 = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("&Quit") ) + wxT('\t') + wxT("CTRL-Q"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItem4 ); - m_menubar1->Append( m_menu1, _("&File") ); + m_menubar1->Append( m_menuFile, _("&File") ); - m_menu3 = new wxMenu(); - m_menu31 = new wxMenu(); - m_menuItemGerman = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Deutsch") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemGerman ); + m_menuAdvanced = new wxMenu(); + m_menuLanguages = new wxMenu(); + m_menuItemGerman = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Deutsch") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemGerman ); - m_menuItemEnglish = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("English") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemEnglish ); + m_menuItemEnglish = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("English") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemEnglish ); - m_menuItemSpanish = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Español") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemSpanish ); + m_menuItemSpanish = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Español") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemSpanish ); - m_menuItemFrench = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Français") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemFrench ); + m_menuItemFrench = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Français") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemFrench ); - m_menuItemHungarian = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Magyar Nyelv") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemHungarian ); + m_menuItemItalian = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Italiano") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemItalian ); - m_menuItemItalian = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Italiano") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemItalian ); + m_menuItemHungarian = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Magyar") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemHungarian ); - m_menuItemPolish = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Język Polski") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemPolish ); + m_menuItemDutch = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Nederlands") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemDutch ); - m_menuItemDutch = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Nederlands") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemDutch ); + m_menuItemPolish = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Polski") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemPolish ); - m_menuItemPortuguese = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Português") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemPortuguese ); + m_menuItemPortuguese = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Português") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemPortuguese ); - m_menuItemSlovenian = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Slovenščina") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemSlovenian ); + m_menuItemPortugueseBrazil = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Português do Brasil") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemPortugueseBrazil ); - m_menuItemJapanese = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("日本語") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemJapanese ); + m_menuItemSlovenian = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("Slovenščina") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemSlovenian ); - m_menuItemChineseSimple = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("简体中文") ) , wxEmptyString, wxITEM_RADIO ); - m_menu31->Append( m_menuItemChineseSimple ); + m_menuItemJapanese = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("日本語") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemJapanese ); - m_menu3->Append( -1, _("&Language"), m_menu31 ); + m_menuItemChineseSimple = new wxMenuItem( m_menuLanguages, wxID_ANY, wxString( _("简体中文") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuLanguages->Append( m_menuItemChineseSimple ); - m_menu3->AppendSeparator(); + m_menuAdvanced->Append( -1, _("&Language"), m_menuLanguages ); - m_menuItemGlobSett = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Global settings") ) , wxEmptyString, wxITEM_NORMAL ); - m_menu3->Append( m_menuItemGlobSett ); + m_menuAdvanced->AppendSeparator(); - m_menuItem7 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Create batch job") ) , wxEmptyString, wxITEM_NORMAL ); - m_menu3->Append( m_menuItem7 ); + m_menuItemGlobSett = new wxMenuItem( m_menuAdvanced, wxID_ANY, wxString( _("&Global settings") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuAdvanced->Append( m_menuItemGlobSett ); + + m_menuItem7 = new wxMenuItem( m_menuAdvanced, wxID_ANY, wxString( _("&Create batch job") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuAdvanced->Append( m_menuItem7 ); wxMenuItem* m_menuItem5; - m_menuItem5 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Export file list") ) , wxEmptyString, wxITEM_NORMAL ); - m_menu3->Append( m_menuItem5 ); + m_menuItem5 = new wxMenuItem( m_menuAdvanced, wxID_ANY, wxString( _("&Export file list") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuAdvanced->Append( m_menuItem5 ); - m_menubar1->Append( m_menu3, _("&Advanced") ); + m_menubar1->Append( m_menuAdvanced, _("&Advanced") ); - m_menu33 = new wxMenu(); + m_menuHelp = new wxMenu(); wxMenuItem* m_menuItemCheckVer; - m_menuItemCheckVer = new wxMenuItem( m_menu33, wxID_ANY, wxString( _("&Check for new version") ) , wxEmptyString, wxITEM_NORMAL ); - m_menu33->Append( m_menuItemCheckVer ); + m_menuItemCheckVer = new wxMenuItem( m_menuHelp, wxID_ANY, wxString( _("&Check for new version") ) , wxEmptyString, wxITEM_NORMAL ); + m_menuHelp->Append( m_menuItemCheckVer ); - m_menu33->AppendSeparator(); + m_menuHelp->AppendSeparator(); - m_menuItemAbout = new wxMenuItem( m_menu33, wxID_ABOUT, wxString( _("&About...") ) + wxT('\t') + wxT("F1"), wxEmptyString, wxITEM_NORMAL ); - m_menu33->Append( m_menuItemAbout ); + m_menuItemAbout = new wxMenuItem( m_menuHelp, wxID_ABOUT, wxString( _("&About...") ) + wxT('\t') + wxT("F1"), wxEmptyString, wxITEM_NORMAL ); + m_menuHelp->Append( m_menuItemAbout ); - m_menubar1->Append( m_menu33, _("&Help") ); + m_menubar1->Append( m_menuHelp, _("&Help") ); this->SetMenuBar( m_menubar1 ); @@ -128,7 +131,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer30->Add( m_buttonCompare, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - m_buttonAbort = new wxButton( m_panel71, wxID_CANCEL, _("Abort"), wxDefaultPosition, wxSize( 180,37 ), 0 ); + m_buttonAbort = new wxButton( m_panel71, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( 180,37 ), 0 ); m_buttonAbort->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Tahoma") ) ); m_buttonAbort->Enable( false ); m_buttonAbort->Hide(); @@ -226,26 +229,28 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer91; bSizer91 = new wxBoxSizer( wxHORIZONTAL ); - m_panel11 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelTopLeft = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer92; bSizer92 = new wxBoxSizer( wxVERTICAL ); - sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( m_panel11, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( m_panelTopLeft, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + + m_directoryLeft = new wxComboBox( m_panelTopLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + sbSizer2->Add( m_directoryLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); - m_comboBoxDirLeft = new wxComboBox( m_panel11, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); - sbSizer2->Add( m_comboBoxDirLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); + m_dirPickerLeft = new wxDirPickerCtrl( m_panelTopLeft, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); + m_dirPickerLeft->SetToolTip( _("Select a folder") ); - m_dirPickerLeft = new wxDirPickerCtrl( m_panel11, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); sbSizer2->Add( m_dirPickerLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer92->Add( sbSizer2, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - m_panel11->SetSizer( bSizer92 ); - m_panel11->Layout(); - bSizer92->Fit( m_panel11 ); - bSizer91->Add( m_panel11, 1, wxALIGN_CENTER_VERTICAL, 5 ); + m_panelTopLeft->SetSizer( bSizer92 ); + m_panelTopLeft->Layout(); + bSizer92->Fit( m_panelTopLeft ); + bSizer91->Add( m_panelTopLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); - m_panel13 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelTopMiddle = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer93; bSizer93 = new wxBoxSizer( wxVERTICAL ); @@ -254,7 +259,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizerMiddle = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonSwap = new wxBitmapButton( m_panel13, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButtonSwap = new wxBitmapButton( m_panelTopMiddle, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); m_bpButtonSwap->SetToolTip( _("Swap sides") ); m_bpButtonSwap->SetToolTip( _("Swap sides") ); @@ -266,12 +271,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer93->Add( 0, 0, 0, 0, 5 ); - m_panel13->SetSizer( bSizer93 ); - m_panel13->Layout(); - bSizer93->Fit( m_panel13 ); - bSizer91->Add( m_panel13, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + m_panelTopMiddle->SetSizer( bSizer93 ); + m_panelTopMiddle->Layout(); + bSizer93->Fit( m_panelTopMiddle ); + bSizer91->Add( m_panelTopMiddle, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - m_panel12 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelTopRight = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer94; bSizer94 = new wxBoxSizer( wxVERTICAL ); @@ -284,7 +289,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer781->Add( 0, 3, 0, 0, 5 ); - m_bpButtonAddPair = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 19,21 ), wxBU_AUTODRAW ); + m_bpButtonAddPair = new wxBitmapButton( m_panelTopRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 19,21 ), wxBU_AUTODRAW ); m_bpButtonAddPair->SetToolTip( _("Add folder pair") ); m_bpButtonAddPair->SetToolTip( _("Add folder pair") ); @@ -294,22 +299,24 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer77->Add( bSizer781, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); wxStaticBoxSizer* sbSizer3; - sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panel12, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelTopRight, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + + m_directoryRight = new wxComboBox( m_panelTopRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + sbSizer3->Add( m_directoryRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); - m_comboBoxDirRight = new wxComboBox( m_panel12, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); - sbSizer3->Add( m_comboBoxDirRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); + m_dirPickerRight = new wxDirPickerCtrl( m_panelTopRight, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); + m_dirPickerRight->SetToolTip( _("Select a folder") ); - m_dirPickerRight = new wxDirPickerCtrl( m_panel12, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); sbSizer3->Add( m_dirPickerRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer77->Add( sbSizer3, 1, wxRIGHT|wxLEFT, 3 ); bSizer94->Add( bSizer77, 0, wxEXPAND, 5 ); - m_panel12->SetSizer( bSizer94 ); - m_panel12->Layout(); - bSizer94->Fit( m_panel12 ); - bSizer91->Add( m_panel12, 1, wxALIGN_CENTER_VERTICAL, 5 ); + m_panelTopRight->SetSizer( bSizer94 ); + m_panelTopRight->Layout(); + bSizer94->Fit( m_panelTopRight ); + bSizer91->Add( m_panelTopRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); bSizer1->Add( bSizer91, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -337,11 +344,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer2; bSizer2 = new wxBoxSizer( wxHORIZONTAL ); - m_panel1 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelLeft = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer7; bSizer7 = new wxBoxSizer( wxVERTICAL ); - m_gridLeft = new CustomGridLeft( m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridLeft = new CustomGridLeft( m_panelLeft, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid m_gridLeft->CreateGrid( 15, 4 ); @@ -367,16 +374,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_gridLeft->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTRE ); bSizer7->Add( m_gridLeft, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, 5 ); - m_panel1->SetSizer( bSizer7 ); - m_panel1->Layout(); - bSizer7->Fit( m_panel1 ); - bSizer2->Add( m_panel1, 1, wxEXPAND, 5 ); + m_panelLeft->SetSizer( bSizer7 ); + m_panelLeft->Layout(); + bSizer7->Fit( m_panelLeft ); + bSizer2->Add( m_panelLeft, 1, wxEXPAND, 5 ); - m_panel3 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelMiddle = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer18; bSizer18 = new wxBoxSizer( wxVERTICAL ); - m_gridMiddle = new CustomGridMiddle( m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridMiddle = new CustomGridMiddle( m_panelMiddle, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid m_gridMiddle->CreateGrid( 15, 1 ); @@ -404,16 +411,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_gridMiddle->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); bSizer18->Add( m_gridMiddle, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 ); - m_panel3->SetSizer( bSizer18 ); - m_panel3->Layout(); - bSizer18->Fit( m_panel3 ); - bSizer2->Add( m_panel3, 0, wxRIGHT|wxLEFT|wxEXPAND, 5 ); + m_panelMiddle->SetSizer( bSizer18 ); + m_panelMiddle->Layout(); + bSizer18->Fit( m_panelMiddle ); + bSizer2->Add( m_panelMiddle, 0, wxRIGHT|wxLEFT|wxEXPAND, 5 ); - m_panel2 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelRight = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer10; bSizer10 = new wxBoxSizer( wxVERTICAL ); - m_gridRight = new CustomGridRight( m_panel2, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_gridRight = new CustomGridRight( m_panelRight, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid m_gridRight->CreateGrid( 15, 4 ); @@ -439,10 +446,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_gridRight->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTRE ); bSizer10->Add( m_gridRight, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, 5 ); - m_panel2->SetSizer( bSizer10 ); - m_panel2->Layout(); - bSizer10->Fit( m_panel2 ); - bSizer2->Add( m_panel2, 1, wxEXPAND, 5 ); + m_panelRight->SetSizer( bSizer10 ); + m_panelRight->Layout(); + bSizer10->Fit( m_panelRight ); + bSizer2->Add( m_panelRight, 1, wxEXPAND, 5 ); bSizer1->Add( bSizer2, 1, wxEXPAND, 5 ); @@ -623,11 +630,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const this->Connect( m_menuItemEnglish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangEnglish ) ); this->Connect( m_menuItemSpanish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangSpanish ) ); this->Connect( m_menuItemFrench->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangFrench ) ); - this->Connect( m_menuItemHungarian->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangHungarian ) ); this->Connect( m_menuItemItalian->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangItalian ) ); - this->Connect( m_menuItemPolish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPolish ) ); + this->Connect( m_menuItemHungarian->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangHungarian ) ); this->Connect( m_menuItemDutch->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangDutch ) ); + this->Connect( m_menuItemPolish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPolish ) ); this->Connect( m_menuItemPortuguese->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPortuguese ) ); + this->Connect( m_menuItemPortugueseBrazil->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPortugueseBrazil ) ); this->Connect( m_menuItemSlovenian->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangSlovenian ) ); this->Connect( m_menuItemJapanese->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangJapanese ) ); this->Connect( m_menuItemChineseSimple->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangChineseSimp ) ); @@ -645,13 +653,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_hyperlinkCfgFilter->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxHideFilt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); m_buttonSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); - m_comboBoxDirLeft->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); - m_comboBoxDirLeft->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_directoryLeft->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerLeft->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); m_bpButtonSwap->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); m_bpButtonAddPair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); - m_comboBoxDirRight->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); - m_comboBoxDirRight->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_directoryRight->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerRight->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); m_gridLeft->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnLeftGridDoubleClick ), NULL, this ); m_gridLeft->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnContextMenu ), NULL, this ); @@ -689,11 +695,12 @@ MainDialogGenerated::~MainDialogGenerated() this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangEnglish ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangSpanish ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangFrench ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangHungarian ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangItalian ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPolish ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangHungarian ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangDutch ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPolish ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPortuguese ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangPortugueseBrazil ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangSlovenian ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangJapanese ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangChineseSimp ) ); @@ -711,13 +718,11 @@ MainDialogGenerated::~MainDialogGenerated() m_hyperlinkCfgFilter->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxHideFilt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); m_buttonSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); - m_comboBoxDirLeft->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); - m_comboBoxDirLeft->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_directoryLeft->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerLeft->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); m_bpButtonSwap->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); m_bpButtonAddPair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); - m_comboBoxDirRight->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); - m_comboBoxDirRight->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_directoryRight->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerRight->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); m_gridLeft->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnLeftGridDoubleClick ), NULL, this ); m_gridLeft->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnContextMenu ), NULL, this ); @@ -754,7 +759,9 @@ FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const m_directoryLeft = new wxTextCtrl( m_panelLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); sbSizer21->Add( m_directoryLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); - m_dirPickerLeft = new wxDirPickerCtrl( m_panelLeft, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); + m_dirPickerLeft = new wxDirPickerCtrl( m_panelLeft, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); + m_dirPickerLeft->SetToolTip( _("Select a folder") ); + sbSizer21->Add( m_dirPickerLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_panelLeft->SetSizer( sbSizer21 ); @@ -785,7 +792,7 @@ FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const m_panel21->SetSizer( bSizer96 ); m_panel21->Layout(); bSizer96->Fit( m_panel21 ); - bSizer95->Add( m_panel21, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + bSizer95->Add( m_panel21, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); m_panel20->SetSizer( bSizer95 ); m_panel20->Layout(); @@ -809,7 +816,9 @@ FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const m_directoryRight = new wxTextCtrl( m_panelRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); sbSizer23->Add( m_directoryRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); - m_dirPickerRight = new wxDirPickerCtrl( m_panelRight, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST ); + m_dirPickerRight = new wxDirPickerCtrl( m_panelRight, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); + m_dirPickerRight->SetToolTip( _("Select a folder") ); + sbSizer23->Add( m_dirPickerRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer105->Add( sbSizer23, 1, wxALIGN_CENTER_VERTICAL|wxLEFT, 3 ); @@ -822,15 +831,78 @@ FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const this->SetSizer( bSizer74 ); this->Layout(); bSizer74->Fit( this ); - - // Connect Events - m_bpButtonRemovePair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FolderPairGenerated::OnRemoveFolderPair ), NULL, this ); } FolderPairGenerated::~FolderPairGenerated() { - // Disconnect Events - m_bpButtonRemovePair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FolderPairGenerated::OnRemoveFolderPair ), NULL, this ); +} + +BatchFolderPairGenerated::BatchFolderPairGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +{ + wxStaticBoxSizer* sbSizer20; + sbSizer20 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxVERTICAL ); + + wxFlexGridSizer* fgSizer9; + fgSizer9 = new wxFlexGridSizer( 2, 2, 5, 5 ); + fgSizer9->AddGrowableCol( 1 ); + fgSizer9->SetFlexibleDirection( wxHORIZONTAL ); + fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText53 = new wxStaticText( this, wxID_ANY, _("Left:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText53->Wrap( -1 ); + m_staticText53->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); + + fgSizer9->Add( m_staticText53, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_panelLeft = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer114; + bSizer114 = new wxBoxSizer( wxHORIZONTAL ); + + m_directoryLeft = new wxTextCtrl( m_panelLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer114->Add( m_directoryLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_dirPickerLeft = new wxDirPickerCtrl( m_panelLeft, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); + m_dirPickerLeft->SetToolTip( _("Select a folder") ); + + bSizer114->Add( m_dirPickerLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_panelLeft->SetSizer( bSizer114 ); + m_panelLeft->Layout(); + bSizer114->Fit( m_panelLeft ); + fgSizer9->Add( m_panelLeft, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_staticText541 = new wxStaticText( this, wxID_ANY, _("Right:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText541->Wrap( -1 ); + m_staticText541->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); + + fgSizer9->Add( m_staticText541, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_panelRight = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer115; + bSizer115 = new wxBoxSizer( wxHORIZONTAL ); + + m_directoryRight = new wxTextCtrl( m_panelRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer115->Add( m_directoryRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_dirPickerRight = new wxDirPickerCtrl( m_panelRight, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); + m_dirPickerRight->SetToolTip( _("Select a folder") ); + + bSizer115->Add( m_dirPickerRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_panelRight->SetSizer( bSizer115 ); + m_panelRight->Layout(); + bSizer115->Fit( m_panelRight ); + fgSizer9->Add( m_panelRight, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); + + sbSizer20->Add( fgSizer9, 0, wxEXPAND, 5 ); + + this->SetSizer( sbSizer20 ); + this->Layout(); + sbSizer20->Fit( this ); +} + +BatchFolderPairGenerated::~BatchFolderPairGenerated() +{ } BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -891,13 +963,18 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer69->Add( m_staticText531, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); + m_notebookSettings = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_panelOverview = new wxPanel( m_notebookSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer67; bSizer67 = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer120; + bSizer120 = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer100; bSizer100 = new wxBoxSizer( wxVERTICAL ); - m_scrolledWindow6 = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL ); + m_scrolledWindow6 = new wxScrolledWindow( m_panelOverview, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL ); m_scrolledWindow6->SetScrollRate( 5, 5 ); bSizerFolderPairs = new wxBoxSizer( wxVERTICAL ); @@ -919,15 +996,15 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer721 = new wxBoxSizer( wxVERTICAL ); wxStaticBoxSizer* sbSizer6; - sbSizer6 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Compare by...") ), wxVERTICAL ); + sbSizer6 = new wxStaticBoxSizer( new wxStaticBox( m_panelOverview, wxID_ANY, _("Compare by...") ), wxVERTICAL ); - m_radioBtnSizeDate = new wxRadioButton( this, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnSizeDate = new wxRadioButton( m_panelOverview, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, 0 ); m_radioBtnSizeDate->SetValue( true ); m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time and date\nare the same.") ); sbSizer6->Add( m_radioBtnSizeDate, 0, 0, 5 ); - m_radioBtnContent = new wxRadioButton( this, wxID_ANY, _("File content"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnContent = new wxRadioButton( m_panelOverview, wxID_ANY, _("File content"), wxDefaultPosition, wxDefaultSize, 0 ); m_radioBtnContent->SetToolTip( _("Files are found equal if\n - file content\nis the same.") ); sbSizer6->Add( m_radioBtnContent, 0, wxTOP, 5 ); @@ -938,104 +1015,77 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer721->Add( 0, 10, 0, 0, 5 ); wxStaticBoxSizer* sbSizer25; - sbSizer25 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Error handling") ), wxVERTICAL ); + sbSizer25 = new wxStaticBoxSizer( new wxStaticBox( m_panelOverview, wxID_ANY, _("Error handling") ), wxVERTICAL ); wxArrayString m_choiceHandleErrorChoices; - m_choiceHandleError = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceHandleErrorChoices, 0 ); + m_choiceHandleError = new wxChoice( m_panelOverview, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceHandleErrorChoices, 0 ); m_choiceHandleError->SetSelection( 0 ); sbSizer25->Add( m_choiceHandleError, 0, wxALL, 5 ); bSizer721->Add( sbSizer25, 1, wxEXPAND, 5 ); + bSizer71->Add( bSizer721, 0, 0, 5 ); - bSizer721->Add( 0, 10, 0, 0, 5 ); - - wxStaticBoxSizer* sbSizer24; - sbSizer24 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxVERTICAL ); - - m_checkBoxUseRecycler = new wxCheckBox( this, wxID_ANY, _("Use Recycle Bin"), wxDefaultPosition, wxDefaultSize, 0 ); - - m_checkBoxUseRecycler->SetToolTip( _("Use Recycle Bin when deleting or overwriting files during synchronization") ); - - sbSizer24->Add( m_checkBoxUseRecycler, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - m_checkBoxSilent = new wxCheckBox( this, wxID_ANY, _("Silent mode"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer71->Add( 10, 0, 1, wxEXPAND, 5 ); - m_checkBoxSilent->SetToolTip( _("Do not show graphical status and error messages but write to a logfile instead") ); + wxStaticBoxSizer* sbSizer24; + sbSizer24 = new wxStaticBoxSizer( new wxStaticBox( m_panelOverview, wxID_ANY, wxEmptyString ), wxVERTICAL ); - sbSizer24->Add( m_checkBoxSilent, 0, wxALL, 5 ); - bSizer721->Add( sbSizer24, 0, wxEXPAND, 5 ); + sbSizer24->Add( 0, 0, 1, wxEXPAND, 5 ); - bSizer71->Add( bSizer721, 0, 0, 5 ); + m_checkBoxUseRecycler = new wxCheckBox( m_panelOverview, wxID_ANY, _("Use Recycle Bin"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer57->Add( bSizer71, 0, wxEXPAND, 5 ); - - - bSizer57->Add( 10, 0, 1, wxEXPAND, 5 ); + m_checkBoxUseRecycler->SetToolTip( _("Use Recycle Bin when deleting or overwriting files during synchronization") ); - wxStaticBoxSizer* sbSizer8; - sbSizer8 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Filter files") ), wxHORIZONTAL ); + sbSizer24->Add( m_checkBoxUseRecycler, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - m_bpButtonFilter = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW|wxFULL_REPAINT_ON_RESIZE ); - sbSizer8->Add( m_bpButtonFilter, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + m_checkBoxFilter = new wxCheckBox( m_panelOverview, wxID_ANY, _("Filter files"), wxDefaultPosition, wxDefaultSize, 0 ); - wxBoxSizer* bSizer101; - bSizer101 = new wxBoxSizer( wxVERTICAL ); + m_checkBoxFilter->SetToolTip( _("Enable filter to exclude files from synchronization") ); - wxBoxSizer* bSizer671; - bSizer671 = new wxBoxSizer( wxHORIZONTAL ); + sbSizer24->Add( m_checkBoxFilter, 0, wxALL, 5 ); - m_bitmap8 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); - m_bitmap8->SetToolTip( _("Include") ); + m_checkBoxSilent = new wxCheckBox( m_panelOverview, wxID_ANY, _("Silent mode"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer671->Add( m_bitmap8, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); - - m_textCtrlInclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 250,-1 ), wxTE_MULTILINE ); - bSizer671->Add( m_textCtrlInclude, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer101->Add( bSizer671, 0, 0, 5 ); + m_checkBoxSilent->SetToolTip( _("Do not display visual status information but write to a logfile instead") ); + sbSizer24->Add( m_checkBoxSilent, 0, wxALL, 5 ); - bSizer101->Add( 0, 10, 0, 0, 5 ); - wxBoxSizer* bSizer691; - bSizer691 = new wxBoxSizer( wxHORIZONTAL ); + sbSizer24->Add( 0, 0, 1, wxEXPAND, 5 ); - m_bitmap9 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); - m_bitmap9->SetToolTip( _("Exclude") ); + bSizer71->Add( sbSizer24, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); - bSizer691->Add( m_bitmap9, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); - m_textCtrlExclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 250,-1 ), wxTE_MULTILINE ); - bSizer691->Add( m_textCtrlExclude, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer71->Add( 150, 0, 0, 0, 5 ); - bSizer101->Add( bSizer691, 0, 0, 5 ); + bSizer57->Add( bSizer71, 0, wxEXPAND, 5 ); - sbSizer8->Add( bSizer101, 1, wxEXPAND, 5 ); - bSizer57->Add( sbSizer8, 0, 0, 5 ); + bSizer57->Add( 10, 0, 1, wxEXPAND, 5 ); bSizer100->Add( bSizer57, 0, 0, 5 ); - bSizer67->Add( bSizer100, 0, 0, 5 ); + bSizer120->Add( bSizer100, 1, 0, 5 ); - bSizer67->Add( 10, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer120->Add( 10, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); wxStaticBoxSizer* sbSizer61; - sbSizer61 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Configuration") ), wxVERTICAL ); + sbSizer61 = new wxStaticBoxSizer( new wxStaticBox( m_panelOverview, wxID_ANY, _("Configuration") ), wxVERTICAL ); wxGridSizer* gSizer3; gSizer3 = new wxGridSizer( 1, 2, 0, 5 ); - m_staticText211 = new wxStaticText( this, wxID_ANY, _("Result"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText211 = new wxStaticText( m_panelOverview, wxID_ANY, _("Result"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText211->Wrap( -1 ); m_staticText211->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); gSizer3->Add( m_staticText211, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText311 = new wxStaticText( this, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText311 = new wxStaticText( m_panelOverview, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText311->Wrap( -1 ); m_staticText311->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); @@ -1043,60 +1093,159 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS sbSizer61->Add( gSizer3, 0, wxEXPAND, 5 ); - m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + m_staticline3 = new wxStaticLine( m_panelOverview, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); sbSizer61->Add( m_staticline3, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 ); wxGridSizer* gSizer1; gSizer1 = new wxGridSizer( 5, 2, 0, 5 ); - m_bitmap13 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmap13 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); m_bitmap13->SetToolTip( _("Files/folders that exist on left side only") ); gSizer1->Add( m_bitmap13, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton5 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButton5 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); gSizer1->Add( m_bpButton5, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap14 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmap14 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); m_bitmap14->SetToolTip( _("Files/folders that exist on right side only") ); gSizer1->Add( m_bitmap14, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton6 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButton6 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); gSizer1->Add( m_bpButton6, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap15 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmap15 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); m_bitmap15->SetToolTip( _("Files that exist on both sides, left one is newer") ); gSizer1->Add( m_bitmap15, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton7 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButton7 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); gSizer1->Add( m_bpButton7, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap16 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmap16 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); m_bitmap16->SetToolTip( _("Files that exist on both sides, right one is newer") ); gSizer1->Add( m_bitmap16, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton8 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButton8 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); gSizer1->Add( m_bpButton8, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap17 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmap17 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); m_bitmap17->SetToolTip( _("dummy") ); gSizer1->Add( m_bitmap17, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton9 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + m_bpButton9 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); gSizer1->Add( m_bpButton9, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); sbSizer61->Add( gSizer1, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); - bSizer67->Add( sbSizer61, 0, 0, 5 ); + bSizer120->Add( sbSizer61, 0, 0, 5 ); + + bSizer67->Add( bSizer120, 1, wxALL, 10 ); + + m_panelOverview->SetSizer( bSizer67 ); + m_panelOverview->Layout(); + bSizer67->Fit( m_panelOverview ); + m_notebookSettings->AddPage( m_panelOverview, _("Overview"), true ); + m_panelFilter = new wxPanel( m_notebookSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer114; + bSizer114 = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* sbSizer8; + sbSizer8 = new wxStaticBoxSizer( new wxStaticBox( m_panelFilter, wxID_ANY, wxEmptyString ), wxVERTICAL ); + + wxFlexGridSizer* fgSizer3; + fgSizer3 = new wxFlexGridSizer( 2, 2, 0, 0 ); + fgSizer3->AddGrowableCol( 1 ); + fgSizer3->AddGrowableRow( 1 ); + fgSizer3->SetFlexibleDirection( wxBOTH ); + fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + + fgSizer3->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_staticText15 = new wxStaticText( m_panelFilter, wxID_ANY, _("Include"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText15->Wrap( -1 ); + m_staticText15->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + + fgSizer3->Add( m_staticText15, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_bitmap8 = new wxStaticBitmap( m_panelFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); + m_bitmap8->SetToolTip( _("Include") ); + + fgSizer3->Add( m_bitmap8, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_textCtrlInclude = new wxTextCtrl( m_panelFilter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + fgSizer3->Add( m_textCtrlInclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + sbSizer8->Add( fgSizer3, 0, wxEXPAND, 5 ); + + wxFlexGridSizer* fgSizer4; + fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 ); + fgSizer4->AddGrowableCol( 1 ); + fgSizer4->AddGrowableRow( 1 ); + fgSizer4->SetFlexibleDirection( wxBOTH ); + fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + + fgSizer4->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_staticText16 = new wxStaticText( m_panelFilter, wxID_ANY, _("Exclude"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText16->Wrap( -1 ); + m_staticText16->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + + fgSizer4->Add( m_staticText16, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_bitmap9 = new wxStaticBitmap( m_panelFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); + m_bitmap9->SetToolTip( _("Exclude") ); - bSizer69->Add( bSizer67, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + fgSizer4->Add( m_bitmap9, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_staticline9 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizer69->Add( m_staticline9, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); + m_textCtrlExclude = new wxTextCtrl( m_panelFilter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + fgSizer4->Add( m_textCtrlExclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + sbSizer8->Add( fgSizer4, 0, wxEXPAND, 5 ); + + bSizer114->Add( sbSizer8, 1, wxALL|wxEXPAND, 10 ); + + m_panelFilter->SetSizer( bSizer114 ); + m_panelFilter->Layout(); + bSizer114->Fit( m_panelFilter ); + m_notebookSettings->AddPage( m_panelFilter, _("Filter"), false ); + m_panelLogging = new wxPanel( m_notebookSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer117; + bSizer117 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer119; + bSizer119 = new wxBoxSizer( wxVERTICAL ); + + m_staticText120 = new wxStaticText( m_panelLogging, wxID_ANY, _("Select logfile directory:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText120->Wrap( -1 ); + bSizer119->Add( m_staticText120, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + wxStaticBoxSizer* sbSizer251; + sbSizer251 = new wxStaticBoxSizer( new wxStaticBox( m_panelLogging, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + + m_textCtrlLogfileDir = new wxTextCtrl( m_panelLogging, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + sbSizer251->Add( m_textCtrlLogfileDir, 1, wxALIGN_CENTER_VERTICAL, 5 ); + + m_dirPickerLogfileDir = new wxDirPickerCtrl( m_panelLogging, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); + m_dirPickerLogfileDir->SetToolTip( _("Select a folder") ); + + sbSizer251->Add( m_dirPickerLogfileDir, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer119->Add( sbSizer251, 1, wxEXPAND, 5 ); + + bSizer117->Add( bSizer119, 0, wxEXPAND|wxALL, 10 ); + + m_panelLogging->SetSizer( bSizer117 ); + m_panelLogging->Layout(); + bSizer117->Fit( m_panelLogging ); + m_notebookSettings->AddPage( m_panelLogging, _("Logging"), false ); + + bSizer69->Add( m_notebookSettings, 1, wxEXPAND, 5 ); wxBoxSizer* bSizer68; bSizer68 = new wxBoxSizer( wxHORIZONTAL ); @@ -1119,7 +1268,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer69->Add( bSizer68, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - bSizer54->Add( bSizer69, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); + bSizer54->Add( bSizer69, 1, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5 ); this->SetSizer( bSizer54 ); this->Layout(); @@ -1133,7 +1282,8 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_radioBtnContent->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeCompareVar ), NULL, this ); m_choiceHandleError->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeErrorHandling ), NULL, this ); m_checkBoxUseRecycler->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSelectRecycleBin ), NULL, this ); - m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnFilterButton ), NULL, this ); + m_checkBoxFilter->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckFilter ), NULL, this ); + m_checkBoxSilent->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckLogging ), NULL, this ); m_bpButton5->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); m_bpButton6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); m_bpButton7->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); @@ -1152,7 +1302,8 @@ BatchDlgGenerated::~BatchDlgGenerated() m_radioBtnContent->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeCompareVar ), NULL, this ); m_choiceHandleError->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeErrorHandling ), NULL, this ); m_checkBoxUseRecycler->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSelectRecycleBin ), NULL, this ); - m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnFilterButton ), NULL, this ); + m_checkBoxFilter->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckFilter ), NULL, this ); + m_checkBoxSilent->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckLogging ), NULL, this ); m_bpButton5->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); m_bpButton6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); m_bpButton7->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); @@ -1163,53 +1314,6 @@ BatchDlgGenerated::~BatchDlgGenerated() m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); } -BatchFolderPairGenerated::BatchFolderPairGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) -{ - wxStaticBoxSizer* sbSizer20; - sbSizer20 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxVERTICAL ); - - wxFlexGridSizer* fgSizer9; - fgSizer9 = new wxFlexGridSizer( 2, 2, 5, 5 ); - fgSizer9->AddGrowableCol( 1 ); - fgSizer9->SetFlexibleDirection( wxHORIZONTAL ); - fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - - m_staticText53 = new wxStaticText( this, wxID_ANY, _("Left folder:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText53->Wrap( -1 ); - m_staticText53->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); - - fgSizer9->Add( m_staticText53, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); - - m_directoryLeft = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer9->Add( m_directoryLeft, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - - m_staticText541 = new wxStaticText( this, wxID_ANY, _("Right folder:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText541->Wrap( -1 ); - m_staticText541->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); - - fgSizer9->Add( m_staticText541, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); - - m_directoryRight = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer9->Add( m_directoryRight, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - - sbSizer20->Add( fgSizer9, 0, wxEXPAND, 5 ); - - this->SetSizer( sbSizer20 ); - this->Layout(); - sbSizer20->Fit( this ); - - // Connect Events - m_directoryLeft->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchFolderPairGenerated::OnEnterLeftDir ), NULL, this ); - m_directoryRight->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchFolderPairGenerated::OnEnterRightDir ), NULL, this ); -} - -BatchFolderPairGenerated::~BatchFolderPairGenerated() -{ - // Disconnect Events - m_directoryLeft->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchFolderPairGenerated::OnEnterLeftDir ), NULL, this ); - m_directoryRight->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchFolderPairGenerated::OnEnterRightDir ), NULL, this ); -} - CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) { wxBoxSizer* bSizer40; @@ -1220,55 +1324,84 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, wxStaticBoxSizer* sbSizer10; sbSizer10 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxHORIZONTAL ); + wxBoxSizer* bSizer118; + bSizer118 = new wxBoxSizer( wxHORIZONTAL ); + m_staticText321 = new wxStaticText( this, wxID_ANY, _("Files/folders scanned:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText321->Wrap( -1 ); - m_staticText321->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + m_staticText321->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Arial") ) ); - sbSizer10->Add( m_staticText321, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxRIGHT, 5 ); + bSizer118->Add( m_staticText321, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 5 ); m_staticTextScanned = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextScanned->Wrap( -1 ); - m_staticTextScanned->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextScanned->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + bSizer118->Add( m_staticTextScanned, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); - sbSizer10->Add( m_staticTextScanned, 0, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizer10->Add( bSizer118, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer42->Add( sbSizer10, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + bSizer42->Add( sbSizer10, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); sbSizer13 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Comparing content") ), wxVERTICAL ); - wxFlexGridSizer* fgSizer8; - fgSizer8 = new wxFlexGridSizer( 2, 2, 3, 0 ); - fgSizer8->SetFlexibleDirection( wxBOTH ); - fgSizer8->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + wxFlexGridSizer* fgSizer12; + fgSizer12 = new wxFlexGridSizer( 2, 4, 3, 5 ); + fgSizer12->SetFlexibleDirection( wxBOTH ); + fgSizer12->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_staticText46 = new wxStaticText( this, wxID_ANY, _("Files remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText46->Wrap( -1 ); - m_staticText46->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + m_staticText46->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Arial") ) ); - fgSizer8->Add( m_staticText46, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + fgSizer12->Add( m_staticText46, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextFilesToCompare = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextFilesToCompare->Wrap( -1 ); - m_staticTextFilesToCompare->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextFilesRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextFilesRemaining->Wrap( -1 ); + m_staticTextFilesRemaining->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); - fgSizer8->Add( m_staticTextFilesToCompare, 0, wxALIGN_CENTER_VERTICAL, 5 ); + fgSizer12->Add( m_staticTextFilesRemaining, 0, wxALIGN_BOTTOM, 5 ); m_staticText32 = new wxStaticText( this, wxID_ANY, _("Data remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText32->Wrap( -1 ); - m_staticText32->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + m_staticText32->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Arial") ) ); + + fgSizer12->Add( m_staticText32, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextDataRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDataRemaining->Wrap( -1 ); + m_staticTextDataRemaining->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); - fgSizer8->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + fgSizer12->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextDataToCompare = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextDataToCompare->Wrap( -1 ); - m_staticTextDataToCompare->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticText104 = new wxStaticText( this, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText104->Wrap( -1 ); + m_staticText104->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Arial") ) ); - fgSizer8->Add( m_staticTextDataToCompare, 0, wxALIGN_CENTER_VERTICAL, 5 ); + fgSizer12->Add( m_staticText104, 0, wxALIGN_BOTTOM, 5 ); - sbSizer13->Add( fgSizer8, 0, 0, 5 ); + m_staticTextSpeed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSpeed->Wrap( -1 ); + m_staticTextSpeed->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + fgSizer12->Add( m_staticTextSpeed, 0, wxALIGN_BOTTOM, 5 ); + + m_staticText103 = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText103->Wrap( -1 ); + m_staticText103->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Arial") ) ); + + fgSizer12->Add( m_staticText103, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextTimeRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeRemaining->Wrap( -1 ); + m_staticTextTimeRemaining->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + fgSizer12->Add( m_staticTextTimeRemaining, 0, wxALIGN_BOTTOM, 5 ); + + sbSizer13->Add( fgSizer12, 1, wxEXPAND, 5 ); bSizer42->Add( sbSizer13, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -1278,17 +1411,22 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, wxStaticBoxSizer* sbSizer131; sbSizer131 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxHORIZONTAL ); + wxBoxSizer* bSizer117; + bSizer117 = new wxBoxSizer( wxHORIZONTAL ); + m_staticText37 = new wxStaticText( this, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText37->Wrap( -1 ); - m_staticText37->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + m_staticText37->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Arial") ) ); - sbSizer131->Add( m_staticText37, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + bSizer117->Add( m_staticText37, 0, wxALIGN_BOTTOM, 5 ); m_staticTextTimeElapsed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextTimeElapsed->Wrap( -1 ); - m_staticTextTimeElapsed->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextTimeElapsed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - sbSizer131->Add( m_staticTextTimeElapsed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer117->Add( m_staticTextTimeElapsed, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); + + sbSizer131->Add( bSizer117, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer42->Add( sbSizer131, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); @@ -1623,7 +1761,7 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr sbSizer6->Add( gSizer1, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); - bSizer181->Add( sbSizer6, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 5 ); + bSizer181->Add( sbSizer6, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); bSizer7->Add( bSizer181, 0, wxALL, 5 ); @@ -1689,7 +1827,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, bSizer37 = new wxBoxSizer( wxHORIZONTAL ); m_animationControl1 = new wxAnimationCtrl(this, wxID_ANY, wxNullAnimation, wxDefaultPosition, wxSize( 45,45 )); - bSizer37->Add( m_animationControl1, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer37->Add( m_animationControl1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_panel8 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER|wxTAB_TRAVERSAL ); m_panel8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT ) ); @@ -1706,7 +1844,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, m_panel8->SetSizer( bSizer72 ); m_panel8->Layout(); bSizer72->Fit( m_panel8 ); - bSizer37->Add( m_panel8, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer37->Add( m_panel8, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); bSizer27->Add( bSizer37, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -1736,51 +1874,72 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, m_staticText21->Wrap( -1 ); m_staticText21->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer31->Add( m_staticText21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer31->Add( m_staticText21, 0, wxALIGN_BOTTOM, 5 ); bSizer31->Add( 0, 0, 1, wxEXPAND, 5 ); m_staticText55 = new wxStaticText( this, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText55->Wrap( -1 ); - m_staticText55->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); + m_staticText55->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer31->Add( m_staticText55, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 5 ); + bSizer31->Add( m_staticText55, 0, wxALIGN_BOTTOM, 5 ); m_staticTextTimeElapsed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextTimeElapsed->Wrap( -1 ); - m_staticTextTimeElapsed->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextTimeElapsed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - bSizer31->Add( m_staticTextTimeElapsed, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer31->Add( m_staticTextTimeElapsed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer27->Add( bSizer31, 0, wxEXPAND, 5 ); + bSizer27->Add( bSizer31, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); m_textCtrlInfo = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY ); m_textCtrlInfo->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); - bSizer27->Add( m_textCtrlInfo, 3, wxALL|wxEXPAND, 5 ); + bSizer27->Add( m_textCtrlInfo, 3, wxEXPAND|wxALL, 5 ); m_gauge1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxSize( -1,20 ), wxGA_HORIZONTAL ); - bSizer27->Add( m_gauge1, 0, wxALL|wxEXPAND, 5 ); + bSizer27->Add( m_gauge1, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); bSizer28 = new wxBoxSizer( wxHORIZONTAL ); - wxBoxSizer* bSizer33; - bSizer33 = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer111; + bSizer111 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer113; + bSizer113 = new wxBoxSizer( wxHORIZONTAL ); m_staticText25 = new wxStaticText( this, wxID_ANY, _("Files/folders remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText25->Wrap( -1 ); - m_staticText25->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); + m_staticText25->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer33->Add( m_staticText25, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + bSizer113->Add( m_staticText25, 0, wxALIGN_BOTTOM, 5 ); m_staticTextRemainingObj = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); m_staticTextRemainingObj->Wrap( -1 ); - m_staticTextRemainingObj->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextRemainingObj->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - bSizer33->Add( m_staticTextRemainingObj, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer113->Add( m_staticTextRemainingObj, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer28->Add( bSizer33, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer111->Add( bSizer113, 0, 0, 5 ); + + bSizerSpeed = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText108 = new wxStaticText( this, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText108->Wrap( -1 ); + m_staticText108->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + bSizerSpeed->Add( m_staticText108, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextSpeed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSpeed->Wrap( -1 ); + m_staticTextSpeed->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + bSizerSpeed->Add( m_staticTextSpeed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + bSizer111->Add( bSizerSpeed, 0, wxTOP, 5 ); + + bSizer28->Add( bSizer111, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer28->Add( 0, 0, 1, 0, 5 ); @@ -1794,35 +1953,55 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, m_buttonPause = new wxButton( this, wxID_ANY, _("&Pause"), wxDefaultPosition, wxSize( 100,32 ), 0 ); m_buttonPause->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer28->Add( m_buttonPause, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + bSizer28->Add( m_buttonPause, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); m_buttonAbort = new wxButton( this, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( 100,32 ), 0 ); - m_buttonAbort->SetDefault(); m_buttonAbort->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer28->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + bSizer28->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); bSizer28->Add( 0, 0, 1, 0, 5 ); - wxBoxSizer* bSizer32; - bSizer32 = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer114; + bSizer114 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer116; + bSizer116 = new wxBoxSizer( wxHORIZONTAL ); m_staticText26 = new wxStaticText( this, wxID_ANY, _("Data remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText26->Wrap( -1 ); - m_staticText26->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); + m_staticText26->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - bSizer32->Add( m_staticText26, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + bSizer116->Add( m_staticText26, 0, wxALIGN_BOTTOM, 5 ); m_staticTextDataRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextDataRemaining->Wrap( -1 ); - m_staticTextDataRemaining->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticTextDataRemaining->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + bSizer116->Add( m_staticTextDataRemaining, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer32->Add( m_staticTextDataRemaining, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + bSizer114->Add( bSizer116, 0, wxALIGN_RIGHT, 5 ); - bSizer28->Add( bSizer32, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizerRemTime = new wxBoxSizer( wxHORIZONTAL ); - bSizer27->Add( bSizer28, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); + m_staticText106 = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText106->Wrap( -1 ); + m_staticText106->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + bSizerRemTime->Add( m_staticText106, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextTimeRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeRemaining->Wrap( -1 ); + m_staticTextTimeRemaining->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Arial") ) ); + + bSizerRemTime->Add( m_staticTextTimeRemaining, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + bSizer114->Add( bSizerRemTime, 0, wxALIGN_RIGHT|wxTOP, 5 ); + + bSizer28->Add( bSizer114, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer27->Add( bSizer28, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxALL, 5 ); bSizer27->Add( 0, 5, 0, wxEXPAND, 5 ); @@ -2110,10 +2289,13 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer72->Add( 0, 5, 0, 0, 5 ); wxFlexGridSizer* fgSizer9; - fgSizer9 = new wxFlexGridSizer( 1, 2, 5, 20 ); + fgSizer9 = new wxFlexGridSizer( 1, 3, 5, 20 ); fgSizer9->SetFlexibleDirection( wxBOTH ); fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + m_bitmapFrench = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapFrench, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText68 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Jean-François Hartmann"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText68->Wrap( -1 ); fgSizer9->Add( m_staticText68, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2122,6 +2304,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText69->Wrap( -1 ); fgSizer9->Add( m_staticText69, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapJapanese = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapJapanese, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + m_staticText70 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Tilt"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText70->Wrap( -1 ); fgSizer9->Add( m_staticText70, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2130,6 +2315,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText71->Wrap( -1 ); fgSizer9->Add( m_staticText71, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapDutch = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapDutch, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText711 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("M.D. Vrakking"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText711->Wrap( -1 ); fgSizer9->Add( m_staticText711, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2138,6 +2326,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText712->Wrap( -1 ); fgSizer9->Add( m_staticText712, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapChineseSimple = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapChineseSimple, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + m_staticText91 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Misty Wu"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText91->Wrap( -1 ); fgSizer9->Add( m_staticText91, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2146,14 +2337,20 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText92->Wrap( -1 ); fgSizer9->Add( m_staticText92, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapPolish = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapPolish, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText911 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Wojtek Pietruszewski"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText911->Wrap( -1 ); fgSizer9->Add( m_staticText911, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText921 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Język Polski"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText921 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Polski"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText921->Wrap( -1 ); fgSizer9->Add( m_staticText921, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapPortuguese = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapPortuguese, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + m_staticText9211 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("QuestMark"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText9211->Wrap( -1 ); fgSizer9->Add( m_staticText9211, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2162,6 +2359,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText9212->Wrap( -1 ); fgSizer9->Add( m_staticText9212, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapItalian = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapItalian, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText92121 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Emmo"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText92121->Wrap( -1 ); fgSizer9->Add( m_staticText92121, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2170,6 +2370,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText92122->Wrap( -1 ); fgSizer9->Add( m_staticText92122, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapSlovenian = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapSlovenian, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText921221 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Matej Badalic"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText921221->Wrap( -1 ); fgSizer9->Add( m_staticText921221, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2178,14 +2381,20 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText921222->Wrap( -1 ); fgSizer9->Add( m_staticText921222, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapHungarian = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapHungarian, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticText682 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Demon"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText682->Wrap( -1 ); fgSizer9->Add( m_staticText682, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText681 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Magyar Nyelv"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText681 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Magyar"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText681->Wrap( -1 ); fgSizer9->Add( m_staticText681, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapSpanish = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapSpanish, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + m_staticText683 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("David Rodríguez"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText683->Wrap( -1 ); fgSizer9->Add( m_staticText683, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2194,6 +2403,17 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText691->Wrap( -1 ); fgSizer9->Add( m_staticText691, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapPortugueseBrazil = new wxStaticBitmap( m_scrolledWindow3, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,11 ), 0 ); + fgSizer9->Add( m_bitmapPortugueseBrazil, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText684 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Edison Aranha"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText684->Wrap( -1 ); + fgSizer9->Add( m_staticText684, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText685 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Português do Brasil"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText685->Wrap( -1 ); + fgSizer9->Add( m_staticText685, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer72->Add( fgSizer9, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); m_scrolledWindow3->SetSizer( bSizer72 ); @@ -2457,6 +2677,78 @@ WarningDlgGenerated::~WarningDlgGenerated() m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this ); } +QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizer24; + bSizer24 = new wxBoxSizer( wxVERTICAL ); + + + bSizer24->Add( 0, 10, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer26; + bSizer26 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); + m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + + bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxBOTTOM, 5 ); + + m_checkBoxDontAskAgain = new wxCheckBox( this, wxID_ANY, _("Don't ask me again"), wxDefaultPosition, wxDefaultSize, 0 ); + + bSizer24->Add( m_checkBoxDontAskAgain, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + + bSizer24->Add( 0, 10, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer25; + bSizer25 = new wxBoxSizer( wxHORIZONTAL ); + + m_buttonYes = new wxButton( this, wxID_YES, _("&Yes"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonYes->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer25->Add( m_buttonYes, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + + m_buttonNo = new wxButton( this, wxID_NO, _("&No"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonNo->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer25->Add( m_buttonNo, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonCancel->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer25->Add( m_buttonCancel, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + + + bSizer25->Add( 5, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer24->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + this->SetSizer( bSizer24 ); + this->Layout(); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( QuestionDlgGenerated::OnClose ) ); + m_buttonYes->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnYes ), NULL, this ); + m_buttonNo->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnNo ), NULL, this ); + m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnCancel ), NULL, this ); +} + +QuestionDlgGenerated::~QuestionDlgGenerated() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( QuestionDlgGenerated::OnClose ) ); + m_buttonYes->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnYes ), NULL, this ); + m_buttonNo->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnNo ), NULL, this ); + m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnCancel ), NULL, this ); +} + DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); @@ -2583,9 +2875,6 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer21->Add( bSizer86, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 ); - - bSizer21->Add( 0, 0, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - wxBoxSizer* bSizer70; bSizer70 = new wxBoxSizer( wxHORIZONTAL ); @@ -2600,7 +2889,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer70->Add( m_bpButtonHelp, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); - bSizer21->Add( bSizer70, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 ); + bSizer21->Add( bSizer70, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 10 ); bSizer21->Add( 0, 5, 0, 0, 5 ); @@ -2633,11 +2922,11 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText85->Wrap( -1 ); bSizer52->Add( m_staticText85, 0, 0, 5 ); - m_staticText86 = new wxStaticText( m_panel13, wxID_ANY, _("4. Keep the number of entries small for best performance."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText86 = new wxStaticText( m_panel13, wxID_ANY, _("4. Keep the number of (different) entries small for best performance."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText86->Wrap( -1 ); bSizer52->Add( m_staticText86, 0, wxBOTTOM, 5 ); - bSizer69->Add( bSizer52, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer69->Add( bSizer52, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 10 ); wxStaticBoxSizer* sbSizer21; sbSizer21 = new wxStaticBoxSizer( new wxStaticBox( m_panel13, wxID_ANY, _("Example") ), wxVERTICAL ); @@ -2669,6 +2958,8 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w wxFlexGridSizer* fgSizer3; fgSizer3 = new wxFlexGridSizer( 2, 2, 0, 0 ); + fgSizer3->AddGrowableCol( 1 ); + fgSizer3->AddGrowableRow( 1 ); fgSizer3->SetFlexibleDirection( wxBOTH ); fgSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); @@ -2682,15 +2973,17 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w fgSizer3->Add( m_staticText15, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_bitmap8 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); - fgSizer3->Add( m_bitmap8, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + fgSizer3->Add( m_bitmap8, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_textCtrlInclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,-1 ), wxTE_MULTILINE ); - fgSizer3->Add( m_textCtrlInclude, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + m_textCtrlInclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + fgSizer3->Add( m_textCtrlInclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer3, 0, 0, 5 ); + sbSizer8->Add( fgSizer3, 0, wxEXPAND, 5 ); wxFlexGridSizer* fgSizer4; fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 ); + fgSizer4->AddGrowableCol( 1 ); + fgSizer4->AddGrowableRow( 1 ); fgSizer4->SetFlexibleDirection( wxBOTH ); fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); @@ -2704,14 +2997,14 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w fgSizer4->Add( m_staticText16, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_bitmap9 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 30,30 ), 0 ); - fgSizer4->Add( m_bitmap9, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + fgSizer4->Add( m_bitmap9, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_textCtrlExclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,-1 ), wxTE_MULTILINE ); - fgSizer4->Add( m_textCtrlExclude, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + m_textCtrlExclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); + fgSizer4->Add( m_textCtrlExclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer4, 0, 0, 5 ); + sbSizer8->Add( fgSizer4, 0, wxEXPAND, 5 ); - bSizer21->Add( sbSizer8, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + bSizer21->Add( sbSizer8, 1, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); bSizer21->Add( 0, 0, 0, 0, 5 ); @@ -2889,7 +3182,7 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind wxBoxSizer* bSizer100; bSizer100 = new wxBoxSizer( wxHORIZONTAL ); - m_staticText99 = new wxStaticText( this, wxID_ANY, _("File Time Tolerance:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText99 = new wxStaticText( this, wxID_ANY, _("File Time tolerance (seconds):"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText99->Wrap( -1 ); m_staticText99->SetToolTip( _("File times that differ by up to the specified number of seconds are still handled as having same time.") ); diff --git a/ui/guiGenerated.h b/ui/guiGenerated.h index 394fa3e7..4bf190e1 100644 --- a/ui/guiGenerated.h +++ b/ui/guiGenerated.h @@ -42,11 +42,11 @@ class wxButtonWithImage; #include <wx/statline.h> #include <wx/frame.h> #include <wx/textctrl.h> +#include <wx/notebook.h> #include <wx/dialog.h> #include <wx/gauge.h> #include <wx/animate.h> #include <wx/treectrl.h> -#include <wx/notebook.h> #include <wx/checklst.h> #include <wx/spinctrl.h> @@ -62,26 +62,27 @@ class MainDialogGenerated : public wxFrame protected: wxMenuBar* m_menubar1; - wxMenu* m_menu1; + wxMenu* m_menuFile; wxMenuItem* m_menuItem10; wxMenuItem* m_menuItem11; - wxMenu* m_menu3; - wxMenu* m_menu31; + wxMenu* m_menuAdvanced; + wxMenu* m_menuLanguages; wxMenuItem* m_menuItemGerman; wxMenuItem* m_menuItemEnglish; wxMenuItem* m_menuItemSpanish; wxMenuItem* m_menuItemFrench; - wxMenuItem* m_menuItemHungarian; wxMenuItem* m_menuItemItalian; - wxMenuItem* m_menuItemPolish; + wxMenuItem* m_menuItemHungarian; wxMenuItem* m_menuItemDutch; + wxMenuItem* m_menuItemPolish; wxMenuItem* m_menuItemPortuguese; + wxMenuItem* m_menuItemPortugueseBrazil; wxMenuItem* m_menuItemSlovenian; wxMenuItem* m_menuItemJapanese; wxMenuItem* m_menuItemChineseSimple; wxMenuItem* m_menuItemGlobSett; wxMenuItem* m_menuItem7; - wxMenu* m_menu33; + wxMenu* m_menuHelp; wxMenuItem* m_menuItemAbout; wxBoxSizer* bSizer1; wxPanel* m_panel71; @@ -100,29 +101,29 @@ class MainDialogGenerated : public wxFrame wxButtonWithImage* m_buttonSync; - wxPanel* m_panel11; + wxPanel* m_panelTopLeft; wxStaticBoxSizer* sbSizer2; - wxComboBox* m_comboBoxDirLeft; + wxComboBox* m_directoryLeft; wxDirPickerCtrl* m_dirPickerLeft; - wxPanel* m_panel13; + wxPanel* m_panelTopMiddle; wxBoxSizer* bSizerMiddle; wxBitmapButton* m_bpButtonSwap; - wxPanel* m_panel12; + wxPanel* m_panelTopRight; wxBitmapButton* m_bpButtonAddPair; - wxComboBox* m_comboBoxDirRight; + wxComboBox* m_directoryRight; wxDirPickerCtrl* m_dirPickerRight; wxBoxSizer* bSizer106; wxStaticBitmap* m_bitmapShift; wxScrolledWindow* m_scrolledWindowFolderPairs; wxBoxSizer* bSizerFolderPairs; - wxPanel* m_panel1; + wxPanel* m_panelLeft; CustomGridLeft* m_gridLeft; - wxPanel* m_panel3; + wxPanel* m_panelMiddle; CustomGridMiddle* m_gridMiddle; - wxPanel* m_panel2; + wxPanel* m_panelRight; CustomGridRight* m_gridRight; wxBoxSizer* bSizer3; wxBoxSizer* bSizer58; @@ -165,11 +166,12 @@ class MainDialogGenerated : public wxFrame virtual void OnMenuLangEnglish( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangSpanish( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangFrench( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuLangHungarian( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangItalian( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuLangPolish( wxCommandEvent& event ){ event.Skip(); } + virtual void OnMenuLangHungarian( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangDutch( wxCommandEvent& event ){ event.Skip(); } + virtual void OnMenuLangPolish( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangPortuguese( wxCommandEvent& event ){ event.Skip(); } + virtual void OnMenuLangPortugueseBrazil( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangSlovenian( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangJapanese( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangChineseSimp( wxCommandEvent& event ){ event.Skip(); } @@ -186,7 +188,6 @@ class MainDialogGenerated : public wxFrame virtual void OnConfigureFilter( wxHyperlinkEvent& event ){ event.Skip(); } virtual void OnHideFilteredButton( wxCommandEvent& event ){ event.Skip(); } virtual void OnFolderHistoryKeyEvent( wxKeyEvent& event ){ event.Skip(); } - virtual void OnWriteDirManually( wxCommandEvent& event ){ event.Skip(); } virtual void OnDirSelected( wxFileDirPickerEvent& event ){ event.Skip(); } virtual void OnSwapDirs( wxCommandEvent& event ){ event.Skip(); } virtual void OnAddFolderPair( wxCommandEvent& event ){ event.Skip(); } @@ -229,10 +230,6 @@ class FolderPairGenerated : public wxPanel wxPanel* m_panel20; wxPanel* m_panel21; - - // Virtual event handlers, overide them in your derived class - virtual void OnRemoveFolderPair( wxCommandEvent& event ){ event.Skip(); } - public: wxPanel* m_panelLeft; @@ -249,6 +246,29 @@ class FolderPairGenerated : public wxPanel }; /////////////////////////////////////////////////////////////////////////////// +/// Class BatchFolderPairGenerated +/////////////////////////////////////////////////////////////////////////////// +class BatchFolderPairGenerated : public wxPanel +{ + private: + + protected: + wxStaticText* m_staticText53; + wxPanel* m_panelLeft; + wxStaticText* m_staticText541; + wxPanel* m_panelRight; + + public: + wxTextCtrl* m_directoryLeft; + wxDirPickerCtrl* m_dirPickerLeft; + wxTextCtrl* m_directoryRight; + wxDirPickerCtrl* m_dirPickerRight; + BatchFolderPairGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); + ~BatchFolderPairGenerated(); + +}; + +/////////////////////////////////////////////////////////////////////////////// /// Class BatchDlgGenerated /////////////////////////////////////////////////////////////////////////////// class BatchDlgGenerated : public wxDialog @@ -266,6 +286,8 @@ class BatchDlgGenerated : public wxDialog wxStaticLine* m_staticline10; wxStaticText* m_staticText531; + wxNotebook* m_notebookSettings; + wxPanel* m_panelOverview; wxScrolledWindow* m_scrolledWindow6; wxBoxSizer* bSizerFolderPairs; @@ -274,15 +296,13 @@ class BatchDlgGenerated : public wxDialog wxChoice* m_choiceHandleError; + wxCheckBox* m_checkBoxUseRecycler; + wxCheckBox* m_checkBoxFilter; wxCheckBox* m_checkBoxSilent; - wxBitmapButton* m_bpButtonFilter; - wxStaticBitmap* m_bitmap8; - wxTextCtrl* m_textCtrlInclude; - wxStaticBitmap* m_bitmap9; - wxTextCtrl* m_textCtrlExclude; + wxStaticText* m_staticText211; wxStaticText* m_staticText311; @@ -297,7 +317,19 @@ class BatchDlgGenerated : public wxDialog wxBitmapButton* m_bpButton8; wxStaticBitmap* m_bitmap17; wxBitmapButton* m_bpButton9; - wxStaticLine* m_staticline9; + wxPanel* m_panelFilter; + + wxStaticText* m_staticText15; + wxStaticBitmap* m_bitmap8; + wxTextCtrl* m_textCtrlInclude; + + wxStaticText* m_staticText16; + wxStaticBitmap* m_bitmap9; + wxTextCtrl* m_textCtrlExclude; + wxPanel* m_panelLogging; + wxStaticText* m_staticText120; + wxTextCtrl* m_textCtrlLogfileDir; + wxDirPickerCtrl* m_dirPickerLogfileDir; wxButton* m_buttonSave; wxButton* m_buttonLoad; wxButton* m_button6; @@ -307,7 +339,8 @@ class BatchDlgGenerated : public wxDialog virtual void OnChangeCompareVar( wxCommandEvent& event ){ event.Skip(); } virtual void OnChangeErrorHandling( wxCommandEvent& event ){ event.Skip(); } virtual void OnSelectRecycleBin( wxCommandEvent& event ){ event.Skip(); } - virtual void OnFilterButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCheckFilter( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCheckLogging( wxCommandEvent& event ){ event.Skip(); } virtual void OnExLeftSideOnly( wxCommandEvent& event ){ event.Skip(); } virtual void OnExRightSideOnly( wxCommandEvent& event ){ event.Skip(); } virtual void OnLeftNewer( wxCommandEvent& event ){ event.Skip(); } @@ -319,36 +352,12 @@ class BatchDlgGenerated : public wxDialog public: - BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Create a batch job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); + BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Create a batch job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~BatchDlgGenerated(); }; /////////////////////////////////////////////////////////////////////////////// -/// Class BatchFolderPairGenerated -/////////////////////////////////////////////////////////////////////////////// -class BatchFolderPairGenerated : public wxPanel -{ - private: - - protected: - wxStaticText* m_staticText53; - wxStaticText* m_staticText541; - - // Virtual event handlers, overide them in your derived class - virtual void OnEnterLeftDir( wxCommandEvent& event ){ event.Skip(); } - virtual void OnEnterRightDir( wxCommandEvent& event ){ event.Skip(); } - - - public: - wxTextCtrl* m_directoryLeft; - wxTextCtrl* m_directoryRight; - BatchFolderPairGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); - ~BatchFolderPairGenerated(); - -}; - -/////////////////////////////////////////////////////////////////////////////// /// Class CompareStatusGenerated /////////////////////////////////////////////////////////////////////////////// class CompareStatusGenerated : public wxPanel @@ -362,9 +371,13 @@ class CompareStatusGenerated : public wxPanel wxStaticBoxSizer* sbSizer13; wxStaticText* m_staticText46; - wxStaticText* m_staticTextFilesToCompare; + wxStaticText* m_staticTextFilesRemaining; wxStaticText* m_staticText32; - wxStaticText* m_staticTextDataToCompare; + wxStaticText* m_staticTextDataRemaining; + wxStaticText* m_staticText104; + wxStaticText* m_staticTextSpeed; + wxStaticText* m_staticText103; + wxStaticText* m_staticTextTimeRemaining; wxStaticText* m_staticText37; wxStaticText* m_staticTextTimeElapsed; @@ -482,6 +495,9 @@ class SyncStatusDlgGenerated : public wxDialog wxBoxSizer* bSizer28; wxStaticText* m_staticText25; wxStaticText* m_staticTextRemainingObj; + wxBoxSizer* bSizerSpeed; + wxStaticText* m_staticText108; + wxStaticText* m_staticTextSpeed; wxButton* m_buttonOK; wxButton* m_buttonPause; @@ -489,6 +505,9 @@ class SyncStatusDlgGenerated : public wxDialog wxStaticText* m_staticText26; wxStaticText* m_staticTextDataRemaining; + wxBoxSizer* bSizerRemTime; + wxStaticText* m_staticText106; + wxStaticText* m_staticTextTimeRemaining; // Virtual event handlers, overide them in your derived class @@ -500,7 +519,7 @@ class SyncStatusDlgGenerated : public wxDialog public: wxGauge* m_gauge1; - SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 614,371 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 638,376 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~SyncStatusDlgGenerated(); }; @@ -576,26 +595,39 @@ class AboutDlgGenerated : public wxDialog wxScrolledWindow* m_scrolledWindow3; wxStaticText* m_staticText54; + wxStaticBitmap* m_bitmapFrench; wxStaticText* m_staticText68; wxStaticText* m_staticText69; + wxStaticBitmap* m_bitmapJapanese; wxStaticText* m_staticText70; wxStaticText* m_staticText71; + wxStaticBitmap* m_bitmapDutch; wxStaticText* m_staticText711; wxStaticText* m_staticText712; + wxStaticBitmap* m_bitmapChineseSimple; wxStaticText* m_staticText91; wxStaticText* m_staticText92; + wxStaticBitmap* m_bitmapPolish; wxStaticText* m_staticText911; wxStaticText* m_staticText921; + wxStaticBitmap* m_bitmapPortuguese; wxStaticText* m_staticText9211; wxStaticText* m_staticText9212; + wxStaticBitmap* m_bitmapItalian; wxStaticText* m_staticText92121; wxStaticText* m_staticText92122; + wxStaticBitmap* m_bitmapSlovenian; wxStaticText* m_staticText921221; wxStaticText* m_staticText921222; + wxStaticBitmap* m_bitmapHungarian; wxStaticText* m_staticText682; wxStaticText* m_staticText681; + wxStaticBitmap* m_bitmapSpanish; wxStaticText* m_staticText683; wxStaticText* m_staticText691; + wxStaticBitmap* m_bitmapPortugueseBrazil; + wxStaticText* m_staticText684; + wxStaticText* m_staticText685; wxStaticLine* m_staticline3; wxPanel* m_panel22; wxStaticText* m_staticText131; @@ -687,6 +719,37 @@ class WarningDlgGenerated : public wxDialog }; /////////////////////////////////////////////////////////////////////////////// +/// Class QuestionDlgGenerated +/////////////////////////////////////////////////////////////////////////////// +class QuestionDlgGenerated : public wxDialog +{ + private: + + protected: + + wxStaticBitmap* m_bitmap10; + wxTextCtrl* m_textCtrl8; + wxCheckBox* m_checkBoxDontAskAgain; + + wxButton* m_buttonYes; + wxButton* m_buttonNo; + wxButton* m_buttonCancel; + + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } + virtual void OnYes( wxCommandEvent& event ){ event.Skip(); } + virtual void OnNo( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + + + public: + QuestionDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Question"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 391,237 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~QuestionDlgGenerated(); + +}; + +/////////////////////////////////////////////////////////////////////////////// /// Class DeleteDlgGenerated /////////////////////////////////////////////////////////////////////////////// class DeleteDlgGenerated : public wxDialog @@ -732,7 +795,6 @@ class FilterDlgGenerated : public wxDialog wxPanel* m_panel8; wxStaticText* m_staticText56; - wxStaticText* m_staticText44; wxBitmapButton* m_bpButtonHelp; @@ -768,7 +830,7 @@ class FilterDlgGenerated : public wxDialog public: - FilterDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Configure filter"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); + FilterDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Configure filter"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~FilterDlgGenerated(); }; diff --git a/ui/guiStatusHandler.cpp b/ui/guiStatusHandler.cpp new file mode 100644 index 00000000..74205dba --- /dev/null +++ b/ui/guiStatusHandler.cpp @@ -0,0 +1,402 @@ +#include "guiStatusHandler.h" +#include "../library/customButton.h" +#include "smallDialogs.h" +#include "../library/globalFunctions.h" +#include "mainDialog.h" + + +CompareStatusHandler::CompareStatusHandler(MainDialog* dlg) : + mainDialog(dlg), + ignoreErrors(false), + 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 + mainDialog->m_radioBtnSizeDate->Disable(); + mainDialog->m_radioBtnContent->Disable(); + mainDialog->m_bpButtonFilter->Disable(); + mainDialog->m_hyperlinkCfgFilter->Disable(); + mainDialog->m_checkBoxHideFilt->Disable(); + mainDialog->m_buttonSync->Disable(); + mainDialog->m_dirPickerLeft->Disable(); + mainDialog->m_dirPickerRight->Disable(); + mainDialog->m_bpButtonSwap->Disable(); + mainDialog->m_bpButtonLeftOnly->Disable(); + mainDialog->m_bpButtonLeftNewer->Disable(); + mainDialog->m_bpButtonEqual->Disable(); + mainDialog->m_bpButtonDifferent->Disable(); + mainDialog->m_bpButtonRightNewer->Disable(); + mainDialog->m_bpButtonRightOnly->Disable(); + mainDialog->m_panelLeft->Disable(); + mainDialog->m_panelMiddle->Disable(); + mainDialog->m_panelRight->Disable(); + mainDialog->m_panelTopLeft->Disable(); + mainDialog->m_panelTopMiddle->Disable(); + mainDialog->m_panelTopRight->Disable(); + mainDialog->m_bpButtonSave->Disable(); + mainDialog->m_bpButtonLoad->Disable(); + mainDialog->m_choiceHistory->Disable(); + mainDialog->m_bpButton10->Disable(); + mainDialog->m_bpButton14->Disable(); + mainDialog->m_scrolledWindowFolderPairs->Disable(); + mainDialog->m_menubar1->EnableTop(0, false); + mainDialog->m_menubar1->EnableTop(1, false); + mainDialog->m_menubar1->EnableTop(2, false); + + //show abort button + mainDialog->m_buttonAbort->Enable(); + mainDialog->m_buttonAbort->Show(); + mainDialog->m_buttonCompare->Disable(); + mainDialog->m_buttonCompare->Hide(); + mainDialog->m_buttonAbort->SetFocus(); + + //display status panel during compare + mainDialog->compareStatus->init(); //clear old values + mainDialog->compareStatus->Show(); + + mainDialog->bSizer1->Layout(); //both sizers need to recalculate! + mainDialog->bSizer6->Layout(); //adapt layout for wxBitmapWithImage + mainDialog->Refresh(); +} + + +CompareStatusHandler::~CompareStatusHandler() +{ + updateUiNow(); //ui update before enabling buttons again: prevent strange behaviour of delayed button clicks + + //reenable complete main dialog + mainDialog->m_radioBtnSizeDate->Enable(); + mainDialog->m_radioBtnContent->Enable(); + mainDialog->m_bpButtonFilter->Enable(); + mainDialog->m_hyperlinkCfgFilter->Enable(); + mainDialog->m_checkBoxHideFilt->Enable(); + mainDialog->m_buttonSync->Enable(); + mainDialog->m_dirPickerLeft->Enable(); + mainDialog->m_dirPickerRight->Enable(); + mainDialog->m_bpButtonSwap->Enable(); + mainDialog->m_bpButtonLeftOnly->Enable(); + mainDialog->m_bpButtonLeftNewer->Enable(); + mainDialog->m_bpButtonEqual->Enable(); + mainDialog->m_bpButtonDifferent->Enable(); + mainDialog->m_bpButtonRightNewer->Enable(); + mainDialog->m_bpButtonRightOnly->Enable(); + mainDialog->m_panelLeft->Enable(); + mainDialog->m_panelMiddle->Enable(); + mainDialog->m_panelRight->Enable(); + mainDialog->m_panelTopLeft->Enable(); + mainDialog->m_panelTopMiddle->Enable(); + mainDialog->m_panelTopRight->Enable(); + mainDialog->m_bpButtonSave->Enable(); + mainDialog->m_bpButtonLoad->Enable(); + mainDialog->m_choiceHistory->Enable(); + mainDialog->m_bpButton10->Enable(); + mainDialog->m_bpButton14->Enable(); + mainDialog->m_scrolledWindowFolderPairs->Enable(); + mainDialog->m_menubar1->EnableTop(0, true); + mainDialog->m_menubar1->EnableTop(1, true); + mainDialog->m_menubar1->EnableTop(2, true); + + if (abortRequested) + mainDialog->pushStatusInformation(_("Operation aborted!")); + + mainDialog->m_buttonAbort->Disable(); + mainDialog->m_buttonAbort->Hide(); + mainDialog->m_buttonCompare->Enable(); //enable compare button + mainDialog->m_buttonCompare->Show(); + + //hide status panel from main window + mainDialog->compareStatus->Hide(); + + mainDialog->bSizer6->Layout(); //adapt layout for wxBitmapWithImage + + mainDialog->Layout(); + mainDialog->Refresh(); +} + + +inline +void CompareStatusHandler::updateStatusText(const Zstring& text) +{ + mainDialog->compareStatus->setStatusText_NoUpdate(text); +} + + +void CompareStatusHandler::initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID) +{ + currentProcess = processID; + + if (currentProcess == StatusHandler::PROCESS_SCANNING) + ; + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + { + mainDialog->compareStatus->switchToCompareBytewise(objectsTotal, dataTotal); + mainDialog->Layout(); + } + + else assert(false); +} + + +inline +void CompareStatusHandler::updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) +{ + if (currentProcess == StatusHandler::PROCESS_SCANNING) + mainDialog->compareStatus->incScannedObjects_NoUpdate(objectsProcessed); + else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + mainDialog->compareStatus->incProcessedCmpData_NoUpdate(objectsProcessed, dataProcessed); + else assert(false); +} + + +ErrorHandler::Response CompareStatusHandler::reportError(const Zstring& text) +{ + if (ignoreErrors) + return ErrorHandler::IGNORE_ERROR; + + mainDialog->compareStatus->updateStatusPanelNow(); + + bool ignoreNextErrors = false; + wxString errorMessage = wxString(text.c_str()) + wxT("\n\n") + _("Ignore this error, retry or abort?"); + ErrorDlg* errorDlg = new ErrorDlg(mainDialog, + ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, + errorMessage, ignoreNextErrors); + int rv = errorDlg->ShowModal(); + switch (rv) + { + case ErrorDlg::BUTTON_IGNORE: + ignoreErrors = ignoreNextErrors; + return ErrorHandler::IGNORE_ERROR; + + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + + case ErrorDlg::BUTTON_ABORT: + abortThisProcess(); + } + + assert(false); + return ErrorHandler::IGNORE_ERROR; //dummy return value +} + + +void CompareStatusHandler::reportFatalError(const Zstring& errorMessage) +{ + mainDialog->compareStatus->updateStatusPanelNow(); + + bool dummy = false; + ErrorDlg* errorDlg = new ErrorDlg(mainDialog, + ErrorDlg::BUTTON_ABORT, + errorMessage.c_str(), dummy); + errorDlg->ShowModal(); + abortThisProcess(); +} + + +void CompareStatusHandler::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) +{ + if (ignoreErrors) //if errors are ignored, then warnings should also + return; + + mainDialog->compareStatus->updateStatusPanelNow(); + + //show popup and ask user how to handle warning + bool dontWarnAgain = false; + WarningDlg* warningDlg = new WarningDlg(mainDialog, + WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, + warningMessage.c_str(), + dontWarnAgain); + switch (warningDlg->ShowModal()) + { + case WarningDlg::BUTTON_ABORT: + abortThisProcess(); + + case WarningDlg::BUTTON_IGNORE: + dontShowAgain = dontWarnAgain; + return; + } + + assert(false); +} + + +inline +void CompareStatusHandler::forceUiRefresh() +{ + mainDialog->compareStatus->updateStatusPanelNow(); +} + + +void CompareStatusHandler::abortThisProcess() +{ + abortRequested = true; + throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame +} +//######################################################################################################## + + +SyncStatusHandler::SyncStatusHandler(wxWindow* dlg, bool ignoreAllErrors) : + ignoreErrors(ignoreAllErrors) +{ + syncStatusFrame = new SyncStatus(this, dlg); + syncStatusFrame->Show(); + updateUiNow(); +} + + +SyncStatusHandler::~SyncStatusHandler() +{ + //print the results list + unsigned int failedItems = unhandledErrors.GetCount(); + wxString result; + if (failedItems) + { + result = wxString(_("Warning: Synchronization failed for %x item(s):")) + wxT("\n\n"); + result.Replace(wxT("%x"), globalFunctions::numberToWxString(failedItems), false); + + for (unsigned int j = 0; j < failedItems; ++j) + { //remove linebreaks + wxString errorMessage = unhandledErrors[j]; + for (wxString::iterator i = errorMessage.begin(); i != errorMessage.end(); ++i) + if (*i == wxChar('\n')) + *i = wxChar(' '); + + result += errorMessage + wxT("\n"); + } + result+= wxT("\n"); + } + + //notify to syncStatusFrame that current process has ended + if (abortRequested) + { + result+= wxString(_("Synchronization aborted!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); + syncStatusFrame->setStatusText_NoUpdate(result.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::ABORTED); //enable okay and close events + } + else if (failedItems) + { + result+= wxString(_("Synchronization completed with errors!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); + syncStatusFrame->setStatusText_NoUpdate(result.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_ERROR); + } + else + { + result+= _("Synchronization completed successfully!"); + syncStatusFrame->setStatusText_NoUpdate(result.c_str()); + syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS); + } +} + + +inline +void SyncStatusHandler::updateStatusText(const Zstring& text) +{ + syncStatusFrame->setStatusText_NoUpdate(text); +} + + +void SyncStatusHandler::initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID) +{ + assert (processID == StatusHandler::PROCESS_SYNCHRONIZING); + + syncStatusFrame->resetGauge(objectsTotal, dataTotal); + syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); +} + + +inline +void SyncStatusHandler::updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) +{ + syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); +} + + +ErrorHandler::Response SyncStatusHandler::reportError(const Zstring& text) +{ + //add current time before error message + wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + text.c_str(); + + if (ignoreErrors) + { + unhandledErrors.Add(errorWithTime); + return ErrorHandler::IGNORE_ERROR; + } + + syncStatusFrame->updateStatusDialogNow(); + + bool ignoreNextErrors = false; + ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, + ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT, + wxString(text) + wxT("\n\n") + _("Ignore this error, retry or abort synchronization?"), + ignoreNextErrors); + int rv = errorDlg->ShowModal(); + switch (rv) + { + case ErrorDlg::BUTTON_IGNORE: + ignoreErrors = ignoreNextErrors; + unhandledErrors.Add(errorWithTime); + return ErrorHandler::IGNORE_ERROR; + + case ErrorDlg::BUTTON_RETRY: + return ErrorHandler::RETRY; + + case ErrorDlg::BUTTON_ABORT: + unhandledErrors.Add(errorWithTime); + abortThisProcess(); + } + + assert (false); + unhandledErrors.Add(errorWithTime); + return ErrorHandler::IGNORE_ERROR; +} + + +void SyncStatusHandler::reportFatalError(const Zstring& errorMessage) +{ //add current time before error message + wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); + + unhandledErrors.Add(errorWithTime); + abortThisProcess(); +} + + +void SyncStatusHandler::reportWarning(const Zstring& warningMessage, bool& dontShowAgain) +{ //add current time before warning message + wxString warningWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + warningMessage.c_str(); + + if (ignoreErrors) //if errors are ignored, then warnings should also + return; //no unhandled error situation! + + syncStatusFrame->updateStatusDialogNow(); + + //show popup and ask user how to handle warning + bool dontWarnAgain = false; + WarningDlg* warningDlg = new WarningDlg(syncStatusFrame, + WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_ABORT, + warningMessage.c_str(), + dontWarnAgain); + switch (warningDlg->ShowModal()) + { + case WarningDlg::BUTTON_IGNORE: //no unhandled error situation! + dontShowAgain = dontWarnAgain; + return; + + case WarningDlg::BUTTON_ABORT: + unhandledErrors.Add(warningWithTime); + abortThisProcess(); + } + + assert(false); +} + + +void SyncStatusHandler::forceUiRefresh() +{ + syncStatusFrame->updateStatusDialogNow(); +} + + +void SyncStatusHandler::abortThisProcess() +{ + abortRequested = true; + throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame +} diff --git a/ui/guiStatusHandler.h b/ui/guiStatusHandler.h new file mode 100644 index 00000000..51a87c98 --- /dev/null +++ b/ui/guiStatusHandler.h @@ -0,0 +1,60 @@ +#ifndef GUISTATUSHANDLER_H_INCLUDED +#define GUISTATUSHANDLER_H_INCLUDED + +#include "../library/statusHandler.h" +#include <wx/arrstr.h> + +class SyncStatus; +class MainDialog; +class wxWindow; + +//classes handling sync and compare error as well as status information +class CompareStatusHandler : public StatusHandler +{ +public: + CompareStatusHandler(MainDialog* dlg); + ~CompareStatusHandler(); + + virtual void updateStatusText(const Zstring& text); + virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); + virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void forceUiRefresh(); + + virtual ErrorHandler::Response reportError(const Zstring& text); + virtual void reportFatalError(const Zstring& errorMessage); + virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); + +private: + virtual void abortThisProcess(); + + MainDialog* mainDialog; + bool ignoreErrors; + Process currentProcess; +}; + + +class SyncStatusHandler : public StatusHandler +{ +public: + SyncStatusHandler(wxWindow* dlg, bool ignoreAllErrors); + ~SyncStatusHandler(); + + virtual void updateStatusText(const Zstring& text); + virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); + virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void forceUiRefresh(); + + virtual ErrorHandler::Response reportError(const Zstring& text); + virtual void reportFatalError(const Zstring& errorMessage); + virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain); + +private: + virtual void abortThisProcess(); + + SyncStatus* syncStatusFrame; + bool ignoreErrors; + wxArrayString unhandledErrors; //list of non-resolved errors +}; + + +#endif // GUISTATUSHANDLER_H_INCLUDED diff --git a/ui/sorting.h b/ui/sorting.h new file mode 100644 index 00000000..22b9c39b --- /dev/null +++ b/ui/sorting.h @@ -0,0 +1,305 @@ +#ifndef SORTING_H_INCLUDED +#define SORTING_H_INCLUDED + +#include "../structures.h" +#include "../library/resources.h" +#include "../library/globalFunctions.h" + + +namespace FreeFileSync +{ + enum SideToSort + { + SORT_ON_LEFT, + SORT_ON_RIGHT, + }; + + enum SortDirection + { + ASCENDING, + DESCENDING, + }; + + + template <SortDirection sortAscending> + inline + bool stringSmallerThan(const wxChar* stringA, const wxChar* stringB) + { +#ifdef FFS_WIN //case-insensitive comparison! + return sortAscending == ASCENDING ? + FreeFileSync::compareStringsWin32(stringA, stringB) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! + FreeFileSync::compareStringsWin32(stringA, stringB) > 0; +#else + while (*stringA == *stringB) + { + if (*stringA == wxChar(0)) //strings are equal + return false; + + ++stringA; + ++stringB; + } + return sortAscending == ASCENDING ? *stringA < *stringB : *stringA > *stringB; //wxChar(0) is handled correctly +#endif + } + + + inline + int compareString(const wxChar* stringA, const wxChar* stringB, const int lengthA, const int lengthB) + { +#ifdef FFS_WIN //case-insensitive comparison! + return FreeFileSync::compareStringsWin32(stringA, stringB, lengthA, lengthB); //way faster than wxString::CmpNoCase() in the windows build!!! +#else + for (int i = 0; i < std::min(lengthA, lengthB); ++i) + { + if (stringA[i] != stringB[i]) + return stringA[i] - stringB[i]; + } + return lengthA - lengthB; +#endif + } + + + template <SortDirection sortAscending, SideToSort side> + inline + bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b) + { + const FileDescrLine* const descrLineA = side == SORT_ON_LEFT ? &a.fileDescrLeft : &a.fileDescrRight; + const FileDescrLine* const descrLineB = side == SORT_ON_LEFT ? &b.fileDescrLeft : &b.fileDescrRight; + + //presort types: first files, then directories then empty rows + if (descrLineA->objType == FileDescrLine::TYPE_NOTHING) + return false; //empty rows always last + else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING) + return true; //empty rows always last + + + if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str()); + else + return false; + } + else + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return true; + else + { + const wxChar* stringA = descrLineA->relativeName.c_str(); + const wxChar* stringB = descrLineB->relativeName.c_str(); + + size_t pos = descrLineA->relativeName.findFromEnd(GlobalResources::FILE_NAME_SEPARATOR); //start search beginning from end + if (pos != std::string::npos) + stringA += pos + 1; + + pos = descrLineB->relativeName.findFromEnd(GlobalResources::FILE_NAME_SEPARATOR); //start search beginning from end + if (pos != std::string::npos) + stringB += pos + 1; + + return stringSmallerThan<sortAscending>(stringA, stringB); + } + } + } + + + template <SortDirection sortAscending, SideToSort side> + bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b) + { + const FileDescrLine* const descrLineA = side == SORT_ON_LEFT ? &a.fileDescrLeft : &a.fileDescrRight; + const FileDescrLine* const descrLineB = side == SORT_ON_LEFT ? &b.fileDescrLeft : &b.fileDescrRight; + + //extract relative name and filename + const wxChar* const relStringA = descrLineA->relativeName.c_str(); //mustn't be NULL for CompareString() API to work correctly + const wxChar* fileStringA = relStringA; + int relLengthA = 0; + int fileLengthA = 0; + + if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) + relLengthA = descrLineA->relativeName.length(); + else if (descrLineA->objType == FileDescrLine::TYPE_FILE) + { + relLengthA = descrLineA->relativeName.findFromEnd(GlobalResources::FILE_NAME_SEPARATOR); //start search beginning from end + if (relLengthA == wxNOT_FOUND) + { + relLengthA = 0; + fileLengthA = descrLineA->relativeName.length(); + } + else + { + fileStringA += relLengthA + 1; + fileLengthA = descrLineA->relativeName.length() - (relLengthA + 1); + } + } + else + return false; //empty rows should be on end of list + + + const wxChar* const relStringB = descrLineB->relativeName.c_str(); //mustn't be NULL for CompareString() API to work correctly + const wxChar* fileStringB = relStringB; + int relLengthB = 0; + int fileLengthB = 0; + + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + relLengthB = descrLineB->relativeName.length(); + else if (descrLineB->objType == FileDescrLine::TYPE_FILE) + { + relLengthB = descrLineB->relativeName.findFromEnd(GlobalResources::FILE_NAME_SEPARATOR); //start search beginning from end + if (relLengthB == wxNOT_FOUND) + { + relLengthB = 0; + fileLengthB = descrLineB->relativeName.length(); + } + else + { + fileStringB += relLengthB + 1; + fileLengthB = descrLineB->relativeName.length() - (relLengthB + 1); + } + } + else + return true; //empty rows should be on end of list + + //compare relative names without filenames first + const int rv = compareString(relStringA, relStringB, relLengthA, relLengthB); + if (rv != 0) + return sortAscending == ASCENDING ? rv < 0 : rv > 0; + else //compare the filenames + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) //directories shall appear before files + return false; + else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) + return true; + + return sortAscending == ASCENDING ? + compareString(fileStringA, fileStringB, fileLengthA, fileLengthB) < 0 : + compareString(fileStringA, fileStringB, fileLengthA, fileLengthB) > 0; + } + } + + + template <SortDirection sortAscending, SideToSort side> + inline + bool sortByFullName(const FileCompareLine& a, const FileCompareLine& b) + { + const FileDescrLine* const descrLineA = side == SORT_ON_LEFT ? &a.fileDescrLeft : &a.fileDescrRight; + const FileDescrLine* const descrLineB = side == SORT_ON_LEFT ? &b.fileDescrLeft : &b.fileDescrRight; + + //presort types: first files, then directories then empty rows + if (descrLineA->objType == FileDescrLine::TYPE_NOTHING) + return false; //empty rows always last + else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING) + return true; //empty rows always last + else +#ifdef FFS_WIN //case-insensitive comparison! + return sortAscending == ASCENDING ? + FreeFileSync::compareStringsWin32(descrLineA->fullName.c_str(), descrLineB->fullName.c_str()) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! + FreeFileSync::compareStringsWin32(descrLineA->fullName.c_str(), descrLineB->fullName.c_str()) > 0; +#else + return sortAscending == ASCENDING ? + descrLineA->fullName.Cmp(descrLineB->fullName) < 0 : + descrLineA->fullName.Cmp(descrLineB->fullName) > 0; +#endif + } + + + template <SortDirection sortAscending, SideToSort side> + inline + bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b) + { + const FileDescrLine* const descrLineA = side == SORT_ON_LEFT ? &a.fileDescrLeft : &a.fileDescrRight; + const FileDescrLine* const descrLineB = side == SORT_ON_LEFT ? &b.fileDescrLeft : &b.fileDescrRight; + + //presort types: first files, then directories then empty rows + if (descrLineA->objType == FileDescrLine::TYPE_NOTHING) + return false; //empty rows always last + else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING) + return true; //empty rows always last + + + if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str()); + else + return false; + } + else + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return true; + else + return sortAscending == ASCENDING ? + descrLineA->fileSize > descrLineB->fileSize : //sortAscending shall result in list beginning with largest files first + descrLineA->fileSize < descrLineB->fileSize; + } + } + + + template <SortDirection sortAscending, SideToSort side> + inline + bool sortByDate(const FileCompareLine& a, const FileCompareLine& b) + { + const FileDescrLine* const descrLineA = side == SORT_ON_LEFT ? &a.fileDescrLeft : &a.fileDescrRight; + const FileDescrLine* const descrLineB = side == SORT_ON_LEFT ? &b.fileDescrLeft : &b.fileDescrRight; + + //presort types: first files, then directories then empty rows + if (descrLineA->objType == FileDescrLine::TYPE_NOTHING) + return false; //empty rows always last + else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING) + return true; //empty rows always last + + if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str()); + else + return false; + } + else + { + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return true; + else + return sortAscending == ASCENDING ? + descrLineA->lastWriteTimeRaw > descrLineB->lastWriteTimeRaw : + descrLineA->lastWriteTimeRaw < descrLineB->lastWriteTimeRaw; + } + } + + + template <SortDirection sortAscending> + inline + bool sortByCmpResult(const FileCompareLine& a, const FileCompareLine& b) + { + //presort result: equal shall appear at end of list + if (a.cmpResult == FILE_EQUAL) + return false; + if (b.cmpResult == FILE_EQUAL) + return true; + + return sortAscending == ASCENDING ? + a.cmpResult < b.cmpResult : + a.cmpResult > b.cmpResult; + } + + + template <SortDirection sortAscending, SideToSort side> + inline + bool sortByDirectory(const FolderCompareLine& a, const FolderCompareLine& b) + { + const Zstring* const dirNameA = side == SORT_ON_LEFT ? &a.syncPair.leftDirectory : &a.syncPair.rightDirectory; + const Zstring* const dirNameB = side == SORT_ON_LEFT ? &b.syncPair.leftDirectory : &b.syncPair.rightDirectory; + +#ifdef FFS_WIN //case-insensitive comparison! + return sortAscending == ASCENDING ? + FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! + FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) > 0; +#elif defined FFS_LINUX + return sortAscending == ASCENDING ? + dirNameA->Cmp(*dirNameB) < 0 : + dirNameA->Cmp(*dirNameB) > 0; +#endif + } +} + +#endif // SORTING_H_INCLUDED |