diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:09:45 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:09:45 +0200 |
commit | 88c8801298cbf6fec9cdce254c7b3cb9e066a421 (patch) | |
tree | 35a35acf48eb227bac30abc8f87ea9b1c3c57b68 /ui/main_dlg.cpp | |
parent | 3.12 (diff) | |
download | FreeFileSync-88c8801298cbf6fec9cdce254c7b3cb9e066a421.tar.gz FreeFileSync-88c8801298cbf6fec9cdce254c7b3cb9e066a421.tar.bz2 FreeFileSync-88c8801298cbf6fec9cdce254c7b3cb9e066a421.zip |
3.13
Diffstat (limited to 'ui/main_dlg.cpp')
-rw-r--r-- | ui/main_dlg.cpp | 771 |
1 files changed, 491 insertions, 280 deletions
diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp index 5fa6aee7..c8106cf9 100644 --- a/ui/main_dlg.cpp +++ b/ui/main_dlg.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // #include "main_dlg.h" @@ -54,11 +54,21 @@ #include <wx/app.h> #include <boost/bind.hpp> - using namespace ffs3; using ffs3::CustomLocale; +namespace +{ +struct wxClientDataString : public wxClientData //we need a wxClientData derived class to tell wxWidgets to take object ownership! +{ + wxClientDataString(const wxString& name) : name_(name) {} + + wxString name_; +}; +} + + class DirectoryNameMainImpl : public DirectoryNameMainDlg { public: @@ -318,8 +328,13 @@ struct DirNotFound { bool operator()(const FolderPairEnh& fp) const { - return !dirExists(ffs3::getFormattedDirectoryName(fp.leftDirectory)) || - !dirExists(ffs3::getFormattedDirectoryName(fp.rightDirectory)); + const Zstring dirFmtLeft = ffs3::getFormattedDirectoryName(fp.leftDirectory); + const Zstring dirFmtRight = ffs3::getFormattedDirectoryName(fp.rightDirectory); + + if (dirFmtLeft.empty() && dirFmtRight.empty()) + return false; + + return !dirExists(dirFmtLeft) || !dirExists(dirFmtRight); } }; @@ -334,10 +349,9 @@ MainDialog::MainDialog(const wxString& cfgFileName, xmlAccess::XmlGlobalSettings bool loadCfgSuccess = false; if (!cfgFileName.empty() || fileExists(wxToZ(lastConfigFileName()))) - { - //load XML try { + //load XML std::vector<wxString> filenames; filenames.push_back(currentConfigFile); @@ -352,16 +366,49 @@ MainDialog::MainDialog(const wxString& cfgFileName, xmlAccess::XmlGlobalSettings else wxMessageBox(error.msg(), _("Error"), wxOK | wxICON_ERROR); } - } + const bool startComparisonImmediately = loadCfgSuccess && !cfgFileName.empty(); init(guiCfg, settings, - !cfgFileName.empty() && loadCfgSuccess); + startComparisonImmediately); setLastUsedConfig(currentConfigFile, loadCfgSuccess ? guiCfg : xmlAccess::XmlGuiConfig()); //simulate changed config on parsing errors } +#ifdef FFS_WIN +class PanelMoveWindow : public MouseMoveWindow +{ +public: + PanelMoveWindow(MainDialog& mainDlg) : + MouseMoveWindow(mainDlg, + mainDlg.m_panelTopButtons, + //mainDlg.m_panelDirectoryPairs, + mainDlg.m_panelConfig, + mainDlg.m_panelFilter, + mainDlg.m_panelViewFilter, + mainDlg.m_panelStatistics, + mainDlg.m_panelStatusBar), + mainDlg_(mainDlg) {} + + virtual bool allowMove(const wxMouseEvent& event) + { + wxPanel* panel = dynamic_cast<wxPanel*>(event.GetEventObject()); + + const wxAuiPaneInfo& paneInfo = mainDlg_.auiMgr.GetPane(panel); + if ( paneInfo.IsOk() && + paneInfo.IsFloating()) + return false; //prevent main dialog move + + return true;; //allow dialog move + } + +private: + MainDialog& mainDlg_; +}; +#endif + + MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg, xmlAccess::XmlGlobalSettings& settings, bool startComparison) : @@ -378,6 +425,8 @@ MainDialog::~MainDialog() //keep non-inline destructor for std::auto_ptr to work with forward declaration cleanUp(true); //do NOT include any other code here! cleanUp() is re-used when switching languages + + auiMgr.UnInit(); } @@ -390,23 +439,67 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, //--------- avoid mirroring this dialog in RTL languages like Hebrew or Arabic -------------------- m_panelViewFilter->SetLayoutDirection(wxLayout_LeftToRight); m_panelStatusBar->SetLayoutDirection(wxLayout_LeftToRight); -// if (GetLayoutDirection() == wxLayout_RightToLeft) -//{ -// bSizerGridHolder->Detach(m_panelRight); -// bSizerGridHolder->Detach(m_panelLeft); -// bSizerGridHolder->Add(m_panelLeft); -// bSizerGridHolder->Prepend(m_panelRight); -//bSizerGridHolder->Fit(this); -// -// bSizerGridHolder->Layout(); -//} -//------------------------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------------------------ + +//---------------- support for dockable gui style -------------------------------- + bSizerPanelHolder->Detach(m_panelTopButtons); + bSizerPanelHolder->Detach(m_panelDirectoryPairs); + bSizerPanelHolder->Detach(m_panelGrids); + bSizerPanelHolder->Detach(m_panelConfig); + bSizerPanelHolder->Detach(m_panelFilter); + bSizerPanelHolder->Detach(m_panelViewFilter); + bSizerPanelHolder->Detach(m_panelStatistics); + bSizerPanelHolder->Detach(m_panelStatusBar); + + auiMgr.SetManagedWindow(this); + auiMgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + + //caption required for all panes that can be manipulated by the users => used by context menu + auiMgr.AddPane(m_panelTopButtons, + wxAuiPaneInfo().Name(wxT("Panel1")).Top().Caption(_("Main bar")).CaptionVisible(false).PaneBorder(false).Gripper().MinSize(-1, m_buttonCompare->GetSize().GetHeight() - 5)); + //note: min height is calculated incorrectly by wxAuiManager if panes with and without caption are in the same row => use smaller min-size + + compareStatus.reset(new CompareStatus(*this)); //integrate the compare status panel (in hidden state) + auiMgr.AddPane(compareStatus->getAsWindow(), + wxAuiPaneInfo().Name(wxT("Panel9")).Top().Row(1).CaptionVisible(false).PaneBorder(false).Hide()); //name "CmpStatus" used by context menu + + auiMgr.AddPane(m_panelDirectoryPairs, + wxAuiPaneInfo().Name(wxT("Panel2")).Top().Row(2).Caption(_("Folder pairs")).CaptionVisible(false).PaneBorder(false).Gripper()); + + auiMgr.AddPane(m_panelGrids, + wxAuiPaneInfo().Name(wxT("Panel3")).CenterPane().PaneBorder(false)); + + auiMgr.AddPane(m_panelConfig, + wxAuiPaneInfo().Name(wxT("Panel4")).Bottom().Row(1).Position(0).Caption(_("Configuration")).MinSize(m_listBoxHistory->GetSize().GetWidth(), m_panelConfig->GetSize().GetHeight())); + + auiMgr.AddPane(m_panelFilter, + wxAuiPaneInfo().Name(wxT("Panel5")).Bottom().Row(1).Position(1).Caption(_("Filter files")).MinSize(-1, m_panelFilter->GetSize().GetHeight())); + + auiMgr.AddPane(m_panelViewFilter, + wxAuiPaneInfo().Name(wxT("Panel6")).Bottom().Row(1).Position(2).Caption(_("Filter view")).MinSize(m_bpButtonSyncDirNone->GetSize().GetWidth(), m_panelViewFilter->GetSize().GetHeight())); + + auiMgr.AddPane(m_panelStatistics, + wxAuiPaneInfo().Name(wxT("Panel7")).Bottom().Row(1).Position(3).Caption(_("Statistics")).MinSize(m_panelStatistics->GetSize().GetWidth() / 2, m_panelStatistics->GetSize().GetHeight())); + + auiMgr.AddPane(m_panelStatusBar, + wxAuiPaneInfo().Name(wxT("Panel8")).Bottom().Row(0).CaptionVisible(false).PaneBorder(false).DockFixed()); + + auiMgr.Update(); + defaultPerspective = auiMgr.SavePerspective(); +//---------------------------------------------------------------------------------- +//register view layout context menu + m_panelTopButtons->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); + m_panelConfig ->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); + m_panelFilter ->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); + m_panelViewFilter->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); + m_panelStatistics->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); + m_panelStatusBar ->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), NULL, this); +//---------------------------------------------------------------------------------- globalSettings = &settings; gridDataView.reset(new ffs3::GridView); contextMenu.reset(new wxMenu); //initialize right-click context menu; will be dynamically re-created on each R-mouse-click - compareStatus.reset(new CompareStatus(*this)); cleanedUp = false; lastSortColumn = -1; lastSortGrid = NULL; @@ -414,10 +507,7 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, updateFileIcons.reset(new IconUpdater(m_gridLeft, m_gridRight)); #ifdef FFS_WIN - new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... - m_panel71, - m_panelBottom, - m_panelStatusBar); //ownership passed to "this" + new PanelMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere... //ownership passed to "this" #endif syncPreview.reset(new SyncPreview(this)); @@ -426,7 +516,6 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, SetIcon(*GlobalResources::getInstance().programIcon); //set application icon - //notify about (logical) application main window => program won't quit, but stay on this dialog ffs3::AppMainWindow::setMainWindow(this); @@ -440,7 +529,6 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, setCurrentConfiguration(guiCfg); //set icons for this dialog - m_bpButton10->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("exit"))); m_buttonCompare->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("compare"))); m_bpButtonSyncConfig->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("syncConfig"))); m_bpButtonCmpConfig->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("cmpConfig"))); @@ -454,7 +542,7 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, m_bitmapDelete->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("delete"))); m_bitmapData->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("data"))); - bSizer6->Layout(); //wxButtonWithImage size might have changed + m_panelTopButtons->Layout(); //wxButtonWithImage size might have changed //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); @@ -491,21 +579,31 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, } //support for CTRL + C and DEL on grids - m_gridLeft->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridLeftButtonEvent), NULL, this); - m_gridRight->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridRightButtonEvent), NULL, this); + m_gridLeft ->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridLeftButtonEvent), NULL, this); + m_gridRight ->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridRightButtonEvent), NULL, this); m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridMiddleButtonEvent), NULL, this); //register global hotkeys (without explicit menu entry) wxTheApp->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::OnGlobalKeyEvent), NULL, this); Connect(wxEVT_IDLE, wxEventHandler(MainDialog::OnIdleEvent), NULL, this); + Connect(wxEVT_SIZE, wxSizeEventHandler(MainDialog::OnResize), NULL, this); Connect(wxEVT_MOVE, wxSizeEventHandler(MainDialog::OnResize), NULL, this); m_bpButtonFilter->Connect(wxEVT_RIGHT_DOWN, wxCommandEventHandler(MainDialog::OnGlobalFilterOpenContext), NULL, this); //calculate witdh of folder pair manually (if scrollbars are visible) - m_scrolledWindowFolderPairs->Connect(wxEVT_SIZE, wxSizeEventHandler(MainDialog::OnResizeFolderPairs), NULL, this); + m_panelTopLeft->Connect(wxEVT_SIZE, wxEventHandler(MainDialog::OnResizeFolderPairs), NULL, this); + + //dynamically change sizer direction depending on size + m_panelConfig ->Connect(wxEVT_SIZE, wxEventHandler(MainDialog::OnResizeConfigPanel), NULL, this); + m_panelViewFilter->Connect(wxEVT_SIZE, wxEventHandler(MainDialog::OnResizeViewPanel), NULL, this); + m_panelStatistics->Connect(wxEVT_SIZE, wxEventHandler(MainDialog::OnResizeStatisticsPanel), NULL, this); + wxSizeEvent dummy3; + OnResizeConfigPanel (dummy3); //call once on window creation + OnResizeViewPanel (dummy3); // + OnResizeStatisticsPanel(dummy3); // //event handler for manual (un-)checking of rows and setting of sync direction m_gridMiddle->Connect(FFS_CHECK_ROWS_EVENT, FFSCheckRowsEventHandler(MainDialog::OnCheckRows), NULL, this); @@ -522,18 +620,6 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, //mainly to update row label sizes... updateGuiGrid(); - //integrate the compare status panel (in hidden state) - bSizer1->Insert(1, compareStatus->getAsWindow(), 0, wxEXPAND | wxBOTTOM, 5 ); - Layout(); //avoid screen flicker when panel is shown later - compareStatus->getAsWindow()->Hide(); - - //correct width of swap button above middle grid - const wxSize source = m_gridMiddle->GetSize(); - const wxSize target = m_bpButtonSwapSides->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); @@ -620,8 +706,20 @@ void MainDialog::readGlobalSettings() m_gridLeft->enableFileIcons(globalSettings->gui.showFileIconsLeft); m_gridRight->enableFileIcons(globalSettings->gui.showFileIconsRight); - //set selected tab - m_notebookBottomLeft->ChangeSelection(globalSettings->gui.selectedTabBottomLeft); +//------------------------------------------------------------------------------------------------ + //wxAuiManager erroneously loads panel captions, we don't want that + typedef std::vector<std::pair<wxString, wxString> > CaptionNameMapping; + CaptionNameMapping captionNameMap; + const wxAuiPaneInfoArray& paneArray = auiMgr.GetAllPanes(); + for (size_t i = 0; i < paneArray.size(); ++i) + captionNameMap.push_back(std::make_pair(paneArray[i].caption, paneArray[i].name)); + + auiMgr.LoadPerspective(globalSettings->gui.guiPerspectiveLast); + + //restore original captions + for (CaptionNameMapping::const_iterator i = captionNameMap.begin(); i != captionNameMap.end(); ++i) + auiMgr.GetPane(i->second).Caption(i->first); + auiMgr.Update(); } @@ -639,7 +737,12 @@ void MainDialog::writeGlobalSettings() globalSettings->gui.columnAttribRight = m_gridRight->getColumnAttributes(); //write list of last used configuration files - globalSettings->gui.cfgFileHistory = cfgFileNames; + std::vector<wxString> cfgFileHistory; + for (int i = 0; i < static_cast<int>(m_listBoxHistory->GetCount()); ++i) + if (m_listBoxHistory->GetClientObject(i)) + cfgFileHistory.push_back(static_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(i))->name_); + + globalSettings->gui.cfgFileHistory = cfgFileHistory; //write list of last used folders globalSettings->gui.folderHistoryLeft.clear(); @@ -652,8 +755,7 @@ void MainDialog::writeGlobalSettings() for (unsigned i = 0; i < rightFolderHistory.GetCount(); ++i) globalSettings->gui.folderHistoryRight.push_back(rightFolderHistory[i]); - //get selected tab - globalSettings->gui.selectedTabBottomLeft = m_notebookBottomLeft->GetSelection(); + globalSettings->gui.guiPerspectiveLast = auiMgr.SavePerspective(); } @@ -885,7 +987,7 @@ void MainDialog::deleteSelectedFiles() int totalDeleteCount = 0; - wxWindow* oldFocus = wxWindow::FindFocus(); + wxWindow* oldFocus = wxWindow::FindFocus(); if (ffs3::showDeleteDialog(compRefLeft, compRefRight, @@ -924,7 +1026,7 @@ void MainDialog::deleteSelectedFiles() m_gridRight-> ClearSelection(); } - if (oldFocus) + if (oldFocus) oldFocus->SetFocus(); //restore focus before deletion } } @@ -967,6 +1069,21 @@ void exstractNames(const FileSystemObject& fsObj, wxString& name, wxString& dir) } +void MainDialog::openExternalApplication(const wxString& commandline) +{ + if (m_gridLeft->isLeadGrid() || m_gridRight->isLeadGrid()) + { + const CustomGrid* leadGrid = m_gridLeft->isLeadGrid() ? + static_cast<CustomGrid*>(m_gridLeft) : + static_cast<CustomGrid*>(m_gridRight); + std::set<size_t> selection = getSelectedRows(leadGrid); + + if (selection.size() == 1) + openExternalApplication(*selection.begin(), m_gridLeft->isLeadGrid(), commandline); + } +} + + void MainDialog::openExternalApplication(size_t rowNumber, bool leftSide, const wxString& commandline) { if (commandline.empty()) @@ -1052,76 +1169,54 @@ void MainDialog::clearStatusBar() void MainDialog::disableAllElements() { //disenables all elements (except abort button) that might receive user input during long-running processes: comparison, deletion - m_bpButtonCmpConfig-> Disable(); - m_notebookBottomLeft->Disable(); - m_checkBoxHideFilt-> Disable(); + m_bpButtonCmpConfig ->Disable(); + m_panelFilter ->Disable(); + m_panelConfig ->Disable(); m_bpButtonSyncConfig->Disable(); - m_buttonStartSync-> Disable(); - m_dirPickerLeft-> Disable(); - m_dirPickerRight-> Disable(); - m_bpButtonSwapSides-> Disable(); - m_bpButtonLeftOnly-> Disable(); - m_bpButtonLeftNewer-> Disable(); - m_bpButtonEqual-> Disable(); - m_bpButtonDifferent-> Disable(); - m_bpButtonRightNewer->Disable(); - m_bpButtonRightOnly-> Disable(); - m_panelLeft-> Disable(); - m_panelMiddle-> Disable(); - m_panelRight-> Disable(); - m_panelTopLeft-> Disable(); - m_panelTopMiddle-> Disable(); - m_panelTopRight-> Disable(); - m_bpButton10-> Disable(); - m_scrolledWindowFolderPairs->Disable(); + m_buttonStartSync ->Disable(); + m_panelGrids ->Disable(); + m_panelDirectoryPairs->Disable(); m_menubar1->EnableTop(0, false); m_menubar1->EnableTop(1, false); m_menubar1->EnableTop(2, false); - EnableCloseButton(false); //show abort button m_buttonAbort->Enable(); m_buttonAbort->Show(); + m_buttonAbort->SetFocus(); m_buttonCompare->Disable(); m_buttonCompare->Hide(); - m_buttonAbort->SetFocus(); + m_bpButtonCmpConfig ->Disable(); + m_bpButtonSyncConfig->Disable(); + m_buttonStartSync ->Disable(); + + m_panelTopButtons->Layout(); } void MainDialog::enableAllElements() { - m_bpButtonCmpConfig-> Enable(); - m_notebookBottomLeft->Enable(); - m_checkBoxHideFilt-> Enable(); + m_bpButtonCmpConfig ->Enable(); + m_panelFilter ->Enable(); + m_panelConfig ->Enable(); m_bpButtonSyncConfig->Enable(); - m_buttonStartSync-> Enable(); - m_dirPickerLeft-> Enable(); - m_dirPickerRight-> Enable(); - m_bpButtonSwapSides-> Enable(); - m_bpButtonLeftOnly-> Enable(); - m_bpButtonLeftNewer-> Enable(); - m_bpButtonEqual-> Enable(); - m_bpButtonDifferent-> Enable(); - m_bpButtonRightNewer->Enable(); - m_bpButtonRightOnly-> Enable(); - m_panelLeft-> Enable(); - m_panelMiddle-> Enable(); - m_panelRight-> Enable(); - m_panelTopLeft-> Enable(); - m_panelTopMiddle-> Enable(); - m_panelTopRight-> Enable(); - m_bpButton10-> Enable(); - m_scrolledWindowFolderPairs->Enable(); + m_buttonStartSync ->Enable(); + m_panelGrids ->Enable(); + m_panelDirectoryPairs->Enable(); m_menubar1->EnableTop(0, true); m_menubar1->EnableTop(1, true); m_menubar1->EnableTop(2, true); - EnableCloseButton(true); //show compare button m_buttonAbort->Disable(); m_buttonAbort->Hide(); m_buttonCompare->Enable(); m_buttonCompare->Show(); + m_bpButtonCmpConfig ->Enable(); + m_bpButtonSyncConfig->Enable(); + m_buttonStartSync ->Enable(); + + m_panelTopButtons->Layout(); } @@ -1139,7 +1234,8 @@ void MainDialog::OnResize(wxSizeEvent& event) //test ALL parameters at once, since width/height are invalid if the window is minimized (eg x,y == -32000; height = 28, width = 160) //note: negative values for x and y are possible when using multiple monitors! - if (width > 0 && height > 0 && x >= -3360 && y >= -200) + if (width > 0 && height > 0 && x >= -3360 && y >= -200 && + wxDisplay::GetFromPoint(wxPoint(x, y)) != wxNOT_FOUND) //make sure upper left corner is in visible view { widthNotMaximized = width; //visible coordinates x < 0 and y < 0 are possible with dual monitors! heightNotMaximized = height; @@ -1153,16 +1249,57 @@ void MainDialog::OnResize(wxSizeEvent& event) } -void MainDialog::OnResizeFolderPairs(wxSizeEvent& event) +namespace { - //adapt left-shift display distortion caused by scrollbars for multiple folder pairs - if (additionalFolderPairs.size() > 0) +void updateSizerOrientation(wxBoxSizer& sizer, wxWindow& window) +{ + if (window.GetSize().GetWidth() > window.GetSize().GetHeight()) //check window NOT sizer width! { - const int width = m_panelTopLeft->GetSize().GetWidth(); - - for (std::vector<DirectoryPair*>::iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) - (*i)->m_panelLeft->SetMinSize(wxSize(width, -1)); + if (sizer.GetOrientation() != wxHORIZONTAL) + { + sizer.SetOrientation(wxHORIZONTAL); + window.Layout(); + } } + else + { + if (sizer.GetOrientation() != wxVERTICAL) + { + sizer.SetOrientation(wxVERTICAL); + window.Layout(); + } + } +} +} + + +void MainDialog::OnResizeConfigPanel(wxEvent& event) +{ + updateSizerOrientation(*bSizerConfig, *m_panelConfig); + event.Skip(); +} + + +void MainDialog::OnResizeViewPanel(wxEvent& event) +{ + updateSizerOrientation(*bSizerViewFilter, *m_panelViewFilter); + event.Skip(); +} + + +void MainDialog::OnResizeStatisticsPanel(wxEvent& event) +{ + updateSizerOrientation(*bSizerStatistics, *m_panelStatistics); + event.Skip(); +} + + +void MainDialog::OnResizeFolderPairs(wxEvent& event) +{ + //adapt left-shift display distortion caused by scrollbars for multiple folder pairs + const int width = m_panelTopLeft->GetSize().GetWidth(); + for (std::vector<DirectoryPair*>::iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + (*i)->m_panelLeft->SetMinSize(wxSize(width, -1)); event.Skip(); } @@ -1233,8 +1370,8 @@ void MainDialog::onGridLeftButtonEvent(wxKeyEvent& event) case WXK_RETURN: case WXK_NUMPAD_ENTER: { - wxCommandEvent dummy(wxEVT_NULL, externalAppIDFirst); //open with first external application - OnContextOpenWith(dummy); + if (!globalSettings->gui.externelApplications.empty()) + openExternalApplication(globalSettings->gui.externelApplications[0].second); //open with first external application } return; } @@ -1325,8 +1462,8 @@ void MainDialog::onGridRightButtonEvent(wxKeyEvent& event) case WXK_RETURN: case WXK_NUMPAD_ENTER: { - wxCommandEvent dummy(wxEVT_NULL, externalAppIDFirst); //open with first external application - OnContextOpenWith(dummy); + if (!globalSettings->gui.externelApplications.empty()) + openExternalApplication(globalSettings->gui.externelApplications[0].second); //open with first external application } return; } @@ -1362,7 +1499,13 @@ void MainDialog::OnGlobalKeyEvent(wxKeyEvent& event) //process key events withou //------------------------------------------------------------ -//temporal variables used by exclude via context menu +//temporal variables used by exclude via context menu, transport string object to context menu handler +struct CtxtSelectionString : public wxObject +{ + CtxtSelectionString(const wxString& name) : objName(name) {} + const wxString objName; +}; + struct SelectedExtension : public wxObject { SelectedExtension(const Zstring& ext) : extension(ext) {} @@ -1378,7 +1521,6 @@ struct FilterObject Zstring relativeName; bool isDir; }; - typedef std::vector<FilterObject> FilterObjList; struct FilterObjContainer : public wxObject @@ -1423,6 +1565,7 @@ void MainDialog::OnContextRim(wxGridEvent& event) const FileSystemObject* fsObj = gridDataView->getObject(selectionBegin); + int contextItemID = 2000; //####################################################### //re-create context menu @@ -1434,25 +1577,28 @@ void MainDialog::OnContextRim(wxGridEvent& event) if (selectionLeft.size() + selectionRight.size() > 0) { //CONTEXT_SYNC_DIR_LEFT - wxMenuItem* menuItemSyncDirLeft = new wxMenuItem(contextMenu.get(), CONTEXT_SYNC_DIR_LEFT, wxString(_("Set direction:")) + + wxMenuItem* menuItemSyncDirLeft = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Set direction:")) + wxT(" ") + getSymbol(fsObj->testSyncOperation(true, SYNC_DIR_LEFT)) + wxT("\tALT + LEFT")); //Linux needs a direction, "<-", because it has no context menu icons! menuItemSyncDirLeft->SetBitmap(getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_LEFT))); contextMenu->Append(menuItemSyncDirLeft); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirLeft), NULL, this); //CONTEXT_SYNC_DIR_NONE - wxMenuItem* menuItemSyncDirNone = new wxMenuItem(contextMenu.get(), CONTEXT_SYNC_DIR_NONE, wxString(_("Set direction:")) + + wxMenuItem* menuItemSyncDirNone = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Set direction:")) + wxT(" ") + getSymbol(fsObj->testSyncOperation(true, SYNC_DIR_NONE)) + wxT("\tALT + UP")); menuItemSyncDirNone->SetBitmap(getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_NONE))); contextMenu->Append(menuItemSyncDirNone); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirNone), NULL, this); //CONTEXT_SYNC_DIR_RIGHT - wxMenuItem* menuItemSyncDirRight = new wxMenuItem(contextMenu.get(), CONTEXT_SYNC_DIR_RIGHT, wxString(_("Set direction:")) + + wxMenuItem* menuItemSyncDirRight = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Set direction:")) + wxT(" ") + getSymbol(fsObj->testSyncOperation(true, SYNC_DIR_RIGHT)) + wxT("\tALT + RIGHT")); menuItemSyncDirRight->SetBitmap(getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_RIGHT))); contextMenu->Append(menuItemSyncDirRight); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirRight), NULL, this); contextMenu->AppendSeparator(); } @@ -1464,22 +1610,24 @@ void MainDialog::OnContextRim(wxGridEvent& event) { if (fsObj->isActive()) { - wxMenuItem* menuItemExclTemp = new wxMenuItem(contextMenu.get(), CONTEXT_FILTER_TEMP, wxString(_("Exclude temporarily")) + wxT("\tSPACE")); + wxMenuItem* menuItemExclTemp = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Exclude temporarily")) + wxT("\tSPACE")); menuItemExclTemp->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("checkboxFalse"))); contextMenu->Append(menuItemExclTemp); } else { - wxMenuItem* menuItemInclTemp = new wxMenuItem(contextMenu.get(), CONTEXT_FILTER_TEMP, wxString(_("Include temporarily")) + wxT("\tSPACE")); + wxMenuItem* menuItemInclTemp = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Include temporarily")) + wxT("\tSPACE")); menuItemInclTemp->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("checkboxTrue"))); contextMenu->Append(menuItemInclTemp); } } else { - contextMenu->Append(CONTEXT_FILTER_TEMP, wxString(_("Exclude temporarily")) + wxT("\tSPACE")); //this element should always be visible - contextMenu->Enable(CONTEXT_FILTER_TEMP, false); + contextMenu->Append(contextItemID, wxString(_("Exclude temporarily")) + wxT("\tSPACE")); //this element should always be visible + contextMenu->Enable(contextItemID, false); } + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextFilterTemp), NULL, this); + //############################################################################################### //get list of relative file/dir-names for filtering @@ -1530,12 +1678,12 @@ void MainDialog::OnContextRim(wxGridEvent& event) const Zstring extension = filename.AfterLast(Zchar('.')); //add context menu item - wxMenuItem* menuItemExclExt = new wxMenuItem(contextMenu.get(), CONTEXT_EXCLUDE_EXT, wxString(_("Exclude via filter:")) + wxT(" ") + wxT("*.") + zToWx(extension)); + wxMenuItem* menuItemExclExt = new wxMenuItem(contextMenu.get(), ++contextItemID, wxString(_("Exclude via filter:")) + wxT(" ") + wxT("*.") + zToWx(extension)); menuItemExclExt->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmall"))); contextMenu->Append(menuItemExclExt); //connect event - contextMenu->Connect(CONTEXT_EXCLUDE_EXT, + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextExcludeExtension), new SelectedExtension(extension), //ownership passed! @@ -1545,11 +1693,12 @@ void MainDialog::OnContextRim(wxGridEvent& event) //CONTEXT_EXCLUDE_OBJ + ++contextItemID; wxMenuItem* menuItemExclObj = NULL; if (exFilterCandidateObj.size() == 1) - menuItemExclObj = new wxMenuItem(contextMenu.get(), CONTEXT_EXCLUDE_OBJ, wxString(_("Exclude via filter:")) + wxT(" ") + zToWx(exFilterCandidateObj[0].relativeName.AfterLast(common::FILE_NAME_SEPARATOR))); + menuItemExclObj = new wxMenuItem(contextMenu.get(), contextItemID, wxString(_("Exclude via filter:")) + wxT(" ") + zToWx(exFilterCandidateObj[0].relativeName.AfterLast(common::FILE_NAME_SEPARATOR))); else if (exFilterCandidateObj.size() > 1) - menuItemExclObj = new wxMenuItem(contextMenu.get(), CONTEXT_EXCLUDE_OBJ, wxString(_("Exclude via filter:")) + wxT(" ") + _("<multiple selection>")); + menuItemExclObj = new wxMenuItem(contextMenu.get(), contextItemID, wxString(_("Exclude via filter:")) + wxT(" ") + _("<multiple selection>")); if (menuItemExclObj != NULL) { @@ -1557,7 +1706,7 @@ void MainDialog::OnContextRim(wxGridEvent& event) contextMenu->Append(menuItemExclObj); //connect event - contextMenu->Connect(CONTEXT_EXCLUDE_OBJ, + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextExcludeObject), new FilterObjContainer(exFilterCandidateObj), //ownership passed! @@ -1565,7 +1714,6 @@ void MainDialog::OnContextRim(wxGridEvent& event) } - //CONTEXT_EXTERNAL_APP if (!globalSettings->gui.externelApplications.empty()) { @@ -1574,57 +1722,51 @@ void MainDialog::OnContextRim(wxGridEvent& event) const bool externalAppEnabled = (m_gridLeft->isLeadGrid() || m_gridRight->isLeadGrid()) && (selectionLeft.size() + selectionRight.size() == 1); - int newID = externalAppIDFirst; for (xmlAccess::ExternalApps::iterator i = globalSettings->gui.externelApplications.begin(); i != globalSettings->gui.externelApplications.end(); - ++i, ++newID) + ++i) { //some trick to translate default external apps on the fly: 1. "open in explorer" 2. "start directly" wxString description = wxGetTranslation(i->first); if (description.empty()) description = wxT(" "); //wxWidgets doesn't like empty items + ++contextItemID; if (i == globalSettings->gui.externelApplications.begin()) - contextMenu->Append(newID, description + wxT("\t") + wxString(_("D-Click")) + wxT("; ENTER")); + contextMenu->Append(contextItemID, description + wxT("\t") + wxString(_("D-Click")) + wxT("; ENTER")); else - contextMenu->Append(newID, description); + contextMenu->Append(contextItemID, description); + contextMenu->Enable(contextItemID, externalAppEnabled); - contextMenu->Enable(newID, externalAppEnabled); - - //register event - contextMenu->Connect(newID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextOpenWith), NULL, this); + contextMenu->Connect(contextItemID, + wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MainDialog::OnContextOpenWith), + new CtxtSelectionString(i->second), //ownership passed! + this); } } - contextMenu->AppendSeparator(); //CONTEXT_CLIPBOARD - contextMenu->Append(CONTEXT_CLIPBOARD, _("Copy to clipboard\tCTRL+C")); + contextMenu->Append(++contextItemID, _("Copy to clipboard\tCTRL+C")); if ( (m_gridLeft->isLeadGrid() && selectionLeft.size()) || (m_gridRight->isLeadGrid() && selectionRight.size())) - contextMenu->Enable(CONTEXT_CLIPBOARD, true); + contextMenu->Enable(contextItemID, true); else - contextMenu->Enable(CONTEXT_CLIPBOARD, false); + contextMenu->Enable(contextItemID, false); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCopyClipboard), NULL, this); //CONTEXT_DELETE_FILES - contextMenu->Append(CONTEXT_DELETE_FILES, _("Delete files\tDEL")); + contextMenu->Append(++contextItemID, _("Delete files\tDEL")); if (selectionLeft.size() + selectionRight.size() == 0) - contextMenu->Enable(CONTEXT_DELETE_FILES, false); - + contextMenu->Enable(contextItemID, false); - //############################################################################################### - //connect events - contextMenu->Connect(CONTEXT_FILTER_TEMP, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextFilterTemp), NULL, this); - contextMenu->Connect(CONTEXT_CLIPBOARD, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCopyClipboard), NULL, this); - contextMenu->Connect(CONTEXT_DELETE_FILES, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextDeleteFiles), NULL, this); - contextMenu->Connect(CONTEXT_SYNC_DIR_LEFT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirLeft), NULL, this); - contextMenu->Connect(CONTEXT_SYNC_DIR_NONE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirNone), NULL, this); - contextMenu->Connect(CONTEXT_SYNC_DIR_RIGHT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncDirRight), NULL, this); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextDeleteFiles), NULL, this); //show context menu PopupMenu(contextMenu.get()); @@ -1723,22 +1865,13 @@ void MainDialog::OnContextCopyClipboard(wxCommandEvent& event) void MainDialog::OnContextOpenWith(wxCommandEvent& event) { - if (m_gridLeft->isLeadGrid() || m_gridRight->isLeadGrid()) - { - const CustomGrid* leadGrid = m_gridLeft->isLeadGrid() ? - static_cast<CustomGrid*>(m_gridLeft) : - static_cast<CustomGrid*>(m_gridRight); - std::set<size_t> selection = getSelectedRows(leadGrid); - - const int index = event.GetId() - externalAppIDFirst; - - if ( selection.size() == 1 && - 0 <= index && static_cast<size_t>(index) < globalSettings->gui.externelApplications.size()) - openExternalApplication(*selection.begin(), m_gridLeft->isLeadGrid(), globalSettings->gui.externelApplications[index].second); - } + CtxtSelectionString* stringObj = dynamic_cast<CtxtSelectionString*>(event.m_callbackUserData); + if (stringObj) + openExternalApplication(stringObj->objName); } + void MainDialog::OnContextDeleteFiles(wxCommandEvent& event) { deleteSelectedFiles(); @@ -1771,17 +1904,18 @@ void MainDialog::OnContextSyncDirRight(wxCommandEvent& event) void MainDialog::OnContextRimLabelLeft(wxGridEvent& event) { + int ctxtElementId = 1000; + contextMenu.reset(new wxMenu); //re-create context menu - contextMenu->Append(CONTEXT_CUSTOMIZE_COLUMN_LEFT, _("Customize...")); + contextMenu->Append(++ctxtElementId, _("Customize...")); + contextMenu->Connect(ctxtElementId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCustColumnLeft), NULL, this); contextMenu->AppendSeparator(); - wxMenuItem* itemAutoAdjust = new wxMenuItem(contextMenu.get(), CONTEXT_AUTO_ADJUST_COLUMN_LEFT, _("Auto-adjust columns"), wxEmptyString, wxITEM_CHECK); + wxMenuItem* itemAutoAdjust = new wxMenuItem(contextMenu.get(), ++ctxtElementId, _("Auto-adjust columns"), wxEmptyString, wxITEM_CHECK); contextMenu->Append(itemAutoAdjust); itemAutoAdjust->Check(globalSettings->gui.autoAdjustColumnsLeft); - - contextMenu->Connect(CONTEXT_CUSTOMIZE_COLUMN_LEFT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCustColumnLeft), NULL, this); - contextMenu->Connect(CONTEXT_AUTO_ADJUST_COLUMN_LEFT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextAutoAdjustLeft), NULL, this); + contextMenu->Connect(ctxtElementId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextAutoAdjustLeft), NULL, this); PopupMenu(contextMenu.get()); //show context menu } @@ -1789,17 +1923,19 @@ void MainDialog::OnContextRimLabelLeft(wxGridEvent& event) void MainDialog::OnContextRimLabelRight(wxGridEvent& event) { + int ctxtElementId = 1000; + contextMenu.reset(new wxMenu); //re-create context menu - contextMenu->Append(CONTEXT_CUSTOMIZE_COLUMN_RIGHT, _("Customize...")); + + contextMenu->Append(++ctxtElementId, _("Customize...")); + contextMenu->Connect(ctxtElementId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCustColumnRight), NULL, this); contextMenu->AppendSeparator(); - wxMenuItem* itemAutoAdjust = new wxMenuItem(contextMenu.get(), CONTEXT_AUTO_ADJUST_COLUMN_RIGHT, _("Auto-adjust columns"), wxEmptyString, wxITEM_CHECK); + wxMenuItem* itemAutoAdjust = new wxMenuItem(contextMenu.get(), ++ctxtElementId, _("Auto-adjust columns"), wxEmptyString, wxITEM_CHECK); contextMenu->Append(itemAutoAdjust); itemAutoAdjust->Check(globalSettings->gui.autoAdjustColumnsRight); - - contextMenu->Connect(CONTEXT_CUSTOMIZE_COLUMN_RIGHT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextCustColumnRight), NULL, this); - contextMenu->Connect(CONTEXT_AUTO_ADJUST_COLUMN_RIGHT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextAutoAdjustRight), NULL, this); + contextMenu->Connect(ctxtElementId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextAutoAdjustRight), NULL, this); PopupMenu(contextMenu.get()); //show context menu } @@ -1851,19 +1987,20 @@ void MainDialog::OnContextAutoAdjustRight(wxCommandEvent& event) void MainDialog::OnContextMiddle(wxGridEvent& event) { - contextMenu.reset(new wxMenu); //re-create context menu + int contextItemID = 2000; - contextMenu->Append(CONTEXT_CHECK_ALL, _("Include all rows")); - contextMenu->Append(CONTEXT_UNCHECK_ALL, _("Exclude all rows")); + contextMenu.reset(new wxMenu); //re-create context menu + contextMenu->Append(++contextItemID, _("Include all rows")); if (gridDataView->rowsTotal() == 0) - { - contextMenu->Enable(CONTEXT_CHECK_ALL, false); - contextMenu->Enable(CONTEXT_UNCHECK_ALL, false); - } + contextMenu->Enable(contextItemID, false); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextIncludeAll), NULL, this); + - contextMenu->Connect(CONTEXT_CHECK_ALL, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextIncludeAll), NULL, this); - contextMenu->Connect(CONTEXT_UNCHECK_ALL, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextExcludeAll), NULL, this); + contextMenu->Append(++contextItemID, _("Exclude all rows")); + if (gridDataView->rowsTotal() == 0) + contextMenu->Enable(contextItemID, false); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextExcludeAll), NULL, this); PopupMenu(contextMenu.get()); //show context menu } @@ -1871,10 +2008,15 @@ void MainDialog::OnContextMiddle(wxGridEvent& event) void MainDialog::OnContextMiddleLabel(wxGridEvent& event) { + int contextItemID = 2000; + contextMenu.reset(new wxMenu); //re-create context menu - wxMenuItem* itemSyncPreview = new wxMenuItem(contextMenu.get(), CONTEXT_SYNC_PREVIEW, _("Synchronization Preview")); - wxMenuItem* itemCmpResult = new wxMenuItem(contextMenu.get(), CONTEXT_COMPARISON_RESULT, _("Comparison Result")); + wxMenuItem* itemSyncPreview = new wxMenuItem(contextMenu.get(), ++contextItemID, _("Synchronization Preview")); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncView), NULL, this); + + wxMenuItem* itemCmpResult = new wxMenuItem(contextMenu.get(), ++contextItemID, _("Comparison Result")); + contextMenu->Connect(contextItemID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextComparisonView), NULL, this); if (syncPreview->previewIsEnabled()) itemSyncPreview->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("syncViewSmall"))); @@ -1884,13 +2026,66 @@ void MainDialog::OnContextMiddleLabel(wxGridEvent& event) contextMenu->Append(itemCmpResult); contextMenu->Append(itemSyncPreview); - contextMenu->Connect(CONTEXT_SYNC_PREVIEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSyncView), NULL, this); - contextMenu->Connect(CONTEXT_COMPARISON_RESULT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextComparisonView), NULL, this); + PopupMenu(contextMenu.get()); //show context menu +} + + +void MainDialog::OnContextSetLayout(wxMouseEvent& event) +{ + int itemId = 1000; + + contextMenu.reset(new wxMenu); //re-create context menu + + contextMenu->Append(++itemId, _("Reset view")); + contextMenu->Connect(itemId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextSetLayoutReset), NULL, this); + + typedef std::vector<std::pair<wxString, wxString> > CaptionNameMapping; + CaptionNameMapping captionNameMap; + + const wxAuiPaneInfoArray& paneArray = auiMgr.GetAllPanes(); + for (size_t i = 0; i < paneArray.size(); ++i) + if (!paneArray[i].IsShown() && !paneArray[i].name.empty() && paneArray[i].window != compareStatus->getAsWindow()) + captionNameMap.push_back(std::make_pair(paneArray[i].caption, paneArray[i].name)); + + if (!captionNameMap.empty()) + { + contextMenu->AppendSeparator(); + + for (CaptionNameMapping::const_iterator i = captionNameMap.begin(); i != captionNameMap.end(); ++i) + { + wxString entry = _("Show \"%x\""); + entry.Replace(wxT("%x"), i->first); + + contextMenu->Append(++itemId, entry); + contextMenu->Connect(itemId, + wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(MainDialog::OnContextSetLayoutShowPanel), + new CtxtSelectionString(i->second), //ownership passed! + this); + } + } PopupMenu(contextMenu.get()); //show context menu } +void MainDialog::OnContextSetLayoutReset(wxCommandEvent& event) +{ + auiMgr.LoadPerspective(defaultPerspective); +} + + +void MainDialog::OnContextSetLayoutShowPanel(wxCommandEvent& event) +{ + CtxtSelectionString* stringObj = dynamic_cast<CtxtSelectionString*>(event.m_callbackUserData); + if (stringObj) + { + auiMgr.GetPane(stringObj->objName).Show(); + auiMgr.Update(); + } +} + + void MainDialog::OnContextIncludeAll(wxCommandEvent& event) { ffs3::setActiveStatus(true, gridDataView->getDataTentative()); @@ -1941,54 +2136,47 @@ wxString getFormattedHistoryElement(const wxString& filename) } -//tests if the same filenames are specified, even if they are relative to the current working directory/include symlinks or \\?\ prefix -class FindDuplicates -{ -public: - FindDuplicates(const Zstring& name) : m_name(name) {} - - bool operator()(const wxString& other) const - { - return util::sameFileSpecified(m_name, wxToZ(other)); - } - -private: - const Zstring& m_name; -}; - - void MainDialog::addFileToCfgHistory(const wxString& filename) { //only (still) existing files should be included in the list if (util::fileExists(wxToZ(filename), 200) == util::EXISTING_FALSE) //potentially slow network access: wait 200ms return; - std::vector<wxString>::const_iterator i = find_if(cfgFileNames.begin(), cfgFileNames.end(), FindDuplicates(wxToZ(filename))); - if (i != cfgFileNames.end()) + int posFound = -1; + + for (int i = 0; i < static_cast<int>(m_listBoxHistory->GetCount()); ++i) + if (m_listBoxHistory->GetClientObject(i)) + { + const wxString& filenameTmp = static_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(i))->name_; + + //tests if the same filenames are specified, even if they are relative to the current working directory/include symlinks or \\?\ prefix + if (util::sameFileSpecified(wxToZ(filename), wxToZ(filenameTmp))) + { + posFound = i; + break; + } + } + + if (posFound != -1) { //if entry is in the list, then jump to element - m_choiceHistory->SetSelection(i - cfgFileNames.begin()); + m_listBoxHistory->SetSelection(posFound); } else { - cfgFileNames.insert(cfgFileNames.begin(), filename); - + int newPos = -1; //the default config file should receive another name on GUI if (util::sameFileSpecified(wxToZ(lastConfigFileName()), wxToZ(filename))) - m_choiceHistory->Insert(_("<Last session>"), 0); //insert at beginning of list + newPos = m_listBoxHistory->Append(_("<Last session>"), new wxClientDataString(filename)); //insert at beginning of list else - m_choiceHistory->Insert(getFormattedHistoryElement(filename), 0); //insert at beginning of list + newPos = m_listBoxHistory->Append(getFormattedHistoryElement(filename), new wxClientDataString(filename)); //insert at beginning of list - m_choiceHistory->SetSelection(0); + m_listBoxHistory->SetSelection(newPos); } //keep maximal size of history list - if (cfgFileNames.size() > globalSettings->gui.cfgHistoryMax) - { - //delete last rows - cfgFileNames.pop_back(); - m_choiceHistory->Delete(globalSettings->gui.cfgHistoryMax); - } + //if (m_comboHistory->GetCount() > globalSettings->gui.cfgHistoryMax) + // m_comboHistory->Delete(globalSettings->gui.cfgHistoryMax); } @@ -2071,9 +2259,13 @@ void MainDialog::OnNewConfig(wxCommandEvent& event) void MainDialog::OnLoadFromHistory(wxCommandEvent& event) { - const int selectedItem = m_choiceHistory->GetSelection(); - if (0 <= selectedItem && unsigned(selectedItem) < cfgFileNames.size()) - loadConfiguration(cfgFileNames[selectedItem]); + const int selectedItem = m_listBoxHistory->GetSelection(); + if ( selectedItem != wxNOT_FOUND && + m_listBoxHistory->GetClientObject(selectedItem)) + { + const wxString filename = static_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(selectedItem))->name_; + loadConfiguration(filename); + } } @@ -2128,26 +2320,50 @@ void MainDialog::OnCfgHistoryKeyEvent(wxKeyEvent& event) if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) { //try to delete the currently selected config history item - const int selectedItem = m_choiceHistory->GetCurrentSelection(); - if ( 0 <= selectedItem && - selectedItem < int(m_choiceHistory->GetCount()) && - selectedItem < int(cfgFileNames.size())) + //const int selectedItem = m_listBoxHistory->GetCurrentSelection(); + const int selectedItem = m_listBoxHistory->GetSelection(); + if (selectedItem != wxNOT_FOUND) { - //delete selected row - cfgFileNames.erase(cfgFileNames.begin() + selectedItem); - m_choiceHistory->Delete(selectedItem); + m_listBoxHistory->Delete(selectedItem); + + //set selection on next element + if (m_listBoxHistory->GetCount() > 0) + { + int newSelection = selectedItem; + if (newSelection >= static_cast<int>(m_listBoxHistory->GetCount())) + newSelection = m_listBoxHistory->GetCount() - 1; + m_listBoxHistory->SetSelection(newSelection); + } } + + return; //"swallow" event } + event.Skip(); } -void MainDialog::OnClose(wxCloseEvent &event) +void MainDialog::OnClose(wxCloseEvent& event) { - if (!saveOldConfig()) //notify user about changed settings - return; + if (m_buttonAbort->IsShown()) //delegate to "abort" button if available + { + wxCommandEvent dummy(wxEVT_COMMAND_BUTTON_CLICKED); + m_buttonAbort->ProcessEvent(dummy); - Destroy(); + if (event.CanVeto()) event.Veto(); //that's what we want here + else Destroy(); //shouldn't be necessary + } + else + { + const bool cancelled = !saveOldConfig(); //notify user about changed settings + if (cancelled && event.CanVeto()) + { + event.Veto(); + return; + } + + Destroy(); + } } @@ -2261,16 +2477,14 @@ bool MainDialog::writeConfigurationToXml(const wxString& filename) try { xmlAccess::writeConfig(guiCfg, filename); + setLastUsedConfig(filename, guiCfg); + return true; } catch (const xmlAccess::XmlError& error) { wxMessageBox(error.msg().c_str(), _("Error"), wxOK | wxICON_ERROR); return false; } - - setLastUsedConfig(filename, guiCfg); - - return true; } @@ -2319,7 +2533,7 @@ void MainDialog::setCurrentConfiguration(const xmlAccess::XmlGuiConfig& newGuiCf //update sync variant name m_staticTextSyncVariant->SetLabel(wxString(wxT("(")) + currentCfg.mainCfg.getSyncVariantName() + wxT(")")); - bSizer6->Layout(); //adapt layout for variant text + m_panelTopButtons->Layout(); //adapt layout for variant text } @@ -2633,31 +2847,16 @@ void MainDialog::initViewFilterButtons() void MainDialog::updateFilterButtons() { - //prepare filter icon - if (m_notebookBottomLeft->GetImageList() == NULL) - { - wxImageList* panelIcons = new wxImageList(16, 16); - panelIcons->Add(wxBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmall")))); - panelIcons->Add(wxBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmallGrey")))); - m_notebookBottomLeft->AssignImageList(panelIcons); //pass ownership - } - //global filter: test for Null-filter if (isNullFilter(currentCfg.mainCfg.globalFilter)) { m_bpButtonFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterOff"))); m_bpButtonFilter->SetToolTip(_("No filter selected")); - - //additional filter icon - m_notebookBottomLeft->SetPageImage(1, 1); } else { m_bpButtonFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterOn"))); m_bpButtonFilter->SetToolTip(_("Filter is active")); - - //show filter icon - m_notebookBottomLeft->SetPageImage(1, 0); } //update main local filter @@ -2729,9 +2928,9 @@ void MainDialog::OnCompare(wxCommandEvent &event) m_buttonStartSync->SetFocus(); //hide sort direction indicator on GUI grids - m_gridLeft->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); + m_gridLeft ->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); m_gridMiddle->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); - m_gridRight->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); + m_gridRight ->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); //reset last sort selection: used for determining sort direction lastSortColumn = -1; @@ -2749,10 +2948,8 @@ void MainDialog::OnCompare(wxCommandEvent &event) updateGuiGrid(); //prepare status information - wxString statusInfo; if (allElementsEqual(gridDataView->getDataTentative())) - statusInfo += _("All directories in sync!"); - pushStatusInformation(statusInfo); + pushStatusInformation(_("All directories in sync!")); } } @@ -2792,6 +2989,8 @@ void MainDialog::updateGuiGrid() //update sync preview statistics calculatePreview(); + auiMgr.Update(); //fix small display distortion, if view filter panel is empty + m_gridLeft ->Refresh(); m_gridMiddle->Refresh(); m_gridRight ->Refresh(); @@ -2852,7 +3051,7 @@ void MainDialog::OnCmpSettings(wxCommandEvent& event) { //update compare variant name m_staticTextCmpVariant->SetLabel(wxString(wxT("(")) + getVariantName(currentCfg.mainCfg.compareVar) + wxT(")")); - bSizer6->Layout(); //adapt layout for variant text + m_panelTopButtons->Layout(); //adapt layout for variant text //disable the sync button syncPreview->enableSynchronization(false); @@ -3278,13 +3477,9 @@ void MainDialog::updateGridViewData() m_panelViewFilter->Hide(); } - - bSizer3->Layout(); - - //update status information + //clear status information clearStatusBar(); - wxString statusLeftNew; wxString statusMiddleNew; wxString statusRightNew; @@ -3426,7 +3621,7 @@ void MainDialog::updateSyncConfig() { //update sync variant name m_staticTextSyncVariant->SetLabel(wxString(wxT("(")) + getCurrentConfiguration().mainCfg.getSyncVariantName() + wxT(")")); - bSizer6->Layout(); //adapt layout for variant text + m_panelTopButtons->Layout(); //adapt layout for variant text class RedetermineCallback : public DeterminationProblem @@ -3463,6 +3658,8 @@ void MainDialog::OnRemoveTopFolderPair(wxCommandEvent& event) { if (additionalFolderPairs.size() > 0) { + wxWindowUpdateLocker dummy(this); //avoid display distortion + //get settings from second folder pair const FolderPairEnh cfgSecond = getEnahncedPair(additionalFolderPairs[0]); @@ -3487,6 +3684,8 @@ void MainDialog::OnRemoveTopFolderPair(wxCommandEvent& event) void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) { + wxWindowUpdateLocker dummy(this); //avoid display distortion + const wxObject* const eventObj = event.GetEventObject(); //find folder pair originating the event for (std::vector<DirectoryPair*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) if (eventObj == (*i)->m_bpButtonRemovePair) @@ -3512,7 +3711,6 @@ void MainDialog::updateGuiForFolderPair() m_bpButtonRemovePair->Hide(); else m_bpButtonRemovePair->Show(); - m_panelTopRight->Layout(); //adapt local filter and sync cfg for first folder pair @@ -3533,14 +3731,28 @@ void MainDialog::updateGuiForFolderPair() m_bpButtonSwapSides->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("swapSlim"))); } - m_panelTopMiddle->Layout(); + + + int addPairHeight = 0; + if (additionalFolderPairs.size() > 0) + addPairHeight = std::min<double>(1.5, additionalFolderPairs.size()) * //have 0.5 * height indicate that more folders are there + additionalFolderPairs[0]->GetSize().GetHeight(); + + //ensure additional folder pairs are at least partially visible + auiMgr.GetPane(m_panelDirectoryPairs).MinSize(-1, m_panelTopLeft->GetSize().GetHeight() + addPairHeight); + auiMgr.Update(); + + m_scrolledWindowFolderPairs->Fit(); //adjust scrolled window size + + //m_scrolledWindowFolderPairs->Layout(); //adjust stuff inside scrolled window + m_panelDirectoryPairs->Layout(); } void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool addFront) { - wxWindowUpdateLocker dummy(this); //avoid display distortion + wxWindowUpdateLocker dummy(m_panelDirectoryPairs); //avoid display distortion if (!newPairs.empty()) { @@ -3550,9 +3762,6 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool //add new folder pair DirectoryPair* newPair = new DirectoryPair(m_scrolledWindowFolderPairs, *this); - //correct width of middle block - newPair->m_panel21->SetMinSize(wxSize(m_gridMiddle->GetSize().GetWidth(), -1)); - //set width of left folder panel const int width = m_panelTopLeft->GetSize().GetWidth(); newPair->m_panelLeft->SetMinSize(wxSize(width, -1)); @@ -3583,13 +3792,12 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool } //set size of scrolled window - const size_t visiblePairs = std::min(additionalFolderPairs.size(), globalSettings->gui.addFolderPairCountMax); //up to "addFolderPairCountMax" additional pairs shall be shown - m_scrolledWindowFolderPairs->SetMinSize(wxSize( -1, pairHeight * static_cast<int>(visiblePairs))); + //m_scrolledWindowFolderPairs->SetMinSize(wxSize( -1, pairHeight * static_cast<int>(visiblePairs))); //update controls - m_scrolledWindowFolderPairs->Fit(); //adjust scrolled window size - m_scrolledWindowFolderPairs->Layout(); //adjust stuff inside scrolled window - bSizer1->Layout(); +// m_scrolledWindowFolderPairs->Fit(); //adjust scrolled window size + // m_scrolledWindowFolderPairs->Layout(); //adjust stuff inside scrolled window + //bSizer1->Layout(); } updateGuiForFolderPair(); @@ -3598,27 +3806,27 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool void MainDialog::removeAddFolderPair(size_t pos) { - wxWindowUpdateLocker dummy(this); //avoid display distortion + wxWindowUpdateLocker dummy(m_panelDirectoryPairs); //avoid display distortion if (pos < additionalFolderPairs.size()) { //remove folder pairs from window DirectoryPair* pairToDelete = additionalFolderPairs[pos]; - const int pairHeight = pairToDelete->GetSize().GetHeight(); + //const int pairHeight = pairToDelete->GetSize().GetHeight(); bSizerAddFolderPairs->Detach(pairToDelete); //Remove() does not work on Window*, so do it manually pairToDelete->Destroy(); // additionalFolderPairs.erase(additionalFolderPairs.begin() + pos); //remove element from vector //set size of scrolled window - const size_t additionalRows = additionalFolderPairs.size(); - if (additionalRows <= globalSettings->gui.addFolderPairCountMax) //up to "addFolderPairCountMax" additional pairs shall be shown - m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, pairHeight * static_cast<int>(additionalRows))); + //const size_t additionalRows = additionalFolderPairs.size(); + //if (additionalRows <= globalSettings->gui.addFolderPairCountMax) //up to "addFolderPairCountMax" additional pairs shall be shown + // m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, pairHeight * static_cast<int>(additionalRows))); //update controls - m_scrolledWindowFolderPairs->Fit(); //adjust scrolled window size - m_scrolledWindowFolderPairs->Layout(); //adjust stuff inside scrolled window - bSizer1->Layout(); + //m_scrolledWindowFolderPairs->Fit(); //adjust scrolled window size + //m_scrolledWindowFolderPairs->Layout(); //adjust stuff inside scrolled window + //bSizer1->Layout(); } updateGuiForFolderPair(); @@ -3627,13 +3835,14 @@ void MainDialog::removeAddFolderPair(size_t pos) void MainDialog::clearAddFolderPairs() { - wxWindowUpdateLocker dummy(this); //avoid display distortion + wxWindowUpdateLocker dummy(m_panelDirectoryPairs); //avoid display distortion additionalFolderPairs.clear(); bSizerAddFolderPairs->Clear(true); - m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, 0)); - bSizer1->Layout(); + updateGuiForFolderPair(); + //m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, 0)); + //bSizer1->Layout(); } //######################################################################################################## @@ -3793,10 +4002,12 @@ void MainDialog::OnLayoutWindowAsync(wxIdleEvent& event) wxWindowUpdateLocker dummy(this); //avoid display distortion //adjust folder pair distortion on startup - m_scrolledWindowFolderPairs->Fit(); + for (std::vector<DirectoryPair*>::iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + (*i)->Layout(); + m_panelTopButtons->Layout(); Layout(); //strangely this layout call works if called in next idle event only - Refresh(); + auiMgr.Update(); //fix view filter distortion } |