diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/Taskbar_Seven/Taskbar_Seven.vcxproj | 8 | ||||
-rw-r--r-- | ui/batch_status_handler.cpp | 15 | ||||
-rw-r--r-- | ui/check_version.cpp | 4 | ||||
-rw-r--r-- | ui/custom_grid.cpp | 12 | ||||
-rw-r--r-- | ui/dir_name.cpp | 2 | ||||
-rw-r--r-- | ui/gui_generated.cpp | 654 | ||||
-rw-r--r-- | ui/gui_generated.h | 153 | ||||
-rw-r--r-- | ui/gui_status_handler.cpp | 12 | ||||
-rw-r--r-- | ui/gui_status_handler.h | 3 | ||||
-rw-r--r-- | ui/main_dlg.cpp | 288 | ||||
-rw-r--r-- | ui/main_dlg.h | 18 | ||||
-rw-r--r-- | ui/msg_popup.h | 9 | ||||
-rw-r--r-- | ui/progress_indicator.cpp | 979 | ||||
-rw-r--r-- | ui/progress_indicator.h | 8 | ||||
-rw-r--r-- | ui/small_dlgs.cpp | 15 | ||||
-rw-r--r-- | ui/switch_to_gui.h | 2 | ||||
-rw-r--r-- | ui/sync_cfg.cpp | 48 | ||||
-rw-r--r-- | ui/taskbar.cpp | 10 | ||||
-rw-r--r-- | ui/taskbar.h | 4 | ||||
-rw-r--r-- | ui/tray_icon.cpp | 224 | ||||
-rw-r--r-- | ui/tray_icon.h | 38 | ||||
-rw-r--r-- | ui/tree_view.cpp | 6 |
22 files changed, 1421 insertions, 1091 deletions
diff --git a/ui/Taskbar_Seven/Taskbar_Seven.vcxproj b/ui/Taskbar_Seven/Taskbar_Seven.vcxproj index 8b8ab5ce..02c4b67b 100644 --- a/ui/Taskbar_Seven/Taskbar_Seven.vcxproj +++ b/ui/Taskbar_Seven/Taskbar_Seven.vcxproj @@ -85,7 +85,7 @@ </BuildLog> <ClCompile> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;_DEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> @@ -120,7 +120,7 @@ </Midl> <ClCompile> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;_DEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> @@ -153,7 +153,7 @@ <ClCompile> <Optimization>MaxSpeed</Optimization> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> @@ -190,7 +190,7 @@ <ClCompile> <Optimization>MaxSpeed</Optimization> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;_WINDOWS;_USRDLL;TASKBAR_SEVEN_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <FunctionLevelLinking>true</FunctionLevelLinking> <PrecompiledHeader> diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp index 0dfd6957..a72aab3e 100644 --- a/ui/batch_status_handler.cpp +++ b/ui/batch_status_handler.cpp @@ -8,8 +8,9 @@ #include <zen/file_handling.h> #include <zen/file_traverser.h> #include <zen/format_unit.h> -#include <wx+/app_main.h> +//#include <wx+/app_main.h> #include <wx+/shell_execute.h> +#include <wx/app.h> #include "msg_popup.h" #include "exec_finished_box.h" #include "../lib/ffs_paths.h" @@ -217,7 +218,7 @@ BatchStatusHandler::~BatchStatusHandler() } else { - if (progressDlg->getAsWindow()->IsShown()) + if (progressDlg->getWindowIfVisible()) showFinalResults = true; //execute "on completion" command (even in case of ignored errors) @@ -236,7 +237,7 @@ BatchStatusHandler::~BatchStatusHandler() if (showFinalResults) //warning: wxWindow::Show() is called within processHasFinished()! { //notify about (logical) application main window => program won't quit, but stay on this dialog - setMainWindow(progressDlg->getAsWindow()); + //setMainWindow(progressDlg->getAsWindow()); -> not required anymore since we block waiting until dialog is closed below //notify to progressDlg that current process has ended if (abortIsRequested()) @@ -257,7 +258,7 @@ BatchStatusHandler::~BatchStatusHandler() //-> nicely manages dialog lifetime while (progressDlg) { - updateUiNow(); //*first* refresh GUI (removing flicker) before sleeping! + wxTheApp->Yield(); //*first* refresh GUI (removing flicker) before sleeping! boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)); } } @@ -306,7 +307,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool& forceUiRefresh(); bool dontWarnAgain = false; - switch (showWarningDlg(progressDlg->getAsWindow(), + switch (showWarningDlg(progressDlg->getWindowIfVisible(), ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_SWITCH | ReturnWarningDlg::BUTTON_CANCEL, warningMessage + L"\n\n" + _("Press \"Switch\" to resolve issues in FreeFileSync main dialog."), dontWarnAgain)) @@ -352,7 +353,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er forceUiRefresh(); bool ignoreNextErrors = false; - switch (showErrorDlg(progressDlg->getAsWindow(), + switch (showErrorDlg(progressDlg->getWindowIfVisible(), ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL, errorMessage, &ignoreNextErrors)) { @@ -399,7 +400,7 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage) forceUiRefresh(); bool ignoreNextErrors = false; - switch (showFatalErrorDlg(progressDlg->getAsWindow(), + switch (showFatalErrorDlg(progressDlg->getWindowIfVisible(), ReturnFatalErrorDlg::BUTTON_IGNORE | ReturnFatalErrorDlg::BUTTON_CANCEL, errorMessage, &ignoreNextErrors)) { diff --git a/ui/check_version.cpp b/ui/check_version.cpp index 2e4c387a..e51c1784 100644 --- a/ui/check_version.cpp +++ b/ui/check_version.cpp @@ -233,11 +233,11 @@ void zen::checkForUpdateNow(wxWindow* parent) wxLaunchDefaultBrowser(L"http://freefilesync.sourceforge.net/get_latest.php"); } else - wxMessageBox(_("FreeFileSync is up to date."), _("Information"), wxOK | wxICON_INFORMATION, parent); + wxMessageBox(_("FreeFileSync is up to date."), L"FreeFileSync - " + _("Information"), wxOK | wxICON_INFORMATION, parent); break; case GET_VER_NO_CONNECTION: - wxMessageBox(_("Unable to connect to sourceforge.net."), _("Error"), wxOK | wxICON_ERROR, parent); + wxMessageBox(_("Unable to connect to sourceforge.net."), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, parent); break; case GET_VER_PAGE_NOT_FOUND: diff --git a/ui/custom_grid.cpp b/ui/custom_grid.cpp index 58e7a7e4..59e80100 100644 --- a/ui/custom_grid.cpp +++ b/ui/custom_grid.cpp @@ -811,19 +811,19 @@ public: break; case BLOCKPOS_LEFT: { - SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_LEFT); + SyncDirectionEvent evt(rowFirst, rowLast, SyncDirection::LEFT); evtHandler->ProcessEvent(evt); } break; case BLOCKPOS_MIDDLE: { - SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_NONE); + SyncDirectionEvent evt(rowFirst, rowLast, SyncDirection::NONE); evtHandler->ProcessEvent(evt); } break; case BLOCKPOS_RIGHT: { - SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_RIGHT); + SyncDirectionEvent evt(rowFirst, rowLast, SyncDirection::RIGHT); evtHandler->ProcessEvent(evt); } break; @@ -983,13 +983,13 @@ private: case BLOCKPOS_CHECK_BOX: break; case BLOCKPOS_LEFT: - drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_LEFT)), rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, buffer); + drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SyncDirection::LEFT)), rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, buffer); break; case BLOCKPOS_MIDDLE: - drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_NONE)), rect, wxALIGN_CENTER, buffer); + drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SyncDirection::NONE)), rect, wxALIGN_CENTER, buffer); break; case BLOCKPOS_RIGHT: - drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_RIGHT)), rect, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, buffer); + drawBitmapRtlMirror(dc, getSyncOpImage(fsObj->testSyncOperation(SyncDirection::RIGHT)), rect, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, buffer); break; } else //default diff --git a/ui/dir_name.cpp b/ui/dir_name.cpp index 4a3939e9..7a068343 100644 --- a/ui/dir_name.cpp +++ b/ui/dir_name.cpp @@ -227,7 +227,7 @@ void DirectoryName<NameControl>::onSelectDir(wxCommandEvent& event) errorMsg); //out, optional: call freeString() after use! if (errorMsg) { - wxMessageBox(errorMsg, _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(errorMsg, /*L"FreeFileSync - " +*/ _("Error"), wxOK | wxICON_ERROR); //component used by FFS *and* RTS! return; } if (cancelled || !selectedFolder) diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp index 3549519c..21f5f82d 100644 --- a/ui/gui_generated.cpp +++ b/ui/gui_generated.cpp @@ -1098,6 +1098,9 @@ CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWi bSizer42 = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer162StretchSpeedAndRemTimeIndependently; + bSizer162StretchSpeedAndRemTimeIndependently = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer157; bSizer157 = new wxBoxSizer( wxVERTICAL ); @@ -1142,10 +1145,10 @@ CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWi bSizer157->Add( bSizerFilesRemaining, 0, 0, 5 ); - bSizer42->Add( bSizer157, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer162StretchSpeedAndRemTimeIndependently->Add( bSizer157, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + bSizer162StretchSpeedAndRemTimeIndependently->Add( 0, 0, 1, wxEXPAND, 5 ); sSizerSpeed = new wxBoxSizer( wxHORIZONTAL ); @@ -1160,11 +1163,17 @@ CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWi sSizerSpeed->Add( m_staticTextSpeed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer42->Add( sSizerSpeed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer162StretchSpeedAndRemTimeIndependently->Add( sSizerSpeed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer42->Add( bSizer162StretchSpeedAndRemTimeIndependently, 1, wxALIGN_CENTER_VERTICAL, 5 ); bSizer42->Add( 10, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer163; + bSizer163 = new wxBoxSizer( wxHORIZONTAL ); + sSizerTimeRemaining = new wxBoxSizer( wxHORIZONTAL ); m_staticTextTimeRemFixed = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -1178,10 +1187,10 @@ CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWi sSizerTimeRemaining->Add( m_staticTextRemTime, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer42->Add( sSizerTimeRemaining, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer163->Add( sSizerTimeRemaining, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + bSizer163->Add( 0, 0, 1, wxEXPAND, 5 ); sSizerTimeElapsed = new wxBoxSizer( wxHORIZONTAL ); @@ -1197,7 +1206,10 @@ CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWi sSizerTimeElapsed->Add( m_staticTextTimeElapsed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - bSizer42->Add( sSizerTimeElapsed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer163->Add( sSizerTimeElapsed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer42->Add( bSizer163, 1, wxALIGN_CENTER_VERTICAL, 5 ); bSizer40->Add( bSizer42, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); @@ -1215,17 +1227,20 @@ CompareProgressDlgGenerated::~CompareProgressDlgGenerated() { } -SyncProgressDlgGenerated::SyncProgressDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) +SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) { - this->SetSizeHints( wxSize( 470,260 ), wxDefaultSize ); - this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); - bSizerRoot = new wxBoxSizer( wxVERTICAL ); bSizer42 = new wxBoxSizer( wxHORIZONTAL ); + + bSizer42->Add( 32, 0, 0, 0, 5 ); + + + bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + m_bitmapStatus = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 32,32 ), 0 ); - bSizer42->Add( m_bitmapStatus, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + bSizer42->Add( m_bitmapStatus, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 ); m_staticTextPhase = new wxStaticText( this, wxID_ANY, _("Synchronizing..."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextPhase->Wrap( -1 ); @@ -1236,11 +1251,32 @@ SyncProgressDlgGenerated::SyncProgressDlgGenerated( wxWindow* parent, wxWindowID m_animCtrlSyncing = new wxAnimationCtrl( this, wxID_ANY, wxNullAnimation, wxDefaultPosition, wxSize( 32,32 ), wxAC_DEFAULT_STYLE ); m_animCtrlSyncing->SetMinSize( wxSize( 32,32 ) ); - bSizer42->Add( m_animCtrlSyncing, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + bSizer42->Add( m_animCtrlSyncing, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 ); - bSizerRoot->Add( bSizer42, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 5 ); + bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_bpButtonMinimizeToTray = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 32,32 ), wxBU_AUTODRAW ); + m_bpButtonMinimizeToTray->SetToolTip( _("Minimize to notification area") ); + + bSizer42->Add( m_bpButtonMinimizeToTray, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizerRoot->Add( bSizer42, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + bSizerStatusText = new wxBoxSizer( wxVERTICAL ); + + m_staticTextStatus = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextStatus->Wrap( -1 ); + bSizerStatusText->Add( m_staticTextStatus, 0, wxEXPAND|wxLEFT, 10 ); + + bSizerStatusText->Add( 0, 5, 0, 0, 5 ); + + + bSizerRoot->Add( bSizerStatusText, 0, wxEXPAND, 5 ); + + wxStaticLine* m_staticlineHeader; m_staticlineHeader = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizerRoot->Add( m_staticlineHeader, 0, wxEXPAND, 5 ); @@ -1250,101 +1286,181 @@ SyncProgressDlgGenerated::SyncProgressDlgGenerated( wxWindow* parent, wxWindowID wxBoxSizer* bSizer173; bSizer173 = new wxBoxSizer( wxVERTICAL ); - m_staticTextStatus = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextStatus->Wrap( -1 ); - bSizer173->Add( m_staticTextStatus, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); - - m_gauge1 = new wxGauge( m_panelProgress, wxID_ANY, 100, wxDefaultPosition, wxSize( -1,14 ), wxGA_HORIZONTAL ); - bSizer173->Add( m_gauge1, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); - bSizer171 = new wxBoxSizer( wxHORIZONTAL ); bSizer171->Add( 10, 0, 0, 0, 5 ); - wxFlexGridSizer* fgSizer10; - fgSizer10 = new wxFlexGridSizer( 0, 2, 2, 5 ); - fgSizer10->SetFlexibleDirection( wxBOTH ); - fgSizer10->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + wxBoxSizer* bSizer164; + bSizer164 = new wxBoxSizer( wxVERTICAL ); + + m_panelItemsProcessed = new wxPanel( m_panelProgress, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_panelItemsProcessed->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + + wxBoxSizer* bSizer165; + bSizer165 = new wxBoxSizer( wxVERTICAL ); - m_staticTextLabelItemsProc = new wxStaticText( m_panelProgress, wxID_ANY, _("Items processed:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextLabelItemsProc->Wrap( -1 ); - fgSizer10->Add( m_staticTextLabelItemsProc, 0, wxALIGN_BOTTOM, 5 ); - bSizerItemsProc = new wxBoxSizer( wxHORIZONTAL ); + bSizer165->Add( 0, 5, 0, 0, 5 ); - m_staticTextProcessedObj = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); + wxStaticText* m_staticText96; + m_staticText96 = new wxStaticText( m_panelItemsProcessed, wxID_ANY, _("Items processed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText96->Wrap( -1 ); + bSizer165->Add( m_staticText96, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizer169; + bSizer169 = new wxBoxSizer( wxHORIZONTAL ); + + m_staticTextProcessedObj = new wxStaticText( m_panelItemsProcessed, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); m_staticTextProcessedObj->Wrap( -1 ); m_staticTextProcessedObj->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - bSizerItemsProc->Add( m_staticTextProcessedObj, 0, wxALIGN_BOTTOM, 5 ); + bSizer169->Add( m_staticTextProcessedObj, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextDataProcessed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDataProcessed = new wxStaticText( m_panelItemsProcessed, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextDataProcessed->Wrap( -1 ); - bSizerItemsProc->Add( m_staticTextDataProcessed, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); + bSizer169->Add( m_staticTextDataProcessed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + + bSizer165->Add( bSizer169, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizer165->Add( 0, 5, 0, 0, 5 ); + + m_panelItemsProcessed->SetSizer( bSizer165 ); + m_panelItemsProcessed->Layout(); + bSizer165->Fit( m_panelItemsProcessed ); + bSizer164->Add( m_panelItemsProcessed, 0, wxEXPAND|wxTOP, 7 ); - fgSizer10->Add( bSizerItemsProc, 0, wxALIGN_BOTTOM, 5 ); + m_panelItemsRemaining = new wxPanel( m_panelProgress, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_panelItemsRemaining->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); - m_staticTextLabelItemsRem = new wxStaticText( m_panelProgress, wxID_ANY, _("Items remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextLabelItemsRem->Wrap( -1 ); - fgSizer10->Add( m_staticTextLabelItemsRem, 0, wxALIGN_BOTTOM, 5 ); + wxBoxSizer* bSizer166; + bSizer166 = new wxBoxSizer( wxVERTICAL ); + + + bSizer166->Add( 0, 5, 0, 0, 5 ); + + wxStaticText* m_staticText97; + m_staticText97 = new wxStaticText( m_panelItemsRemaining, wxID_ANY, _("Items remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText97->Wrap( -1 ); + bSizer166->Add( m_staticText97, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); - bSizerItemsRem = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizer170; + bSizer170 = new wxBoxSizer( wxHORIZONTAL ); - m_staticTextRemainingObj = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); + m_staticTextRemainingObj = new wxStaticText( m_panelItemsRemaining, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); m_staticTextRemainingObj->Wrap( -1 ); m_staticTextRemainingObj->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - bSizerItemsRem->Add( m_staticTextRemainingObj, 0, wxALIGN_BOTTOM, 5 ); + bSizer170->Add( m_staticTextRemainingObj, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextDataRemaining = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDataRemaining = new wxStaticText( m_panelItemsRemaining, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextDataRemaining->Wrap( -1 ); - bSizerItemsRem->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); + bSizer170->Add( m_staticTextDataRemaining, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - fgSizer10->Add( bSizerItemsRem, 0, wxALIGN_BOTTOM, 5 ); + bSizer166->Add( bSizer170, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); - m_staticText84 = new wxStaticText( m_panelProgress, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText84->Wrap( -1 ); - fgSizer10->Add( m_staticText84, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextSpeed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextSpeed->Wrap( -1 ); - m_staticTextSpeed->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + bSizer166->Add( 0, 5, 0, 0, 5 ); - fgSizer10->Add( m_staticTextSpeed, 0, wxALIGN_BOTTOM, 5 ); - m_staticTextLabelRemTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextLabelRemTime->Wrap( -1 ); - fgSizer10->Add( m_staticTextLabelRemTime, 0, wxALIGN_BOTTOM, 5 ); + m_panelItemsRemaining->SetSizer( bSizer166 ); + m_panelItemsRemaining->Layout(); + bSizer166->Fit( m_panelItemsRemaining ); + bSizer164->Add( m_panelItemsRemaining, 0, wxTOP|wxEXPAND, 7 ); + + m_panelTimeRemaining = new wxPanel( m_panelProgress, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_panelTimeRemaining->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + + wxBoxSizer* bSizer167; + bSizer167 = new wxBoxSizer( wxVERTICAL ); - m_staticTextRemTime = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + + bSizer167->Add( 0, 5, 0, 0, 5 ); + + wxStaticText* m_staticText98; + m_staticText98 = new wxStaticText( m_panelTimeRemaining, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText98->Wrap( -1 ); + bSizer167->Add( m_staticText98, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextRemTime = new wxStaticText( m_panelTimeRemaining, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextRemTime->Wrap( -1 ); m_staticTextRemTime->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - fgSizer10->Add( m_staticTextRemTime, 0, wxALIGN_BOTTOM, 5 ); + bSizer167->Add( m_staticTextRemTime, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + - m_staticTextLabelElapsedTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextLabelElapsedTime->Wrap( -1 ); - fgSizer10->Add( m_staticTextLabelElapsedTime, 0, wxALIGN_BOTTOM, 5 ); + bSizer167->Add( 0, 5, 0, 0, 5 ); - m_staticTextTimeElapsed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + + m_panelTimeRemaining->SetSizer( bSizer167 ); + m_panelTimeRemaining->Layout(); + bSizer167->Fit( m_panelTimeRemaining ); + bSizer164->Add( m_panelTimeRemaining, 0, wxTOP|wxEXPAND, 7 ); + + wxPanel* m_panelTimeElapsed; + m_panelTimeElapsed = new wxPanel( m_panelProgress, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_panelTimeElapsed->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + + wxBoxSizer* bSizer168; + bSizer168 = new wxBoxSizer( wxVERTICAL ); + + + bSizer168->Add( 0, 5, 0, 0, 5 ); + + wxStaticText* m_staticText961; + m_staticText961 = new wxStaticText( m_panelTimeElapsed, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText961->Wrap( -1 ); + bSizer168->Add( m_staticText961, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticTextTimeElapsed = new wxStaticText( m_panelTimeElapsed, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextTimeElapsed->Wrap( -1 ); m_staticTextTimeElapsed->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - fgSizer10->Add( m_staticTextTimeElapsed, 0, wxALIGN_BOTTOM, 5 ); + bSizer168->Add( m_staticTextTimeElapsed, 0, wxALIGN_BOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizer168->Add( 0, 5, 0, 0, 5 ); + + m_panelTimeElapsed->SetSizer( bSizer168 ); + m_panelTimeElapsed->Layout(); + bSizer168->Fit( m_panelTimeElapsed ); + bSizer164->Add( m_panelTimeElapsed, 0, wxTOP|wxEXPAND, 7 ); - bSizer171->Add( fgSizer10, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer171->Add( bSizer164, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer171->Add( 10, 0, 0, 0, 5 ); - m_panelGraph = new zen::Graph2D( m_panelProgress, wxID_ANY, wxDefaultPosition, wxSize( 340,150 ), wxTAB_TRAVERSAL ); - m_panelGraph->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + wxBoxSizer* bSizer161; + bSizer161 = new wxBoxSizer( wxVERTICAL ); + + + bSizer161->Add( 0, 15, 0, 0, 5 ); + + m_panelGraphBytes = new zen::Graph2D( m_panelProgress, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), 0 ); + m_panelGraphBytes->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + bSizer161->Add( m_panelGraphBytes, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_panelGraphItems = new zen::Graph2D( m_panelProgress, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), 0 ); + m_panelGraphItems->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + bSizer161->Add( m_panelGraphItems, 1, wxEXPAND, 5 ); - bSizer171->Add( m_panelGraph, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP, 10 ); + + bSizer161->Add( 420, 0, 0, 0, 5 ); + + + bSizer171->Add( bSizer161, 1, wxEXPAND, 5 ); + + + bSizer171->Add( 0, 230, 0, 0, 5 ); bSizer173->Add( bSizer171, 1, wxEXPAND, 5 ); @@ -1404,26 +1520,10 @@ SyncProgressDlgGenerated::SyncProgressDlgGenerated( wxWindow* parent, wxWindowID this->SetSizer( bSizerRoot ); this->Layout(); bSizerRoot->Fit( this ); - - this->Centre( wxBOTH ); - - // Connect Events - this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncProgressDlgGenerated::OnClose ) ); - this->Connect( wxEVT_ICONIZE, wxIconizeEventHandler( SyncProgressDlgGenerated::OnIconize ) ); - m_buttonClose->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnOkay ), NULL, this ); - m_buttonPause->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnPause ), NULL, this ); - m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnCancel ), NULL, this ); } -SyncProgressDlgGenerated::~SyncProgressDlgGenerated() +SyncProgressPanelGenerated::~SyncProgressPanelGenerated() { - // Disconnect Events - this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncProgressDlgGenerated::OnClose ) ); - this->Disconnect( wxEVT_ICONIZE, wxIconizeEventHandler( SyncProgressDlgGenerated::OnIconize ) ); - m_buttonClose->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnOkay ), NULL, this ); - m_buttonPause->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnPause ), NULL, this ); - m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncProgressDlgGenerated::OnCancel ), NULL, this ); - } LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) @@ -1439,13 +1539,13 @@ LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxP wxBoxSizer* bSizer154; bSizer154 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonErrors = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), wxBU_AUTODRAW ); + m_bpButtonErrors = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49,49 ), wxBU_AUTODRAW ); bSizer154->Add( m_bpButtonErrors, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonWarnings = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), wxBU_AUTODRAW ); + m_bpButtonWarnings = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49,49 ), wxBU_AUTODRAW ); bSizer154->Add( m_bpButtonWarnings, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonInfo = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), wxBU_AUTODRAW ); + m_bpButtonInfo = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49,49 ), wxBU_AUTODRAW ); bSizer154->Add( m_bpButtonInfo, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -1481,6 +1581,200 @@ LogPanelGenerated::~LogPanelGenerated() } +SyncConfirmationDlgGenerated::SyncConfirmationDlgGenerated( 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 ); + this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + + wxBoxSizer* bSizer134; + bSizer134 = new wxBoxSizer( wxVERTICAL ); + + m_panelStatistics = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelStatistics->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + wxBoxSizer* bSizer169; + bSizer169 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapSync = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer169->Add( m_bitmapSync, 0, wxALL, 10 ); + + m_staticline39 = new wxStaticLine( m_panelStatistics, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); + bSizer169->Add( m_staticline39, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer162; + bSizer162 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer172; + bSizer172 = new wxBoxSizer( wxVERTICAL ); + + m_staticText84 = new wxStaticText( m_panelStatistics, wxID_ANY, _("Variant"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText84->Wrap( -1 ); + bSizer172->Add( m_staticText84, 0, wxALL, 5 ); + + m_staticTextVariant = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextVariant->Wrap( -1 ); + m_staticTextVariant->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizer172->Add( m_staticTextVariant, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizer172->Add( 0, 10, 0, 0, 5 ); + + + bSizer162->Add( bSizer172, 0, wxEXPAND, 5 ); + + m_staticline14 = new wxStaticLine( m_panelStatistics, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizer162->Add( m_staticline14, 0, wxEXPAND, 5 ); + + m_staticText83 = new wxStaticText( m_panelStatistics, wxID_ANY, _("Statistics"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText83->Wrap( -1 ); + bSizer162->Add( m_staticText83, 0, wxALL, 5 ); + + wxFlexGridSizer* fgSizer11; + fgSizer11 = new wxFlexGridSizer( 2, 7, 2, 5 ); + fgSizer11->SetFlexibleDirection( wxBOTH ); + fgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_bitmapCreateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapCreateLeft->SetToolTip( _("Number of files and folders that will be created") ); + + fgSizer11->Add( m_bitmapCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_bitmapUpdateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapUpdateLeft->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer11->Add( m_bitmapUpdateLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_bitmapDeleteLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapDeleteLeft->SetToolTip( _("Number of files and folders that will be deleted") ); + + fgSizer11->Add( m_bitmapDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_bitmapData = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapData->SetToolTip( _("Total bytes to copy") ); + + fgSizer11->Add( m_bitmapData, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_bitmapDeleteRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapDeleteRight->SetToolTip( _("Number of files and folders that will be deleted") ); + + fgSizer11->Add( m_bitmapDeleteRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_bitmapUpdateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapUpdateRight->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer11->Add( m_bitmapUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_bitmapCreateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapCreateRight->SetToolTip( _("Number of files and folders that will be created") ); + + fgSizer11->Add( m_bitmapCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_staticTextCreateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCreateLeft->Wrap( -1 ); + m_staticTextCreateLeft->SetToolTip( _("Number of files and folders that will be created") ); + + fgSizer11->Add( m_staticTextCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_staticTextUpdateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUpdateLeft->Wrap( -1 ); + m_staticTextUpdateLeft->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer11->Add( m_staticTextUpdateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_staticTextDeleteLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDeleteLeft->Wrap( -1 ); + m_staticTextDeleteLeft->SetToolTip( _("Number of files and folders that will be deleted") ); + + fgSizer11->Add( m_staticTextDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextData = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextData->Wrap( -1 ); + m_staticTextData->SetToolTip( _("Total bytes to copy") ); + + fgSizer11->Add( m_staticTextData, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextDeleteRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDeleteRight->Wrap( -1 ); + m_staticTextDeleteRight->SetToolTip( _("Number of files and folders that will be deleted") ); + + fgSizer11->Add( m_staticTextDeleteRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextUpdateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextUpdateRight->Wrap( -1 ); + m_staticTextUpdateRight->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer11->Add( m_staticTextUpdateRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextCreateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCreateRight->Wrap( -1 ); + m_staticTextCreateRight->SetToolTip( _("Number of files and folders that will be created") ); + + fgSizer11->Add( m_staticTextCreateRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer162->Add( fgSizer11, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxRIGHT|wxLEFT, 25 ); + + + bSizer162->Add( 0, 5, 0, 0, 5 ); + + + bSizer169->Add( bSizer162, 0, 0, 5 ); + + + m_panelStatistics->SetSizer( bSizer169 ); + m_panelStatistics->Layout(); + bSizer169->Fit( m_panelStatistics ); + bSizer134->Add( m_panelStatistics, 0, wxEXPAND, 5 ); + + m_staticline12 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizer134->Add( m_staticline12, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer164; + bSizer164 = new wxBoxSizer( wxVERTICAL ); + + m_checkBoxDontShowAgain = new wxCheckBox( this, wxID_ANY, _("Don't show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer164->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 ); + + bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); + + m_buttonStartSync = new wxButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonStartSync->SetDefault(); + m_buttonStartSync->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + + bSizerStdButtons->Add( m_buttonStartSync, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + bSizerStdButtons->Add( m_buttonCancel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + + bSizer164->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 ); + + + bSizer134->Add( bSizer164, 1, wxEXPAND, 5 ); + + + this->SetSizer( bSizer134 ); + this->Layout(); + bSizer134->Fit( this ); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncConfirmationDlgGenerated::OnClose ) ); + m_buttonStartSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnStartSync ), NULL, this ); + m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnCancel ), NULL, this ); +} + +SyncConfirmationDlgGenerated::~SyncConfirmationDlgGenerated() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncConfirmationDlgGenerated::OnClose ) ); + m_buttonStartSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnStartSync ), NULL, this ); + m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnCancel ), NULL, this ); + +} + CmpCfgDlgGenerated::CmpCfgDlgGenerated( 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 ); @@ -3191,200 +3485,6 @@ GlobalSettingsDlgGenerated::~GlobalSettingsDlgGenerated() } -SyncConfirmationDlgGenerated::SyncConfirmationDlgGenerated( 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 ); - this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); - - wxBoxSizer* bSizer134; - bSizer134 = new wxBoxSizer( wxVERTICAL ); - - m_panelStatistics = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - m_panelStatistics->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - - wxBoxSizer* bSizer169; - bSizer169 = new wxBoxSizer( wxHORIZONTAL ); - - m_bitmapSync = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - bSizer169->Add( m_bitmapSync, 0, wxALL, 10 ); - - m_staticline39 = new wxStaticLine( m_panelStatistics, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); - bSizer169->Add( m_staticline39, 0, wxEXPAND, 5 ); - - wxBoxSizer* bSizer162; - bSizer162 = new wxBoxSizer( wxVERTICAL ); - - wxBoxSizer* bSizer172; - bSizer172 = new wxBoxSizer( wxVERTICAL ); - - m_staticText84 = new wxStaticText( m_panelStatistics, wxID_ANY, _("Variant"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText84->Wrap( -1 ); - bSizer172->Add( m_staticText84, 0, wxALL, 5 ); - - m_staticTextVariant = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextVariant->Wrap( -1 ); - m_staticTextVariant->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - - bSizer172->Add( m_staticTextVariant, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - - bSizer172->Add( 0, 10, 0, 0, 5 ); - - - bSizer162->Add( bSizer172, 0, wxEXPAND, 5 ); - - m_staticline14 = new wxStaticLine( m_panelStatistics, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizer162->Add( m_staticline14, 0, wxEXPAND, 5 ); - - m_staticText83 = new wxStaticText( m_panelStatistics, wxID_ANY, _("Statistics"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText83->Wrap( -1 ); - bSizer162->Add( m_staticText83, 0, wxALL, 5 ); - - wxFlexGridSizer* fgSizer11; - fgSizer11 = new wxFlexGridSizer( 2, 7, 2, 5 ); - fgSizer11->SetFlexibleDirection( wxBOTH ); - fgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - - m_bitmapCreateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapCreateLeft->SetToolTip( _("Number of files and folders that will be created") ); - - fgSizer11->Add( m_bitmapCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_bitmapUpdateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapUpdateLeft->SetToolTip( _("Number of files that will be overwritten") ); - - fgSizer11->Add( m_bitmapUpdateLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_bitmapDeleteLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapDeleteLeft->SetToolTip( _("Number of files and folders that will be deleted") ); - - fgSizer11->Add( m_bitmapDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_bitmapData = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapData->SetToolTip( _("Total bytes to copy") ); - - fgSizer11->Add( m_bitmapData, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_bitmapDeleteRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapDeleteRight->SetToolTip( _("Number of files and folders that will be deleted") ); - - fgSizer11->Add( m_bitmapDeleteRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_bitmapUpdateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapUpdateRight->SetToolTip( _("Number of files that will be overwritten") ); - - fgSizer11->Add( m_bitmapUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_bitmapCreateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - m_bitmapCreateRight->SetToolTip( _("Number of files and folders that will be created") ); - - fgSizer11->Add( m_bitmapCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_staticTextCreateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextCreateLeft->Wrap( -1 ); - m_staticTextCreateLeft->SetToolTip( _("Number of files and folders that will be created") ); - - fgSizer11->Add( m_staticTextCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_staticTextUpdateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextUpdateLeft->Wrap( -1 ); - m_staticTextUpdateLeft->SetToolTip( _("Number of files that will be overwritten") ); - - fgSizer11->Add( m_staticTextUpdateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_staticTextDeleteLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextDeleteLeft->Wrap( -1 ); - m_staticTextDeleteLeft->SetToolTip( _("Number of files and folders that will be deleted") ); - - fgSizer11->Add( m_staticTextDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticTextData = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextData->Wrap( -1 ); - m_staticTextData->SetToolTip( _("Total bytes to copy") ); - - fgSizer11->Add( m_staticTextData, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticTextDeleteRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextDeleteRight->Wrap( -1 ); - m_staticTextDeleteRight->SetToolTip( _("Number of files and folders that will be deleted") ); - - fgSizer11->Add( m_staticTextDeleteRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticTextUpdateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextUpdateRight->Wrap( -1 ); - m_staticTextUpdateRight->SetToolTip( _("Number of files that will be overwritten") ); - - fgSizer11->Add( m_staticTextUpdateRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticTextCreateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextCreateRight->Wrap( -1 ); - m_staticTextCreateRight->SetToolTip( _("Number of files and folders that will be created") ); - - fgSizer11->Add( m_staticTextCreateRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer162->Add( fgSizer11, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxRIGHT|wxLEFT, 25 ); - - - bSizer162->Add( 0, 5, 0, 0, 5 ); - - - bSizer169->Add( bSizer162, 0, 0, 5 ); - - - m_panelStatistics->SetSizer( bSizer169 ); - m_panelStatistics->Layout(); - bSizer169->Fit( m_panelStatistics ); - bSizer134->Add( m_panelStatistics, 0, wxEXPAND, 5 ); - - m_staticline12 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizer134->Add( m_staticline12, 0, wxEXPAND, 5 ); - - wxBoxSizer* bSizer164; - bSizer164 = new wxBoxSizer( wxVERTICAL ); - - m_checkBoxDontShowAgain = new wxCheckBox( this, wxID_ANY, _("Don't show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer164->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 ); - - bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); - - m_buttonStartSync = new wxButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1,30 ), 0 ); - m_buttonStartSync->SetDefault(); - m_buttonStartSync->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - - bSizerStdButtons->Add( m_buttonStartSync, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); - bSizerStdButtons->Add( m_buttonCancel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); - - - bSizer164->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 ); - - - bSizer134->Add( bSizer164, 1, wxEXPAND, 5 ); - - - this->SetSizer( bSizer134 ); - this->Layout(); - bSizer134->Fit( this ); - - this->Centre( wxBOTH ); - - // Connect Events - this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncConfirmationDlgGenerated::OnClose ) ); - m_buttonStartSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnStartSync ), NULL, this ); - m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnCancel ), NULL, this ); -} - -SyncConfirmationDlgGenerated::~SyncConfirmationDlgGenerated() -{ - // Disconnect Events - this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncConfirmationDlgGenerated::OnClose ) ); - m_buttonStartSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnStartSync ), NULL, this ); - m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncConfirmationDlgGenerated::OnCancel ), NULL, this ); - -} - PopupDialogGenerated::PopupDialogGenerated( 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 ); diff --git a/ui/gui_generated.h b/ui/gui_generated.h index 27395e33..f06ebf93 100644 --- a/ui/gui_generated.h +++ b/ui/gui_generated.h @@ -45,9 +45,9 @@ namespace zen{ class TripleSplitter; } #include <wx/gauge.h> #include <wx/animate.h> #include <wx/notebook.h> +#include <wx/dialog.h> #include <wx/tglbtn.h> #include <wx/choice.h> -#include <wx/dialog.h> #include <wx/spinctrl.h> #include <wx/hyperlink.h> #include <wx/grid.h> @@ -290,61 +290,48 @@ class CompareProgressDlgGenerated : public wxPanel }; /////////////////////////////////////////////////////////////////////////////// -/// Class SyncProgressDlgGenerated +/// Class SyncProgressPanelGenerated /////////////////////////////////////////////////////////////////////////////// -class SyncProgressDlgGenerated : public wxFrame +class SyncProgressPanelGenerated : public wxPanel { private: protected: - wxBoxSizer* bSizerRoot; wxBoxSizer* bSizer42; + wxBoxSizer* bSizer171; + wxStaticText* m_staticText87; + + public: + wxBoxSizer* bSizerRoot; wxStaticBitmap* m_bitmapStatus; wxStaticText* m_staticTextPhase; wxAnimationCtrl* m_animCtrlSyncing; - wxStaticLine* m_staticlineHeader; - wxPanel* m_panelProgress; + wxBitmapButton* m_bpButtonMinimizeToTray; + wxBoxSizer* bSizerStatusText; wxStaticText* m_staticTextStatus; - wxBoxSizer* bSizer171; - wxStaticText* m_staticTextLabelItemsProc; - wxBoxSizer* bSizerItemsProc; + wxPanel* m_panelProgress; + wxPanel* m_panelItemsProcessed; wxStaticText* m_staticTextProcessedObj; wxStaticText* m_staticTextDataProcessed; - wxStaticText* m_staticTextLabelItemsRem; - wxBoxSizer* bSizerItemsRem; + wxPanel* m_panelItemsRemaining; wxStaticText* m_staticTextRemainingObj; wxStaticText* m_staticTextDataRemaining; - wxStaticText* m_staticText84; - wxStaticText* m_staticTextSpeed; - wxStaticText* m_staticTextLabelRemTime; + wxPanel* m_panelTimeRemaining; wxStaticText* m_staticTextRemTime; - wxStaticText* m_staticTextLabelElapsedTime; wxStaticText* m_staticTextTimeElapsed; - zen::Graph2D* m_panelGraph; + zen::Graph2D* m_panelGraphBytes; + zen::Graph2D* m_panelGraphItems; wxNotebook* m_notebookResult; wxStaticLine* m_staticlineFooter; wxBoxSizer* bSizerStdButtons; wxBoxSizer* bSizerExecFinished; - wxStaticText* m_staticText87; ExecFinishedBox* m_comboBoxExecFinished; wxButton* m_buttonClose; wxButton* m_buttonPause; wxButton* m_buttonCancel; - // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } - virtual void OnIconize( wxIconizeEvent& event ) { event.Skip(); } - virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } - virtual void OnPause( wxCommandEvent& event ) { event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } - - - public: - wxGauge* m_gauge1; - - SyncProgressDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); - - ~SyncProgressDlgGenerated(); + SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); + ~SyncProgressPanelGenerated(); }; @@ -376,6 +363,54 @@ class LogPanelGenerated : public wxPanel }; /////////////////////////////////////////////////////////////////////////////// +/// Class SyncConfirmationDlgGenerated +/////////////////////////////////////////////////////////////////////////////// +class SyncConfirmationDlgGenerated : public wxDialog +{ + private: + + protected: + wxPanel* m_panelStatistics; + wxStaticBitmap* m_bitmapSync; + wxStaticLine* m_staticline39; + wxStaticText* m_staticText84; + wxStaticText* m_staticTextVariant; + wxStaticLine* m_staticline14; + wxStaticText* m_staticText83; + wxStaticBitmap* m_bitmapCreateLeft; + wxStaticBitmap* m_bitmapUpdateLeft; + wxStaticBitmap* m_bitmapDeleteLeft; + wxStaticBitmap* m_bitmapData; + wxStaticBitmap* m_bitmapDeleteRight; + wxStaticBitmap* m_bitmapUpdateRight; + wxStaticBitmap* m_bitmapCreateRight; + wxStaticText* m_staticTextCreateLeft; + wxStaticText* m_staticTextUpdateLeft; + wxStaticText* m_staticTextDeleteLeft; + wxStaticText* m_staticTextData; + wxStaticText* m_staticTextDeleteRight; + wxStaticText* m_staticTextUpdateRight; + wxStaticText* m_staticTextCreateRight; + wxStaticLine* m_staticline12; + wxCheckBox* m_checkBoxDontShowAgain; + wxBoxSizer* bSizerStdButtons; + wxButton* m_buttonStartSync; + wxButton* m_buttonCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnStartSync( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } + + + public: + + SyncConfirmationDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Start synchronization"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); + ~SyncConfirmationDlgGenerated(); + +}; + +/////////////////////////////////////////////////////////////////////////////// /// Class CmpCfgDlgGenerated /////////////////////////////////////////////////////////////////////////////// class CmpCfgDlgGenerated : public wxDialog @@ -571,7 +606,7 @@ class BatchDlgGenerated : public wxDialog public: FolderHistoryBox* m_logfileDir; - BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Save as batch job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER ); + BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Save as batch job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~BatchDlgGenerated(); }; @@ -664,7 +699,7 @@ class MessageDlgGenerated : public wxDialog public: - MessageDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("dummy"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER ); + MessageDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("dummy"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~MessageDlgGenerated(); }; @@ -698,7 +733,7 @@ class DeleteDlgGenerated : public wxDialog public: - DeleteDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Delete"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER ); + DeleteDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Delete"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); ~DeleteDlgGenerated(); }; @@ -756,7 +791,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 = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER ); + FilterDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Configure filter"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); ~FilterDlgGenerated(); }; @@ -810,54 +845,6 @@ class GlobalSettingsDlgGenerated : public wxDialog }; /////////////////////////////////////////////////////////////////////////////// -/// Class SyncConfirmationDlgGenerated -/////////////////////////////////////////////////////////////////////////////// -class SyncConfirmationDlgGenerated : public wxDialog -{ - private: - - protected: - wxPanel* m_panelStatistics; - wxStaticBitmap* m_bitmapSync; - wxStaticLine* m_staticline39; - wxStaticText* m_staticText84; - wxStaticText* m_staticTextVariant; - wxStaticLine* m_staticline14; - wxStaticText* m_staticText83; - wxStaticBitmap* m_bitmapCreateLeft; - wxStaticBitmap* m_bitmapUpdateLeft; - wxStaticBitmap* m_bitmapDeleteLeft; - wxStaticBitmap* m_bitmapData; - wxStaticBitmap* m_bitmapDeleteRight; - wxStaticBitmap* m_bitmapUpdateRight; - wxStaticBitmap* m_bitmapCreateRight; - wxStaticText* m_staticTextCreateLeft; - wxStaticText* m_staticTextUpdateLeft; - wxStaticText* m_staticTextDeleteLeft; - wxStaticText* m_staticTextData; - wxStaticText* m_staticTextDeleteRight; - wxStaticText* m_staticTextUpdateRight; - wxStaticText* m_staticTextCreateRight; - wxStaticLine* m_staticline12; - wxCheckBox* m_checkBoxDontShowAgain; - wxBoxSizer* bSizerStdButtons; - wxButton* m_buttonStartSync; - wxButton* m_buttonCancel; - - // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } - virtual void OnStartSync( wxCommandEvent& event ) { event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } - - - public: - - SyncConfirmationDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Start synchronization"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); - ~SyncConfirmationDlgGenerated(); - -}; - -/////////////////////////////////////////////////////////////////////////////// /// Class PopupDialogGenerated /////////////////////////////////////////////////////////////////////////////// class PopupDialogGenerated : public wxDialog diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp index db92c24c..0131af3f 100644 --- a/ui/gui_status_handler.cpp +++ b/ui/gui_status_handler.cpp @@ -8,6 +8,7 @@ #include <wx/wupdlock.h> #include <wx+/shell_execute.h> #include <wx+/button.h> +#include <wx/app.h> #include "msg_popup.h" #include "main_dlg.h" #include "exec_finished_box.h" @@ -169,13 +170,12 @@ void CompareStatusHandler::abortThisProcess() //######################################################################################################## -SyncStatusHandler::SyncStatusHandler(wxTopLevelWindow* parentDlg, +SyncStatusHandler::SyncStatusHandler(wxFrame* parentDlg, size_t lastSyncsLogFileSizeMax, OnGuiError handleError, const std::wstring& jobName, const std::wstring& execWhenFinished, std::vector<std::wstring>& execFinishedHistory) : - parentDlg_(parentDlg), progressDlg(createProgressDialog(*this, [this] { this->onProgressDialogTerminate(); }, *this, parentDlg, true, jobName, execWhenFinished, execFinishedHistory)), lastSyncsLogFileSizeMax_(lastSyncsLogFileSizeMax), handleError_(handleError), @@ -267,7 +267,7 @@ SyncStatusHandler::~SyncStatusHandler() //-> nicely manages dialog lifetime while (progressDlg) { - updateUiNow(); //*first* refresh GUI (removing flicker) before sleeping! + wxTheApp->Yield(); //*first* refresh GUI (removing flicker) before sleeping! boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)); } } @@ -313,7 +313,7 @@ ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& err forceUiRefresh(); bool ignoreNextErrors = false; - switch (showErrorDlg(parentDlg_, + switch (showErrorDlg(progressDlg->getWindowIfVisible(), ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL, errorMessage, &ignoreNextErrors)) @@ -357,7 +357,7 @@ void SyncStatusHandler::reportFatalError(const std::wstring& errorMessage) forceUiRefresh(); bool ignoreNextErrors = false; - switch (showFatalErrorDlg(parentDlg_, + switch (showFatalErrorDlg(progressDlg->getWindowIfVisible(), ReturnFatalErrorDlg::BUTTON_IGNORE | ReturnFatalErrorDlg::BUTTON_CANCEL, errorMessage, &ignoreNextErrors)) { @@ -395,7 +395,7 @@ void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool& forceUiRefresh(); bool dontWarnAgain = false; - switch (showWarningDlg(parentDlg_, + switch (showWarningDlg(progressDlg->getWindowIfVisible(), ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_CANCEL, warningMessage, dontWarnAgain)) { diff --git a/ui/gui_status_handler.h b/ui/gui_status_handler.h index f7b58f05..30efe3fb 100644 --- a/ui/gui_status_handler.h +++ b/ui/gui_status_handler.h @@ -49,7 +49,7 @@ private: class SyncStatusHandler : public zen::StatusHandler { public: - SyncStatusHandler(wxTopLevelWindow* parentDlg, + SyncStatusHandler(wxFrame* parentDlg, size_t lastSyncsLogFileSizeMax, xmlAccess::OnGuiError handleError, const std::wstring& jobName, @@ -70,7 +70,6 @@ private: virtual void abortThisProcess(); //throw GuiAbortProcess void onProgressDialogTerminate(); - wxTopLevelWindow* parentDlg_; SyncProgressDialog* progressDlg; //managed to have shorter lifetime than this handler! const size_t lastSyncsLogFileSizeMax_; xmlAccess::OnGuiError handleError_; diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp index ead99c6a..eaae0545 100644 --- a/ui/main_dlg.cpp +++ b/ui/main_dlg.cpp @@ -8,7 +8,6 @@ #include <zen/format_unit.h> #include <zen/file_handling.h> #include <zen/serialize.h> -//#include <zen/file_id.h> //#include <zen/perf.h> #include <zen/thread.h> #include <wx/clipbrd.h> @@ -97,23 +96,26 @@ public: virtual bool acceptDrop(const std::vector<wxString>& droppedFiles, const wxPoint& clientPos, const wxWindow& wnd) { - if (droppedFiles.empty()) + if (std::any_of(droppedFiles.begin(), droppedFiles.end(), [](const wxString& filename) + { + using namespace xmlAccess; + switch (getXmlType(utfCvrtTo<Zstring>(filename))) //throw() + { + case XML_TYPE_GUI: + case XML_TYPE_BATCH: + return true; + case XML_TYPE_GLOBAL: + case XML_TYPE_OTHER: + break; + } return false; - - switch (xmlAccess::getMergeType(toZ(droppedFiles))) //throw() + })) { - case xmlAccess::MERGE_BATCH: - case xmlAccess::MERGE_GUI: - case xmlAccess::MERGE_GUI_BATCH: - mainDlg_.loadConfiguration(toZ(droppedFiles)); - return false; - - case xmlAccess::MERGE_OTHER: - //=> return true: change directory selection via drag and drop - break; + mainDlg_.loadConfiguration(toZ(droppedFiles)); + return false; } - //mainDlg_.clearGrid(); + //=> return true: change directory selection via drag and drop return true; } @@ -321,51 +323,43 @@ xmlAccess::XmlGlobalSettings retrieveGlobalCfgFromDisk() //blocks on GUI on erro { assert(false); if (e.getSeverity() != FfsXmlError::WARNING) //ignore parsing errors: should be migration problems only *cross-fingers* - wxMessageBox(e.toString(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(e.toString(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR); } return globalCfg; } } -void MainDialog::create(const std::vector<Zstring>& cfgFileNames) +void MainDialog::create() { using namespace xmlAccess; const XmlGlobalSettings globalSettings = retrieveGlobalCfgFromDisk(); - std::vector<Zstring> filenames; - if (!cfgFileNames.empty()) //1. this one has priority - filenames = cfgFileNames; - else //FFS default startup: use last used selection - { - filenames = globalSettings.gui.lastUsedConfigFiles; //2. now try last used files - - //------------------------------------------------------------------------------------------ - //check existence of all directories in parallel! + std::vector<Zstring> filenames = globalSettings.gui.lastUsedConfigFiles; //2. now try last used files - RunUntilFirstHit<NullType> findFirstMissing; + //------------------------------------------------------------------------------------------ + //check existence of all files in parallel: + RunUntilFirstHit<NullType> findFirstMissing; - std::for_each(filenames.begin(), filenames.end(), [&](const Zstring& filename) - { - findFirstMissing.addJob([=] { return filename.empty() /*ever empty??*/ || !fileExists(filename) ? zen::make_unique<NullType>() : nullptr; }); - }); - //potentially slow network access: give all checks 500ms to finish - const bool allFilesExist = findFirstMissing.timedWait(boost::posix_time::milliseconds(500)) && //false: time elapsed - !findFirstMissing.get(); //no missing - if (!allFilesExist) - filenames.clear(); //we do NOT want to show an error due to last config file missing on application start! - //------------------------------------------------------------------------------------------ + std::for_each(filenames.begin(), filenames.end(), [&](const Zstring& filename) + { + findFirstMissing.addJob([=] { return filename.empty() /*ever empty??*/ || !fileExists(filename) ? zen::make_unique<NullType>() : nullptr; }); + }); + //potentially slow network access: give all checks 500ms to finish + const bool allFilesExist = findFirstMissing.timedWait(boost::posix_time::milliseconds(500)) && //false: time elapsed + !findFirstMissing.get(); //no missing + if (!allFilesExist) + filenames.clear(); //we do NOT want to show an error due to last config file missing on application start! + //------------------------------------------------------------------------------------------ - if (filenames.empty()) - { - if (zen::fileExists(lastRunConfigName())) //3. try to load auto-save config - filenames.push_back(lastRunConfigName()); - } + if (filenames.empty()) + { + if (zen::fileExists(lastRunConfigName())) //3. try to load auto-save config + filenames.push_back(lastRunConfigName()); } XmlGuiConfig guiCfg; //structure to receive gui settings with default values - bool loadCfgSuccess = false; if (filenames.empty()) { //add default exclusion filter: this is only ever relevant when creating new configurations! @@ -379,58 +373,40 @@ void MainDialog::create(const std::vector<Zstring>& cfgFileNames) try { readAnyConfig(filenames, guiCfg); //throw FfsXmlError - loadCfgSuccess = true; } catch (const FfsXmlError& error) { if (error.getSeverity() == FfsXmlError::WARNING) - wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING); + wxMessageBox(error.toString(), L"FreeFileSync - " + _("Warning"), wxOK | wxICON_WARNING); //what about simulating changed config on parsing errors???? else - wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error.toString(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR); } - const bool startComparisonImmediately = !cfgFileNames.empty() && loadCfgSuccess; - //------------------------------------------------------------------------------------------ - create_impl(guiCfg, filenames, globalSettings, startComparisonImmediately); -} - - -void MainDialog::create(const xmlAccess::XmlGuiConfig& guiCfg, - bool startComparison) -{ - create_impl(guiCfg, std::vector<Zstring>(), retrieveGlobalCfgFromDisk(), startComparison); + create(guiCfg, filenames, &globalSettings, false); } void MainDialog::create(const xmlAccess::XmlGuiConfig& guiCfg, const std::vector<Zstring>& referenceFiles, - const xmlAccess::XmlGlobalSettings& globalSettings, + const xmlAccess::XmlGlobalSettings* globalSettings, bool startComparison) { - create_impl(guiCfg, referenceFiles, globalSettings, startComparison); -} - - -void MainDialog::create_impl(const xmlAccess::XmlGuiConfig& guiCfg, - const std::vector<Zstring>& referenceFiles, - const xmlAccess::XmlGlobalSettings& globalSettings, - bool startComparison) -{ + const xmlAccess::XmlGlobalSettings& globSett = globalSettings ? *globalSettings : retrieveGlobalCfgFromDisk(); try { //we need to set language *before* creating MainDialog! - setLanguage(globalSettings.programLanguage); //throw FileError + setLanguage(globSett.programLanguage); //throw FileError } catch (const FileError& e) { - wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(e.toString().c_str(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR); //continue! } - MainDialog* frame = new MainDialog(guiCfg, referenceFiles, globalSettings, startComparison); + MainDialog* frame = new MainDialog(guiCfg, referenceFiles, globSett, startComparison); frame->Show(); } @@ -757,7 +733,7 @@ MainDialog::~MainDialog() } catch (const xmlAccess::FfsXmlError& e) { - wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(e.toString().c_str(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); } try //save "LastRun.ffs_gui" @@ -1026,7 +1002,7 @@ void MainDialog::copySelectionToClipboard(const std::vector<const Grid*>& gridRe } catch (const std::bad_alloc& e) { - wxMessageBox(_("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(_("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); } } @@ -1064,10 +1040,9 @@ std::vector<FileSystemObject*> MainDialog::getTreeSelection() const if (auto root = dynamic_cast<const TreeView::RootNode*>(node.get())) { //select first level of child elements - std::transform(root->baseDirObj_.refSubDirs ().begin(), root->baseDirObj_.refSubDirs ().end(), std::back_inserter(output), [](FileSystemObject& fsObj) { return &fsObj; }); - std::transform(root->baseDirObj_.refSubFiles().begin(), root->baseDirObj_.refSubFiles().end(), std::back_inserter(output), [](FileSystemObject& fsObj) { return &fsObj; }); - std::transform(root->baseDirObj_.refSubLinks().begin(), root->baseDirObj_.refSubLinks().end(), std::back_inserter(output), [](FileSystemObject& fsObj) { return &fsObj; }); - //for (auto& fsObj : root->baseDirObj_.refSubLinks()) output.push_back(&fsObj); -> seriously MSVC, stop this disgrace and implement "range for"! + for (auto& fsObj : root->baseDirObj_.refSubDirs ()) output.push_back(&fsObj); + for (auto& fsObj : root->baseDirObj_.refSubFiles()) output.push_back(&fsObj); + for (auto& fsObj : root->baseDirObj_.refSubLinks()) output.push_back(&fsObj); } else if (auto dir = dynamic_cast<const TreeView::DirNode*>(node.get())) output.push_back(&(dir->dirObj_)); @@ -1170,7 +1145,7 @@ private: { //std::wstring msg = toGuiString(deletionCount) + mainDlg.setStatusBarFullText(statusMsg); - updateUiNow(); + wxTheApp->Yield(); } //context: C callstack message loop => throw()! @@ -1314,6 +1289,31 @@ void MainDialog::openExternalApplication(const wxString& commandline, const std: } } + const size_t massInvokeThreshold = 10; //more than this is likely a user mistake + + if (selectionTmp.size() > massInvokeThreshold) + if (globalCfg.optDialogs.confirmExternalCommandMassInvoke) + { + bool dontAskAgain = false; + switch (showQuestionDlg(this, + ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_CANCEL, + replaceCpy(replaceCpy(_P("Do you really want to execute the command %y for 1 item?", + "Do you really want to execute the command %y for %x items?", selectionTmp.size()), + L"%x", toGuiString(selectionTmp.size())), L"%y", L'\'' + commandline + L'\''), + QuestConfig().setCaption(_("Confirm")).setLabelYes(_("&Execute")). + showCheckBox(dontAskAgain, _("&Don't show this dialog again"), 0))) + { + case ReturnQuestionDlg::BUTTON_YES: + globalCfg.optDialogs.confirmExternalCommandMassInvoke = !dontAskAgain; + break; + + case ReturnQuestionDlg::BUTTON_NO: + assert(false); + case ReturnQuestionDlg::BUTTON_CANCEL: + return; + } + } + //regular command evaluation for (auto it = selectionTmp.begin(); it != selectionTmp.end(); ++it) //context menu calls this function only if selection is not empty! { @@ -1338,7 +1338,8 @@ void MainDialog::openExternalApplication(const wxString& commandline, const std: replace(command, Zstr("%item2_folder%"), dir2 ); auto cmdExp = expandMacros(command); - zen::shellExecute(cmdExp); //shows error message if command is malformed + //caveat: spawning too many threads asynchronously can easily kill a user's desktop session! + zen::shellExecute(cmdExp, selectionTmp.size() > massInvokeThreshold ? EXEC_TYPE_SYNC : EXEC_TYPE_ASYNC); } } @@ -1448,27 +1449,26 @@ void MainDialog::onProcessAsyncTasks(wxEvent& event) void MainDialog::disableAllElements(bool enableAbort) { + //disables all elements (except abort button) that might receive user input during long-running processes: //when changing consider: comparison, synchronization, manual deletion EnableCloseButton(false); //not allowed for synchronization! progress indicator is top window! -> not honored on OS X! - //disables all elements (except abort button) that might receive user input during long-running processes: comparison, deletion - m_panelViewFilter ->Disable(); + //OS X: wxWidgets portability promise is again a mess: http://wxwidgets.10942.n7.nabble.com/Disable-panel-and-appropriate-children-windows-linux-macos-td35357.html + + m_menubar1->EnableTop(0, false); + m_menubar1->EnableTop(1, false); + m_menubar1->EnableTop(2, false); m_bpButtonCmpConfig ->Disable(); - m_panelFilter ->Disable(); - m_panelConfig ->Disable(); m_bpButtonSyncConfig ->Disable(); m_buttonSync ->Disable(); - m_gridMainL ->Disable(); - m_gridMainC ->Disable(); - m_gridMainR ->Disable(); + m_panelDirectoryPairs->Disable(); + m_panelCenter ->Disable(); + m_panelViewFilter ->Disable(); + m_panelFilter ->Disable(); + m_panelConfig ->Disable(); m_panelStatistics ->Disable(); m_gridNavi ->Disable(); - m_panelDirectoryPairs->Disable(); - m_splitterMain ->Disable(); - m_menubar1->EnableTop(0, false); - m_menubar1->EnableTop(1, false); - m_menubar1->EnableTop(2, false); if (enableAbort) { @@ -1492,22 +1492,19 @@ void MainDialog::enableAllElements() EnableCloseButton(true); - m_panelViewFilter ->Enable(); + m_menubar1->EnableTop(0, true); + m_menubar1->EnableTop(1, true); + m_menubar1->EnableTop(2, true); m_bpButtonCmpConfig ->Enable(); - m_panelFilter ->Enable(); - m_panelConfig ->Enable(); m_bpButtonSyncConfig ->Enable(); m_buttonSync ->Enable(); - m_gridMainL ->Enable(); - m_gridMainC ->Enable(); - m_gridMainR ->Enable(); + m_panelDirectoryPairs->Enable(); + m_panelCenter ->Enable(); + m_panelViewFilter ->Enable(); + m_panelFilter ->Enable(); + m_panelConfig ->Enable(); m_panelStatistics ->Enable(); m_gridNavi ->Enable(); - m_panelDirectoryPairs->Enable(); - m_splitterMain ->Enable(); - m_menubar1->EnableTop(0, true); - m_menubar1->EnableTop(1, true); - m_menubar1->EnableTop(2, true); //show compare button m_buttonCancel->Disable(); @@ -1517,6 +1514,9 @@ void MainDialog::enableAllElements() m_panelTopButtons->Layout(); m_panelTopButtons->Enable(); + + //at least wxWidgets on OS X fails to do this after enabling: + Refresh(); } @@ -1540,12 +1540,14 @@ void MainDialog::OnResizeConfigPanel(wxEvent& event) event.Skip(); } + void MainDialog::OnResizeViewPanel(wxEvent& event) { updateSizerOrientation(*bSizerViewFilter, *m_panelViewFilter, 1.0); event.Skip(); } + void MainDialog::OnResizeStatisticsPanel(wxEvent& event) { //updateSizerOrientation(*bSizerStatistics, *m_panelStatistics); @@ -1619,19 +1621,19 @@ void MainDialog::onTreeButtonEvent(wxKeyEvent& event) { case WXK_NUMPAD_LEFT: case WXK_LEFT: //ALT + <- - setSyncDirManually(getTreeSelection(), SYNC_DIR_LEFT); + setSyncDirManually(getTreeSelection(), SyncDirection::LEFT); return; case WXK_NUMPAD_RIGHT: case WXK_RIGHT: //ALT + -> - setSyncDirManually(getTreeSelection(), SYNC_DIR_RIGHT); + setSyncDirManually(getTreeSelection(), SyncDirection::RIGHT); return; case WXK_NUMPAD_UP: case WXK_NUMPAD_DOWN: case WXK_UP: /* ALT + /|\ */ case WXK_DOWN: /* ALT + \|/ */ - setSyncDirManually(getTreeSelection(), SYNC_DIR_NONE); + setSyncDirManually(getTreeSelection(), SyncDirection::NONE); return; } @@ -1704,19 +1706,19 @@ void MainDialog::onGridButtonEvent(wxKeyEvent& event, Grid& grid, bool leftSide) { case WXK_NUMPAD_LEFT: case WXK_LEFT: //ALT + <- - setSyncDirManually(getGridSelection(), SYNC_DIR_LEFT); + setSyncDirManually(getGridSelection(), SyncDirection::LEFT); return; case WXK_NUMPAD_RIGHT: case WXK_RIGHT: //ALT + -> - setSyncDirManually(getGridSelection(), SYNC_DIR_RIGHT); + setSyncDirManually(getGridSelection(), SyncDirection::RIGHT); return; case WXK_NUMPAD_UP: case WXK_NUMPAD_DOWN: case WXK_UP: /* ALT + /|\ */ case WXK_DOWN: /* ALT + \|/ */ - setSyncDirManually(getGridSelection(), SYNC_DIR_NONE); + setSyncDirManually(getGridSelection(), SyncDirection::NONE); return; } @@ -1920,18 +1922,18 @@ void MainDialog::onNaviGridContext(GridClickEvent& event) return mirrorIfRtl(getSyncOpImage(selection[0]->getSyncOperation() != SO_EQUAL ? selection[0]->testSyncOperation(dir) : soDefault)); }; - const wxBitmap opRight = getImage(SYNC_DIR_RIGHT, SO_OVERWRITE_RIGHT); - const wxBitmap opNone = getImage(SYNC_DIR_NONE, SO_DO_NOTHING ); - const wxBitmap opLeft = getImage(SYNC_DIR_LEFT, SO_OVERWRITE_LEFT ); + const wxBitmap opRight = getImage(SyncDirection::RIGHT, SO_OVERWRITE_RIGHT); + const wxBitmap opNone = getImage(SyncDirection::NONE, SO_DO_NOTHING ); + const wxBitmap opLeft = getImage(SyncDirection::LEFT, SO_OVERWRITE_LEFT ); wxString shortCutLeft = L"\tAlt+Left"; wxString shortCutRight = L"\tAlt+Right"; if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) std::swap(shortCutLeft, shortCutRight); - menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_RIGHT); }, &opRight); - menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone); - menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_LEFT); }, &opLeft); + menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SyncDirection::RIGHT); }, &opRight); + menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SyncDirection::NONE); }, &opNone); + menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SyncDirection::LEFT); }, &opLeft); //Gtk needs a direction, "<-", because it has no context menu icons! //Gtk requires "no spaces" for shortcut identifiers! menu.addSeparator(); @@ -2012,18 +2014,18 @@ void MainDialog::onMainGridContextRim(bool leftSide) return mirrorIfRtl(getSyncOpImage(selection[0]->getSyncOperation() != SO_EQUAL ? selection[0]->testSyncOperation(dir) : soDefault)); }; - const wxBitmap opRight = getImage(SYNC_DIR_RIGHT, SO_OVERWRITE_RIGHT); - const wxBitmap opNone = getImage(SYNC_DIR_NONE, SO_DO_NOTHING ); - const wxBitmap opLeft = getImage(SYNC_DIR_LEFT, SO_OVERWRITE_LEFT ); + const wxBitmap opRight = getImage(SyncDirection::RIGHT, SO_OVERWRITE_RIGHT); + const wxBitmap opNone = getImage(SyncDirection::NONE, SO_DO_NOTHING ); + const wxBitmap opLeft = getImage(SyncDirection::LEFT, SO_OVERWRITE_LEFT ); wxString shortCutLeft = L"\tAlt+Left"; wxString shortCutRight = L"\tAlt+Right"; if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) std::swap(shortCutLeft, shortCutRight); - menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_RIGHT); }, &opRight); - menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone); - menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_LEFT); }, &opLeft); + menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SyncDirection::RIGHT); }, &opRight); + menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SyncDirection::NONE); }, &opNone); + menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SyncDirection::LEFT); }, &opLeft); //Gtk needs a direction, "<-", because it has no context menu icons! //Gtk requires "no spaces" for shortcut identifiers! menu.addSeparator(); @@ -2482,7 +2484,7 @@ void MainDialog::removeObsoleteCfgHistoryItems(const std::vector<Zstring>& filen std::vector<Zstring> missingFiles; auto itFut = fileEx.begin(); - for (auto it = filenames.begin(); it != filenames.end(); ++it, ++itFut) + for (auto it = filenames.begin(); it != filenames.end(); ++it, (void)++itFut) //void: prevent ADL from dragging in boost's ,-overload: "MSVC warning C4913: user defined binary operator ',' exists but no overload could convert all operands" if (itFut->is_ready() && !itFut->get()) //remove only files that are confirmed to be non-existent missingFiles.push_back(*it); @@ -2606,15 +2608,16 @@ bool MainDialog::trySaveConfig(const Zstring* fileNameGui) //return true if save } else { - wxString defaultFileName = activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? toWx(activeConfigFiles[0]) : L"SyncSettings.ffs_gui"; + Zstring defaultFileName = activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? activeConfigFiles[0] : Zstr("SyncSettings.ffs_gui"); //attention: activeConfigFiles may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config! - if (endsWith(defaultFileName, L".ffs_batch")) - replace(defaultFileName, L".ffs_batch", L".ffs_gui", false); + if (endsWith(defaultFileName, Zstr(".ffs_batch"))) + replace(defaultFileName, Zstr(".ffs_batch"), Zstr(".ffs_gui"), false); wxFileDialog filePicker(this, //put modal dialog on stack: creating this on freestore leads to memleak! wxEmptyString, - wxEmptyString, - defaultFileName, + //OS X really needs dir/file separated like this: + utfCvrtTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR)), //default dir; empty string if / not found + utfCvrtTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR)), //default file; whole string if / not found wxString(L"FreeFileSync (*.ffs_gui)|*.ffs_gui") + L"|" +_("All files") + L" (*.*)|*", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (filePicker.ShowModal() != wxID_OK) @@ -2634,7 +2637,7 @@ bool MainDialog::trySaveConfig(const Zstring* fileNameGui) //return true if save } catch (const xmlAccess::FfsXmlError& e) { - wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(e.toString().c_str(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); return false; } } @@ -2667,15 +2670,16 @@ bool MainDialog::trySaveBatchConfig(const Zstring* fileNameBatch) globalCfg.gui.onCompletionHistoryMax)) return false; - wxString defaultFileName = !activeCfgFilename.empty() ? toWx(activeCfgFilename) : L"BatchRun.ffs_batch"; + Zstring defaultFileName = !activeCfgFilename.empty() ? activeCfgFilename : Zstr("BatchRun.ffs_batch"); //attention: activeConfigFiles may be a *.ffs_gui file! We don't want to overwrite it with a BATCH config! - if (endsWith(defaultFileName, L".ffs_gui")) - replace(defaultFileName, L".ffs_gui", L".ffs_batch"); + if (endsWith(defaultFileName, Zstr(".ffs_gui"))) + replace(defaultFileName, Zstr(".ffs_gui"), Zstr(".ffs_batch")); wxFileDialog filePicker(this, //put modal dialog on stack: creating this on freestore leads to memleak! wxEmptyString, - wxEmptyString, - defaultFileName, + //OS X really needs dir/file separated like this: + utfCvrtTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR)), //default dir; empty string if / not found + utfCvrtTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR)), //default file; whole string if / not found _("FreeFileSync batch") + L" (*.ffs_batch)|*.ffs_batch" + L"|" +_("All files") + L" (*.*)|*", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (filePicker.ShowModal() != wxID_OK) @@ -2693,7 +2697,7 @@ bool MainDialog::trySaveBatchConfig(const Zstring* fileNameBatch) } catch (const xmlAccess::FfsXmlError& e) { - wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(e.toString().c_str(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); return false; } } @@ -2710,7 +2714,7 @@ bool MainDialog::saveOldConfig() //return false on user abort if (!activeCfgFilename.empty()) //only if check is active and non-default config file loaded { - bool neverSave = !globalCfg.optDialogs.popupOnConfigChange; + bool dontAskAgain = false; switch (showQuestionDlg(this, ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO | ReturnQuestionDlg::BUTTON_CANCEL, @@ -2718,7 +2722,7 @@ bool MainDialog::saveOldConfig() //return false on user abort QuestConfig().setCaption(toWx(activeCfgFilename)). setLabelYes(_("&Save")). setLabelNo(_("Do&n't save")). - showCheckBox(neverSave, _("Never save changes"), ReturnQuestionDlg::BUTTON_YES))) + showCheckBox(dontAskAgain, _("Never save changes"), ReturnQuestionDlg::BUTTON_YES))) { case ReturnQuestionDlg::BUTTON_YES: @@ -2736,7 +2740,7 @@ bool MainDialog::saveOldConfig() //return false on user abort } case ReturnQuestionDlg::BUTTON_NO: - globalCfg.optDialogs.popupOnConfigChange = !neverSave; + globalCfg.optDialogs.popupOnConfigChange = !dontAskAgain; break; case ReturnQuestionDlg::BUTTON_CANCEL: @@ -2759,7 +2763,7 @@ void MainDialog::OnConfigLoad(wxCommandEvent& event) wxFileDialog filePicker(this, wxEmptyString, - toWx(beforeLast(activeCfgFilename, FILE_NAME_SEPARATOR)), //set default dir: empty string if "activeConfigFiles" is empty or has no path separator + utfCvrtTo<wxString>(beforeLast(activeCfgFilename, FILE_NAME_SEPARATOR)), //set default dir: empty string if "activeConfigFiles" is empty or has no path separator wxEmptyString, wxString(L"FreeFileSync (*.ffs_gui;*.ffs_batch)|*.ffs_gui;*.ffs_batch") + L"|" +_("All files") + L" (*.*)|*", wxFD_OPEN | wxFD_MULTIPLE); @@ -2866,12 +2870,12 @@ bool MainDialog::loadConfiguration(const std::vector<Zstring>& filenames) { if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING) { - wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this); + wxMessageBox(error.toString(), L"FreeFileSync - " + _("Warning"), wxOK | wxICON_WARNING, this); setConfig(newGuiCfg, filenames); setLastUsedConfig(filenames, xmlAccess::XmlGuiConfig()); //simulate changed config due to parsing errors } else - wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(error.toString(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); return false; } } @@ -3308,7 +3312,8 @@ void MainDialog::OnCompare(wxCommandEvent& event) clearGrid(); //avoid memory peak by clearing old data first disableAllElements(true); //CompareStatusHandler will internally process Window messages, so avoid unexpected callbacks! - ZEN_ON_SCOPE_EXIT(updateUiNow(); enableAllElements()); //ui update before enabling buttons again: prevent strange behaviour of delayed button clicks + auto app = wxTheApp; //fix lambda/wxWigets/VC fuck up + ZEN_ON_SCOPE_EXIT(app->Yield(); enableAllElements()); //ui update before enabling buttons again: prevent strange behaviour of delayed button clicks try { @@ -4093,12 +4098,11 @@ void MainDialog::OnMenuGlobalSettings(wxCommandEvent& event) void MainDialog::OnMenuExportFileList(wxCommandEvent& event) { //get a filename - const wxString defaultFileName = L"FileList.csv"; //proposal wxFileDialog filePicker(this, //creating this on freestore leads to memleak! wxEmptyString, wxEmptyString, - defaultFileName, - _("Comma separated list") + L" (*.csv)|*.csv" + L"|" +_("All files") + L" (*.*)|*", + L"FileList.csv", //default file name + _("Comma-separated values") + L" (*.csv)|*.csv" + L"|" +_("All files") + L" (*.*)|*", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (filePicker.ShowModal() != wxID_OK) return; @@ -4220,7 +4224,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } catch (const FileError& e) { - wxMessageBox(e.toString(), _("Error"), wxOK | wxICON_ERROR, this); + wxMessageBox(e.toString(), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR, this); } } } @@ -4288,7 +4292,7 @@ void MainDialog::switchProgramLanguage(int langID) newGlobalCfg.programLanguage = langID; //show new dialog, then delete old one - MainDialog::create(getConfig(), activeConfigFiles, newGlobalCfg, false); + MainDialog::create(getConfig(), activeConfigFiles, &newGlobalCfg, false); //we don't use Close(): //1. we don't want to show the prompt to save current config in OnClose() diff --git a/ui/main_dlg.h b/ui/main_dlg.h index 5575cefb..b655d95e 100644 --- a/ui/main_dlg.h +++ b/ui/main_dlg.h @@ -29,16 +29,15 @@ class CompareProgressDialog; class MainDialog : public MainDialogGenerated { public: - //default behavior, application start - static void create(const std::vector<Zstring>& cfgFileNames); //cfgFileNames empty: restore last config; non-empty load/merge given set of config files + //default behavior, application start, restores last used config + static void create(); - //load dynamically assembled config - static void create(const xmlAccess::XmlGuiConfig& guiCfg, bool startComparison); - - //when switching language or switching from batch run to GUI on warnings + //when loading dynamically assembled config, + //when switching language, + //or switching from batch run to GUI on warnings static void create(const xmlAccess::XmlGuiConfig& guiCfg, const std::vector<Zstring>& referenceFiles, - const xmlAccess::XmlGlobalSettings& globalSettings, //take over ownership => save on exit + const xmlAccess::XmlGlobalSettings* globalSettings, //optional: take over ownership => save on exit bool startComparison); void disableAllElements(bool enableAbort); //dis-/enables all elements (except abort button) that might receive user input @@ -47,11 +46,6 @@ public: void onQueryEndSession(); //last chance to do something useful before killing the application! private: - static void create_impl(const xmlAccess::XmlGuiConfig& guiCfg, - const std::vector<Zstring>& referenceFiles, - const xmlAccess::XmlGlobalSettings& globalSettings, - bool startComparison); - MainDialog(const xmlAccess::XmlGuiConfig& guiCfg, const std::vector<Zstring>& referenceFiles, const xmlAccess::XmlGlobalSettings& globalSettings, //take over ownership => save on exit diff --git a/ui/msg_popup.h b/ui/msg_popup.h index 5e7ea97f..d93b5002 100644 --- a/ui/msg_popup.h +++ b/ui/msg_popup.h @@ -7,6 +7,7 @@ #ifndef MESSAGEPOPUP_H_820780154723456 #define MESSAGEPOPUP_H_820780154723456 +#include <zen/string_tools.h> #include <wx/window.h> #include <wx/string.h> @@ -66,9 +67,11 @@ class QuestConfig public: QuestConfig() : checkBoxValue(), disabledButtonsWhenChecked_() {} QuestConfig& setCaption (const wxString& label) { caption = label; return *this; } - QuestConfig& setLabelYes(const wxString& label) { labelYes = label; return *this; } - QuestConfig& setLabelNo (const wxString& label) { labelNo = label; return *this; } - QuestConfig& showCheckBox(bool& value, const wxString& label, int disabledButtonsWhenChecked) { checkBoxValue = &value; checkBoxLabel = label; disabledButtonsWhenChecked_ = disabledButtonsWhenChecked; return *this; } + QuestConfig& setLabelYes(const wxString& label) { assert(contains(label, L"&")); labelYes = label; return *this; } + QuestConfig& setLabelNo (const wxString& label) { assert(contains(label, L"&")); labelNo = label; return *this; } + QuestConfig& showCheckBox(bool& value, + const wxString& label, + int disabledButtonsWhenChecked) { assert(contains(label, L"&")); checkBoxValue = &value; checkBoxLabel = label; disabledButtonsWhenChecked_ = disabledButtonsWhenChecked; return *this; } private: friend class ::QuestionDlg; diff --git a/ui/progress_indicator.cpp b/ui/progress_indicator.cpp index 732b21c7..fd1c305d 100644 --- a/ui/progress_indicator.cpp +++ b/ui/progress_indicator.cpp @@ -26,6 +26,7 @@ #include <wx+/font_size.h> #include <wx+/std_button_order.h> #include <zen/file_handling.h> +#include <zen/thread.h> #include "gui_generated.h" #include "../lib/ffs_paths.h" #include "../lib/resources.h" @@ -33,10 +34,14 @@ #include "tray_icon.h" #include "taskbar.h" #include "exec_finished_box.h" -//#include <wx/msgdlg.h> + +#include <wx/msgdlg.h> using namespace zen; +warn_static("remove after test") +#include <zen/perf.h> + namespace { @@ -51,7 +56,7 @@ const int WINDOW_BYTES_PER_SEC = 5000; // class CompareProgressDialog::Pimpl : public CompareProgressDlgGenerated { public: - Pimpl(wxTopLevelWindow& parentWindow); + Pimpl(wxFrame& parentWindow); void init(const Statistics& syncStat); //constructor/destructor semantics, but underlying Window is reused void finalize(); // @@ -60,7 +65,7 @@ public: void updateStatusPanelNow(); private: - wxTopLevelWindow& parentWindow_; + wxFrame& parentWindow_; wxString titleTextBackup; wxStopWatch timeElapsed; @@ -75,7 +80,7 @@ private: }; -CompareProgressDialog::Pimpl::Pimpl(wxTopLevelWindow& parentWindow) : +CompareProgressDialog::Pimpl::Pimpl(wxFrame& parentWindow) : CompareProgressDlgGenerated(&parentWindow), parentWindow_(parentWindow), binCompStartMs(0), @@ -214,11 +219,13 @@ void CompareProgressDialog::Pimpl::updateStatusPanelNow() perf->addSample(objectsCurrent, to<double>(dataCurrent), timeNow); //current speed -> Win 7 copy uses 1 sec update interval instead - setText(*m_staticTextSpeed, perf->getBytesPerSecond(), &layoutChanged); + Opt<std::wstring> bps = perf->getBytesPerSecond(); + setText(*m_staticTextSpeed, bps ? *bps : L"-", &layoutChanged); //remaining time: display with relative error of 10% - based on samples taken every 0.5 sec only //-> call more often than once per second to correctly show last few seconds countdown, but don't call too often to avoid occasional jitter - setText(*m_staticTextRemTime, perf->getRemainingTime(to<double>(dataTotal - dataCurrent)), &layoutChanged); + Opt<std::wstring> rt = perf->getRemainingTime(to<double>(dataTotal - dataCurrent)); + setText(*m_staticTextRemTime, rt ? *rt : L"-", &layoutChanged); } } break; @@ -238,17 +245,17 @@ void CompareProgressDialog::Pimpl::updateStatusPanelNow() wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") : wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged); - //do the ui update if (layoutChanged) bSizer42->Layout(); - updateUiNow(); + //do the ui update + wxTheApp->Yield(); } //######################################################################################## //redirect to implementation -CompareProgressDialog::CompareProgressDialog(wxTopLevelWindow& parentWindow) : +CompareProgressDialog::CompareProgressDialog(wxFrame& parentWindow) : pimpl(new Pimpl(parentWindow)) {} //owned by parentWindow wxWindow* CompareProgressDialog::getAsWindow() @@ -715,7 +722,7 @@ private: } catch (const std::bad_alloc& e) { - wxMessageBox(_("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(_("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()), L"FreeFileSync - " + _("Error"), wxOK | wxICON_ERROR); } } @@ -726,88 +733,212 @@ private: namespace { -class GraphDataBytes : public GraphData +class CurveDataStatistics : public SparseCurveData { public: - void addRecord(double currentBytes, long timeMs) + CurveDataStatistics() : SparseCurveData(true), timeNow(0) {} + + void clear() { samples.clear(); timeNow = 0; } + + void addRecord(long timeNowMs, double value) { - data.insert(data.end(), std::make_pair(timeMs, currentBytes)); + warn_static("review") + timeNow = timeNowMs; + if (!samples.empty() && samples.rbegin()->second == value) + return; //don't insert duplicate values + + samples.insert(samples.end(), std::make_pair(timeNowMs, value)); //use fact that time is monotonously ascending //documentation differs about whether "hint" should be before or after the to be inserted element! //however "std::map<>::end()" is interpreted correctly by GCC and VS2010 - if (data.size() > MAX_BUFFER_SIZE) //limit buffer size - data.erase(data.begin()); + if (samples.size() > MAX_BUFFER_SIZE) //limit buffer size + samples.erase(samples.begin()); } - void clear() { data.clear(); } +private: + virtual std::pair<double, double> getRangeX() const final + { + if (samples.empty()) return std::make_pair(0.0, 0.0); - virtual double getXBegin() const { return data.empty() ? 0 : data.begin()->first / 1000.0; } //need not start with 0, e.g. "binary comparison, graph reset, followed by sync" - virtual double getXEnd () const { return data.empty() ? 0 : (--data.end())->first / 1000.0; } + double upperEndMs = std::max(timeNow, samples.rbegin()->first); -private: - static const size_t MAX_BUFFER_SIZE = 2500000; //sizeof(single node) worst case ~ 3 * 8 byte ptr + 16 byte key/value = 40 byte + //request some additional width by 5% elapsed time to make graph recalibrate before hitting the right border + //caveat: graph for batch mode binary comparison does NOT start at elapsed time 0!! PHASE_COMPARING_CONTENT and PHASE_SYNCHRONIZING! + //=> consider width of current sample set! + upperEndMs += 0.05 *(upperEndMs - samples.begin()->first); - virtual double getValue(double x) const //x: seconds since begin + return std::make_pair(samples.begin()->first / 1000.0, //need not start with 0, e.g. "binary comparison, graph reset, followed by sync" + upperEndMs / 1000.0); + } + + virtual Opt<CurvePoint> getLessEq(double x) const final //x: seconds since begin { - auto it = data.lower_bound(x * 1000); - if (it == data.end()) - return data.empty() ? 0 : (--data.end())->second; - return it->second; + const long timex = std::floor(x * 1000); + //------ add artifical last sample value ------- + if (!samples.empty() && samples.rbegin()->first < timeNow) + if (timeNow <= timex) + return CurvePoint(timeNow / 1000.0, samples.rbegin()->second); + //-------------------------------------------------- + + //find first key > x, then go one step back: => samples must be a std::map, NOT std::multimap!!! + auto it = samples.upper_bound(timex); + if (it == samples.begin()) + return NoValue(); + //=> samples not empty in this context + --it; + return CurvePoint(it->first / 1000.0, it->second); } - //example: two-element range is accessible within [0, 2) - std::map<long, double> data; + virtual Opt<CurvePoint> getGreaterEq(double x) const final + { + const long timex = std::ceil(x * 1000); + //------ add artifical last sample value ------- + if (!samples.empty() && samples.rbegin()->first < timeNow) + if (samples.rbegin()->first < timex && timex <= timeNow) + return CurvePoint(timeNow / 1000.0, samples.rbegin()->second); + //-------------------------------------------------- + + auto it = samples.lower_bound(timex); + if (it == samples.end()) + return NoValue(); + return CurvePoint(it->first / 1000.0, it->second); + } + + static const size_t MAX_BUFFER_SIZE = 2500000; //sizeof(single node) worst case ~ 3 * 8 byte ptr + 16 byte key/value = 40 byte + + std::map<long, double> samples; //time, unit: [ms] !don't use std::multimap, see getLessEq() + long timeNow; //help create an artificial record at the end of samples to visualize current time! }; -class GraphDataConstLine : public GraphData //a constant line +class CurveDataCurrentValue : public CurveData { public: - GraphDataConstLine() : value_(0) {} + CurveDataCurrentValue() : x(0), yCurrent_(0), yTotal_(0) {} - void setValue(double val) { value_ = val; } + void setValue(long xTimeNowMs, double yCurrent, double yTotal) { x = xTimeNowMs / 1000.0; yCurrent_ = yCurrent; yTotal_ = yTotal; } private: - virtual double getValue(double x) const { return value_; } - virtual double getXBegin() const { return -std::numeric_limits<double>::infinity(); } - virtual double getXEnd () const { return std::numeric_limits<double>::infinity(); } + virtual std::pair<double, double> getRangeX() const final { return std::make_pair(x, x); } //conceptually just a vertical line! - double value_; + virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final + { + + warn_static("remove after test") +#if 0 + if (yTotal_ > 100) + { +points.push_back(CurvePoint(0.38552801074951426,0.3861846045528107)); +points.push_back(CurvePoint(-0.5565680734345084,1.793989720937398)); +points.push_back(CurvePoint(2.85210684934041,3.339141677944872)); +points.push_back(CurvePoint(0.45404408959926135,0.7810567713436095)); +points.push_back(CurvePoint(2.303978218542433,-0.6610850551966995)); +points.push_back(CurvePoint(-2.5606633797896112,-0.4035597290287872)); +points.push_back(CurvePoint(-0.5394390537220716,0.40335295963067147)); + + + //points.push_back(CurvePoint(0.2885508231771302,-1.9264175407823294)); + //points.push_back(CurvePoint(-1.9332518577512143,0.6244007597162101)); + //points.push_back(CurvePoint(3.116299689813205,1.6973640131005165)); + //points.push_back(CurvePoint(0.0,0.0)); + //points.push_back(CurvePoint(-5.993091301993007,0.5231778112837284)); + return; + } +#endif + + + + + + + if (x <= maxX) + { + points.push_back(CurvePoint(x, 0)); + points.push_back(CurvePoint(x, yCurrent_)); + points.push_back(CurvePoint(maxX, yCurrent_)); + points.push_back(CurvePoint(x, yCurrent_)); + points.push_back(CurvePoint(x, yTotal_)); + } + } + + double x; //time elapsed in seconds + double yCurrent_; //current bytes/items + double yTotal_; }; -inline -double bestFit(double val, double low, double high) { return val < (high + low) / 2 ? low : high; } +class CurveDataTotalValue : public CurveData +{ +public: + CurveDataTotalValue () : x(0), yTotal_(0) {} + + void setValue(long xTimeNowMs, double yTotal) { x = xTimeNowMs / 1000.0; yTotal_ = yTotal; } + +private: + virtual std::pair<double, double> getRangeX() const final { return std::make_pair(x, x); } //conceptually just a vertical line! + + virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final + { + if (x <= maxX) + { + points.push_back(CurvePoint(x, yTotal_)); + points.push_back(CurvePoint(maxX, yTotal_)); + } + } + + double x; //time elapsed in seconds + double yTotal_; +}; struct LabelFormatterBytes : public LabelFormatter { virtual double getOptimalBlockSize(double bytesProposed) const { - if (bytesProposed <= 0) - return 0; + if (bytesProposed <= 1) //never smaller than 1 byte + return 1; - bytesProposed *= 1.5; //enlarge block default size + bytesProposed *= 1.4; //enlarge block default size //round to next number which is a convenient to read block size const double k = std::floor(std::log(bytesProposed) / std::log(2.0)); const double e = std::pow(2.0, k); if (numeric::isNull(e)) return 0; - const double a = bytesProposed / e; //bytesProposed = a * 2^k with a in (1, 2) - assert(1 < a && a < 2); - return bestFit(a, 1, 2) * e; + const double a = bytesProposed / e; //bytesProposed = a * 2^k with a in [1, 2) + assert(1 <= a && a < 2); + const double steps[] = { 1, 2 }; + return e * numeric::nearMatch(a, std::begin(steps), std::end(steps)); } virtual wxString formatText(double value, double optimalBlockSize) const { return filesizeToShortString(Int64(value)); }; }; +struct LabelFormatterItemCount : public LabelFormatter +{ + virtual double getOptimalBlockSize(double itemsProposed) const + { + const double steps[] = { 1, 2, 5, 10 }; + if (itemsProposed <= 10) + return numeric::nearMatch(itemsProposed, std::begin(steps), std::end(steps)); //similar to nextNiceNumber(), but without the 2.5 step! + return nextNiceNumber(itemsProposed); + } + + virtual wxString formatText(double value, double optimalBlockSize) const + { + return toGuiString(numeric::round(value)); //not enough room for a "%x items" representation + }; +}; + + struct LabelFormatterTimeElapsed : public LabelFormatter { + LabelFormatterTimeElapsed(bool drawLabel) : drawLabel_(drawLabel) {} + virtual double getOptimalBlockSize(double secProposed) const { - const double stepsSec[] = { 10, 20, 30, 60 }; //10 sec: minimum block size; no 15: avoid flicker between 10<->15<->20 sec blocks + const double stepsSec[] = { 20, 30, 60 }; //20 sec: minimum block size; (no 15: avoid flicker between 10<->15<->20 sec blocks) if (secProposed <= 60) return numeric::nearMatch(secProposed, std::begin(stepsSec), std::end(stepsSec)); @@ -816,215 +947,302 @@ struct LabelFormatterTimeElapsed : public LabelFormatter return 60.0 * numeric::nearMatch(secProposed / 60, std::begin(stepsMin), std::end(stepsMin)); if (secProposed <= 3600 * 24) - return nextNiceNumber(secProposed / 3600) * 3600; + return nextNiceNumber(secProposed / 3600) * 3600; //round up to full hours - return nextNiceNumber(secProposed / (24 * 3600)) * 24 * 3600; //round up to full days + return nextNiceNumber(secProposed / (24 * 3600)) * 24 * 3600; //round to full days } virtual wxString formatText(double timeElapsed, double optimalBlockSize) const { + if (!drawLabel_) return wxString(); return timeElapsed < 60 ? replaceCpy(_P("1 sec", "%x sec", numeric::round(timeElapsed)), L"%x", zen::numberTo<std::wstring>(numeric::round(timeElapsed))) : timeElapsed < 3600 ? wxTimeSpan::Seconds(timeElapsed).Format( L"%M:%S") : wxTimeSpan::Seconds(timeElapsed).Format(L"%H:%M:%S"); } -}; -//void fitHeight(wxTopLevelWindow& wnd) -//{ -// if (wnd.IsMaximized()) -// return; -// //Fit() height only: -// int width = wnd.GetSize().GetWidth(); -// wnd.Fit(); -// int height = wnd.GetSize().GetHeight(); -// wnd.SetSize(wxSize(width, height)); -//} +private: + bool drawLabel_; +}; } -class SyncProgressDialogImpl : private SyncProgressDlgGenerated, public SyncProgressDialog +template <class TopLevelDialog> //can be a wxFrame or wxDialog +class SyncProgressDialogImpl : private TopLevelDialog, public SyncProgressDialog +/*we need derivation, not composition! + 1. SyncProgressDialogImpl IS a wxFrame/wxDialog + 2. implement virtual ~wxFrame() + 3. event handling below assumes lifetime is larger-equal than wxFrame's +*/ { public: - SyncProgressDialogImpl(AbortCallback& abortCb, + SyncProgressDialogImpl(long style, //wxFrame/wxDialog style + const std::function<wxFrame*(TopLevelDialog& progDlg)>& getTaskbarFrame, + AbortCallback& abortCb, const std::function<void()>& notifyWindowTerminate, const Statistics& syncStat, - wxTopLevelWindow* parentWindow, + wxFrame* parentFrame, bool showProgress, const wxString& jobName, const std::wstring& execWhenFinished, std::vector<std::wstring>& execFinishedHistory); - ~SyncProgressDialogImpl(); + virtual ~SyncProgressDialogImpl(); //call this in StatusUpdater derived class destructor at the LATEST(!) to prevent access to currentStatusUpdater virtual void processHasFinished(SyncResult resultId, const ErrorLog& log); virtual void closeWindowDirectly(); - virtual wxWindow* getAsWindow() { return this; } + virtual wxWindow* getWindowIfVisible() { return this->IsShown() ? this : nullptr; } + //workaround OS X bug: if "this" is used as parent window for a modal dialog then this dialog will erroneously un-hide its parent! + virtual void initNewPhase(); virtual void notifyProgressChange(); - virtual void updateGui() { updateGuiInt(true); } - - virtual std::wstring getExecWhenFinishedCommand() const; + virtual void updateGui() { + + + warn_static("remove after test") +#if 0 + static bool init = false; + static wxStopWatch sw; + if (!init) + { + init = true; + sw.Start(); + } + if (sw.Time() > 1000 * 10) + { + PERF_START + for (int i = 0; i < 10000; ++i) + //for (int i = 0; i < 1000000; ++i) + updateGuiInt(true); + sw.Start(); + sw.Pause(); + } +#endif + + + + + + + updateGuiInt(true); } + + virtual std::wstring getExecWhenFinishedCommand() const { return pnl.m_comboBoxExecFinished->getValue(); } virtual void stopTimer() //halt all internal counters! { - m_animCtrlSyncing->Stop(); + pnl.m_animCtrlSyncing->Stop(); timeElapsed.Pause (); } virtual void resumeTimer() { - m_animCtrlSyncing->Play(); + pnl.m_animCtrlSyncing->Play(); timeElapsed.Resume(); } private: void updateGuiInt(bool allowYield); - void minimizeToTray(); void OnKeyPressed(wxKeyEvent& event); - virtual void OnOkay (wxCommandEvent& event); - virtual void OnPause (wxCommandEvent& event); - virtual void OnCancel (wxCommandEvent& event); - virtual void OnClose (wxCloseEvent& event); - virtual void OnIconize(wxIconizeEvent& event); - - void updateDialogStatus(); + void OnOkay (wxCommandEvent& event); + void OnPause (wxCommandEvent& event); + void OnCancel (wxCommandEvent& event); + void OnClose (wxCloseEvent& event); + void OnIconize(wxIconizeEvent& event); + void OnMinimizeToTray(wxCommandEvent& event) { minimizeToTray(); } + void minimizeToTray(); void resumeFromSystray(); - void OnResumeFromTray(wxCommandEvent& event); + void updateDialogStatus(); void setExternalStatus(const wxString& status, const wxString& progress); //progress may be empty! + SyncProgressPanelGenerated& pnl; //wxPanel containing the GUI controls of *this + const wxString jobName_; wxStopWatch timeElapsed; - wxTopLevelWindow* mainDialog; //optional + wxFrame* parentFrame_; //optional std::function<void()> notifyWindowTerminate_; //call once in OnClose(), NOT in destructor which is called far too late somewhere in wxWidgets main loop! + bool wereDead; //after wxWindow::Delete, which is equal to "delete this" on OS X! + //status variables const Statistics* syncStat_; // AbortCallback* abortCb_; //valid only while sync is running bool paused_; //valid only while sync is running SyncResult finalResult; //set after sync - bool isZombie; //wxGTK sends iconize event *after* wxWindow::Destroy, sigh... - //remaining time std::unique_ptr<PerfCheck> perf; long lastStatCallSpeed; //used for calculating intervals between collecting perf samples //help calculate total speed long phaseStartMs; //begin of current phase in [ms] - std::shared_ptr<GraphDataBytes> graphDataBytes; - std::shared_ptr<GraphDataConstLine> graphDataBytesTotal; + std::shared_ptr<CurveDataStatistics> curveDataBytes; + std::shared_ptr<CurveDataStatistics> curveDataItems; - wxString titelTextBackup; + std::shared_ptr<CurveDataTotalValue > curveDataBytesTotal; + std::shared_ptr<CurveDataCurrentValue> curveDataBytesCurrent; + std::shared_ptr<CurveDataTotalValue > curveDataItemsTotal; + std::shared_ptr<CurveDataCurrentValue> curveDataItemsCurrent; + + wxString parentFrameTitleBackup; std::unique_ptr<FfsTrayIcon> trayIcon; //optional: if filled all other windows should be hidden and conversely std::unique_ptr<Taskbar> taskbar_; }; -SyncProgressDialogImpl::SyncProgressDialogImpl(AbortCallback& abortCb, - const std::function<void()>& notifyWindowTerminate, - const Statistics& syncStat, - wxTopLevelWindow* parentWindow, - bool showProgress, - const wxString& jobName, - const std::wstring& execWhenFinished, - std::vector<std::wstring>& execFinishedHistory) : - SyncProgressDlgGenerated(parentWindow, - wxID_ANY, - parentWindow ? wxString() : (wxString(L"FreeFileSync - ") + _("Folder Comparison and Synchronization")), - wxDefaultPosition, wxDefaultSize, - parentWindow ? - wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT : //wxTAB_TRAVERSAL is needed for standard button handling: wxID_OK/wxID_CANCEL - wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL), +template <class TopLevelDialog> +SyncProgressDialogImpl<TopLevelDialog>::SyncProgressDialogImpl(long style, //wxFrame/wxDialog style + const std::function<wxFrame*(TopLevelDialog& progDlg)>& getTaskbarFrame, + AbortCallback& abortCb, + const std::function<void()>& notifyWindowTerminate, + const Statistics& syncStat, + wxFrame* parentFrame, + bool showProgress, + const wxString& jobName, + const std::wstring& execWhenFinished, + std::vector<std::wstring>& execFinishedHistory) : + TopLevelDialog(parentFrame, wxID_ANY, wxString(), wxDefaultPosition, wxDefaultSize, style), //title is overwritten anyway in setExternalStatus() + pnl(*new SyncProgressPanelGenerated(this)), //ownership passed to "this" jobName_ (jobName), - mainDialog(parentWindow), + parentFrame_(parentFrame), notifyWindowTerminate_(notifyWindowTerminate), + wereDead(false), syncStat_ (&syncStat), abortCb_ (&abortCb), paused_ (false), finalResult(RESULT_ABORTED), //dummy value - isZombie(false), lastStatCallSpeed(-1000000), //some big number phaseStartMs(0) { + assert_static((IsSameType<TopLevelDialog, wxFrame >::value || + IsSameType<TopLevelDialog, wxDialog>::value)); + assert((IsSameType<TopLevelDialog, wxFrame>::value == !parentFrame)); + + //finish construction of this dialog: + this->SetMinSize(wxSize(470, 280)); //== minimum size! no idea why SetMinSize() is not used... + wxBoxSizer* bSizer170 = new wxBoxSizer(wxVERTICAL); + bSizer170->Add(&pnl, 1, wxEXPAND); + this->SetSizer(bSizer170); //pass ownership + //this->Layout(); + //bSizer170->Fit(this); + this->Centre(wxBOTH); + + //lifetime of event sources is subset of this instance's lifetime => no wxEvtHandler::Disconnect() needed + this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler (SyncProgressDialogImpl<TopLevelDialog>::OnClose)); + this->Connect(wxEVT_ICONIZE, wxIconizeEventHandler(SyncProgressDialogImpl<TopLevelDialog>::OnIconize)); + this->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(SyncProgressDialogImpl::OnKeyPressed), nullptr, this); + pnl.m_buttonClose ->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SyncProgressDialogImpl::OnOkay ), NULL, this); + pnl.m_buttonPause ->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SyncProgressDialogImpl::OnPause ), NULL, this); + pnl.m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SyncProgressDialogImpl::OnCancel), NULL, this); + pnl.m_bpButtonMinimizeToTray->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SyncProgressDialogImpl::OnMinimizeToTray), NULL, this); + #ifdef ZEN_WIN new MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this" #endif - assert(m_buttonClose->GetId() == wxID_OK); //we cannot use wxID_CLOSE else Esc key won't work: yet another wxWidgets bug?? + assert(pnl.m_buttonClose->GetId() == wxID_OK); //we cannot use wxID_CLOSE else Esc key won't work: yet another wxWidgets bug?? - setRelativeFontSize(*m_staticTextPhase, 1.5); + setRelativeFontSize(*pnl.m_staticTextPhase, 1.5); - if (mainDialog) - titelTextBackup = mainDialog->GetTitle(); //save old title (will be used as progress indicator) + if (parentFrame_) + parentFrameTitleBackup = parentFrame_->GetTitle(); //save old title (will be used as progress indicator) - m_animCtrlSyncing->SetAnimation(GlobalResources::instance().aniWorking); - m_animCtrlSyncing->Play(); + pnl.m_animCtrlSyncing->SetAnimation(GlobalResources::instance().aniWorking); + pnl.m_animCtrlSyncing->Play(); - SetIcon(GlobalResources::instance().programIconFFS); - - //initialize gauge - m_gauge1->SetRange(GAUGE_FULL_RANGE); - m_gauge1->SetValue(0); + this->SetIcon(GlobalResources::instance().programIconFFS); - EnableCloseButton(false); //this is NOT honored on OS X or during system shutdown on Windows! - - if (IsShown()) //don't steal focus when starting in sys-tray! - m_buttonCancel->SetFocus(); + this->EnableCloseButton(false); //this is NOT honored on OS X or during system shutdown on Windows! timeElapsed.Start(); //measure total time - try //try to get access to Windows 7/Ubuntu taskbar - { - taskbar_ = make_unique<Taskbar>(mainDialog ? *static_cast<wxTopLevelWindow*>(mainDialog) : *this); - } - catch (const TaskbarNotAvailable&) {} + if (wxFrame* frame = getTaskbarFrame(*this)) + try //try to get access to Windows 7/Ubuntu taskbar + { + taskbar_ = make_unique<Taskbar>(*frame); //throw TaskbarNotAvailable + } + catch (const TaskbarNotAvailable&) {} //hide "processed" statistics until end of process - m_notebookResult ->Hide(); - m_staticTextLabelItemsProc->Show(false); - bSizerItemsProc ->Show(false); - m_buttonClose ->Show(false); + pnl.m_notebookResult ->Hide(); + pnl.m_panelItemsProcessed->Hide(); + pnl.m_buttonClose ->Show(false); //set std order after button visibility was set - setStandardButtonOrder(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonPause).setCancel(m_buttonCancel)); + setStandardButtonOrder(*pnl.bSizerStdButtons, StdButtons().setAffirmative(pnl.m_buttonPause).setCancel(pnl.m_buttonCancel)); - //register key event - Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(SyncProgressDialogImpl::OnKeyPressed), nullptr, this); + pnl.m_bpButtonMinimizeToTray->SetBitmapLabel(getResourceImage(L"minimize_to_tray")); //init graph - graphDataBytes = std::make_shared<GraphDataBytes>(); - graphDataBytesTotal = std::make_shared<GraphDataConstLine>(); + curveDataBytes = std::make_shared<CurveDataStatistics>(); + curveDataItems = std::make_shared<CurveDataStatistics>(); + curveDataBytesTotal = std::make_shared<CurveDataTotalValue>(); + curveDataBytesCurrent = std::make_shared<CurveDataCurrentValue>(); + curveDataItemsTotal = std::make_shared<CurveDataTotalValue>(); + curveDataItemsCurrent = std::make_shared<CurveDataCurrentValue>(); + + const int xLabelHeight = 18; //we need to use the same height for both graphs to make sure they stretch evenly + const int yLabelWidth = 70; + pnl.m_panelGraphBytes->setAttributes(Graph2D::MainAttributes(). + setLabelX(Graph2D::X_LABEL_BOTTOM, xLabelHeight, std::make_shared<LabelFormatterTimeElapsed>(true)). + setLabelY(Graph2D::Y_LABEL_RIGHT, yLabelWidth, std::make_shared<LabelFormatterBytes>()). + setSelectionMode(Graph2D::SELECT_NONE)); + + pnl.m_panelGraphItems->setAttributes(Graph2D::MainAttributes(). + setLabelX(Graph2D::X_LABEL_BOTTOM, xLabelHeight, std::make_shared<LabelFormatterTimeElapsed>(false)). + setLabelY(Graph2D::Y_LABEL_RIGHT, yLabelWidth, std::make_shared<LabelFormatterItemCount>()). + setSelectionMode(Graph2D::SELECT_NONE)); + + pnl.m_panelGraphBytes->setCurve(curveDataBytes, Graph2D::CurveAttributes().setLineWidth(2). + fillCurveArea(wxColor(205, 255, 202)). //faint green + setColor (wxColor( 20, 200, 0))); //medium green + + pnl.m_panelGraphItems->setCurve(curveDataItems, Graph2D::CurveAttributes().setLineWidth(2). + fillCurveArea(wxColor(198, 206, 255)). //faint blue + setColor (wxColor( 90, 120, 255))); //medium blue + + pnl.m_panelGraphBytes->addCurve(curveDataBytesTotal, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(12, 128, 0))); //dark green + pnl.m_panelGraphBytes->addCurve(curveDataBytesCurrent, Graph2D::CurveAttributes().setLineWidth(1).setColor(wxColor(12, 128, 0))); // + + pnl.m_panelGraphItems->addCurve(curveDataItemsTotal, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(53, 25, 255))); //dark blue + pnl.m_panelGraphItems->addCurve(curveDataItemsCurrent, Graph2D::CurveAttributes().setLineWidth(1).setColor(wxColor(53, 25, 255))); // + + //allow changing on completion command + pnl.m_comboBoxExecFinished->initHistory(execFinishedHistory, execFinishedHistory.size()); //-> we won't use addItemHistory() later + pnl.m_comboBoxExecFinished->setValue(execWhenFinished); + + updateDialogStatus(); //null-status will be shown while waiting for dir locks + + + warn_static("remove after test") +#if 0 + pnl.m_panelGraphBytes->setAttributes(Graph2D::MainAttributes().setMinX(-1).setMaxX(1).setMinY(-1).setMaxY(1)); + pnl.m_panelGraphBytes->setCurve(curveDataBytesCurrent, Graph2D::CurveAttributes().setLineWidth(6).setColor(wxColor(12, 128, 0)) + .fillCurveArea(wxColor(198, 206, 255)) //faint blue + ); // +#endif + + + - m_panelGraph->setAttributes(Graph2D::MainAttributes(). - setLabelX(Graph2D::X_LABEL_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()). - setLabelY(Graph2D::Y_LABEL_RIGHT, 70, std::make_shared<LabelFormatterBytes>()). - setSelectionMode(Graph2D::SELECT_NONE)); - m_panelGraph->setData(graphDataBytes, - Graph2D::CurveAttributes().setLineWidth(2). - setColor (wxColor( 0, 192, 0)). //medium green - fillCurveArea(wxColor(192, 255, 192))); //faint green - m_panelGraph->addData(graphDataBytesTotal, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 64, 0))); //dark green - //allow changing on completion command - m_comboBoxExecFinished->initHistory(execFinishedHistory, execFinishedHistory.size()); //-> we won't use addItemHistory() later - m_comboBoxExecFinished->setValue(execWhenFinished); - updateDialogStatus(); //null-status will be shown while waiting for dir locks (if at all) - Fit(); - Layout(); + + this->Fit(); + pnl.Layout(); if (showProgress) { - Show(); + this->Show(); + pnl.m_buttonCancel->SetFocus(); //don't steal focus when starting in sys-tray! + //clear gui flicker, remove dummy texts: window must be visible to make this work! updateGuiInt(true); //at least on OS X a real Yield() is required to flush pending GUI updates; Update() is not enough } @@ -1033,24 +1251,25 @@ SyncProgressDialogImpl::SyncProgressDialogImpl(AbortCallback& abortCb, } -SyncProgressDialogImpl::~SyncProgressDialogImpl() +template <class TopLevelDialog> +SyncProgressDialogImpl<TopLevelDialog>::~SyncProgressDialogImpl() { - if (mainDialog) + if (parentFrame_) { - mainDialog->SetTitle(titelTextBackup); //restore title text + parentFrame_->SetTitle(parentFrameTitleBackup); //restore title text //make sure main dialog is shown again if still "minimized to systray"! see SyncProgressDialog::closeWindowDirectly() - if (mainDialog->IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! - mainDialog->Iconize(false); - - mainDialog->Show(); + parentFrame_->Show(); + //if (parentFrame_->IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! + // parentFrame_->Iconize(false); } //our client is NOT expecting a second call via notifyWindowTerminate_()! } -void SyncProgressDialogImpl::OnKeyPressed(wxKeyEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnKeyPressed(wxKeyEvent& event) { const int keyCode = event.GetKeyCode(); if (keyCode == WXK_ESCAPE) @@ -1058,15 +1277,15 @@ void SyncProgressDialogImpl::OnKeyPressed(wxKeyEvent& event) wxCommandEvent dummy(wxEVT_COMMAND_BUTTON_CLICKED); //simulate click on abort button - if (m_buttonCancel->IsShown()) //delegate to "cancel" button if available + if (pnl.m_buttonCancel->IsShown()) //delegate to "cancel" button if available { - if (wxEvtHandler* handler = m_buttonCancel->GetEventHandler()) + if (wxEvtHandler* handler = pnl.m_buttonCancel->GetEventHandler()) handler->ProcessEvent(dummy); return; } - else if (m_buttonClose->IsShown()) + else if (pnl.m_buttonClose->IsShown()) { - if (wxEvtHandler* handler = m_buttonClose->GetEventHandler()) + if (wxEvtHandler* handler = pnl.m_buttonClose->GetEventHandler()) handler->ProcessEvent(dummy); return; } @@ -1076,29 +1295,33 @@ void SyncProgressDialogImpl::OnKeyPressed(wxKeyEvent& event) } -void SyncProgressDialogImpl::initNewPhase() +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::initNewPhase() { updateDialogStatus(); //evaluates "syncStat_->currentPhase()" - //reset graph (e.g. after binary comparison) - graphDataBytes->clear(); + //reset graphs (e.g. after binary comparison) + curveDataBytesTotal ->setValue(0, 0); + curveDataBytesCurrent->setValue(0, 0, 0); + curveDataItemsTotal ->setValue(0, 0); + curveDataItemsCurrent->setValue(0, 0, 0); + curveDataBytes->clear(); + curveDataItems->clear(); + notifyProgressChange(); //start new measurement perf = make_unique<PerfCheck>(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC); - lastStatCallSpeed = -1000000; //some big number + lastStatCallSpeed = -1000000; //some big number phaseStartMs = timeElapsed.Time(); - //set to 0 even if totalDataToProcess is 0: due to a bug in wxGauge::SetValue, it doesn't change to determinate mode when setting the old value again - //so give updateGui() a chance to set a different value - m_gauge1->SetValue(0); - updateGuiInt(false); } -void SyncProgressDialogImpl::notifyProgressChange() //noexcept! +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::notifyProgressChange() //noexcept! { if (syncStat_) //sync running switch (syncStat_->currentPhase()) @@ -1109,13 +1332,9 @@ void SyncProgressDialogImpl::notifyProgressChange() //noexcept! break; case ProcessCallback::PHASE_COMPARING_CONTENT: case ProcessCallback::PHASE_SYNCHRONIZING: - { - const double currentData = to<double>(syncStat_->getDataCurrent(syncStat_->currentPhase())); - - //add sample for perf measurements + calc. of remaining time - graphDataBytes->addRecord(currentData, timeElapsed.Time()); - } - break; + curveDataBytes->addRecord(timeElapsed.Time(), to<double>(syncStat_->getDataCurrent (syncStat_->currentPhase()))); + curveDataItems->addRecord(timeElapsed.Time(), syncStat_->getObjectsCurrent(syncStat_->currentPhase())); + break; } } @@ -1140,7 +1359,7 @@ Zorder evaluateZorder(const wxWindow& top, const wxWindow& bottom) if (hAbove == hTop) return ZORDER_CORRECT; - for (HWND hAbove = ::GetNextWindow(hTop, GW_HWNDPREV); hAbove; hAbove = ::GetNextWindow(hAbove, GW_HWNDPREV)) + for (HWND hAbove = hTop; hAbove; hAbove = ::GetNextWindow(hAbove, GW_HWNDPREV)) if (hAbove == hBottom) return ZORDER_WRONG; @@ -1183,7 +1402,8 @@ std::wstring getDialogPhaseText(const Statistics* syncStat, bool paused, SyncPro } -void SyncProgressDialogImpl::setExternalStatus(const wxString& status, const wxString& progress) //progress may be empty! +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::setExternalStatus(const wxString& status, const wxString& progress) //progress may be empty! { //sys tray: order "top-down": jobname, status, progress wxString newTrayInfo = jobName_.empty() ? status : L"\"" + jobName_ + L"\"\n" + status; @@ -1200,10 +1420,10 @@ void SyncProgressDialogImpl::setExternalStatus(const wxString& status, const wxS trayIcon->setToolTip(newTrayInfo); //show text in dialog title (and at the same time in taskbar) - if (mainDialog) + if (parentFrame_) { - if (mainDialog->GetTitle() != newCaption) - mainDialog->SetTitle(newCaption); + if (parentFrame_->GetTitle() != newCaption) + parentFrame_->SetTitle(newCaption); } //always set a title: we don't wxGTK to show "nameless window" instead @@ -1212,7 +1432,8 @@ void SyncProgressDialogImpl::setExternalStatus(const wxString& status, const wxS } -void SyncProgressDialogImpl::updateGuiInt(bool allowYield) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::updateGuiInt(bool allowYield) { if (!syncStat_) //sync not running return; @@ -1223,7 +1444,7 @@ void SyncProgressDialogImpl::updateGuiInt(bool allowYield) const long timeNow = timeElapsed.Time(); //sync status text - setText(*m_staticTextStatus, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts! + setText(*pnl.m_staticTextStatus, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts! switch (syncStat_->currentPhase()) //no matter if paused or not { @@ -1233,33 +1454,30 @@ void SyncProgressDialogImpl::updateGuiInt(bool allowYield) setExternalStatus(getDialogPhaseText(syncStat_, paused_, finalResult), toGuiString(syncStat_->getObjectsCurrent(ProcessCallback::PHASE_SCANNING))); //status text may be "paused"! //progress indicators - m_gauge1->Pulse(); - if (trayIcon.get()) trayIcon->setProgress(1); //1 = regular FFS logo + if (trayIcon.get()) trayIcon->setProgress(1); //100% = regular FFS logo - //taskbar_ status is Taskbar::STATUS_INDETERMINATE - - //constant line graph - graphDataBytesTotal->setValue(0); + //ignore graphs: should already have been cleared in initNewPhase() //remaining objects and data - setText(*m_staticTextRemainingObj , L"-", &layoutChanged); - setText(*m_staticTextDataRemaining, L"", &layoutChanged); + setText(*pnl.m_staticTextRemainingObj , L"-", &layoutChanged); + setText(*pnl.m_staticTextDataRemaining, L"", &layoutChanged); //remaining time and speed - setText(*m_staticTextSpeed, L"-", &layoutChanged); - setText(*m_staticTextRemTime, L"-", &layoutChanged); + setText(*pnl.m_staticTextRemTime, L"-", &layoutChanged); + pnl.m_panelGraphBytes->setAttributes(pnl.m_panelGraphBytes->getAttributes().setCornerText(wxString(), Graph2D::CORNER_TOP_LEFT)); + pnl.m_panelGraphItems->setAttributes(pnl.m_panelGraphItems->getAttributes().setCornerText(wxString(), Graph2D::CORNER_TOP_LEFT)); break; case ProcessCallback::PHASE_COMPARING_CONTENT: case ProcessCallback::PHASE_SYNCHRONIZING: { - auto objectsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase()); - auto objectsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase()); - auto dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase()); - auto dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase()); + const int itemsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase()); + const int itemsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase()); + const Int64 dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase()); + const Int64 dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase()); //add both data + obj-count, to handle "deletion-only" cases - const double fraction = dataTotal + objectsTotal == 0 ? 1 : std::max(0.0, to<double>(dataCurrent + objectsCurrent) / to<double>(dataTotal + objectsTotal)); + const double fraction = dataTotal + itemsTotal == 0 ? 1 : std::max(0.0, to<double>(dataCurrent + itemsCurrent) / to<double>(dataTotal + itemsTotal)); //yes, this may legitimately become < 0: failed rename operation falls-back to copy + delete, reducing "dataCurrent" to potentially < 0! //---------------------------------------------------------------------------------------------------- @@ -1267,16 +1485,22 @@ void SyncProgressDialogImpl::updateGuiInt(bool allowYield) setExternalStatus(getDialogPhaseText(syncStat_, paused_, finalResult), fractionToString(fraction)); //status text may be "paused"! //progress indicators - m_gauge1->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE)); if (trayIcon.get()) trayIcon->setProgress(fraction); if (taskbar_.get()) taskbar_->setProgress(fraction); //constant line graph - graphDataBytesTotal->setValue(to<double>(dataTotal)); - + curveDataBytesTotal ->setValue(timeNow, to<double>(dataTotal)); + curveDataBytesCurrent->setValue(timeNow, to<double>(dataCurrent), to<double>(dataTotal)); + curveDataItemsTotal ->setValue(timeNow, itemsTotal); + curveDataItemsCurrent->setValue(timeNow, itemsCurrent, itemsTotal); + //even though notifyProgressChange() already set the latest data, let's add another sample to have all curves consider "timeNow" + //no problem with adding too many records: CurveDataStatistics will remove duplicate entries! + curveDataBytes->addRecord(timeNow, to<double>(dataCurrent)); + curveDataItems->addRecord(timeNow, itemsCurrent); + //remaining objects and data - setText(*m_staticTextRemainingObj, toGuiString(objectsTotal - objectsCurrent), &layoutChanged); - setText(*m_staticTextDataRemaining, L"(" + filesizeToShortString(dataTotal - dataCurrent) + L")", &layoutChanged); + setText(*pnl.m_staticTextRemainingObj, toGuiString(itemsTotal - itemsCurrent), &layoutChanged); + setText(*pnl.m_staticTextDataRemaining, L"(" + filesizeToShortString(dataTotal - dataCurrent) + L")", &layoutChanged); //it's possible data remaining becomes shortly negative if last file synced has ADS data and the dataTotal was not yet corrected! //remaining time and speed @@ -1287,48 +1511,52 @@ void SyncProgressDialogImpl::updateGuiInt(bool allowYield) lastStatCallSpeed = timeNow; if (numeric::dist(phaseStartMs, timeNow) >= 1000) //discard stats for first second: probably messy - perf->addSample(objectsCurrent, to<double>(dataCurrent), timeNow); + perf->addSample(itemsCurrent, to<double>(dataCurrent), timeNow); //current speed -> Win 7 copy uses 1 sec update interval instead - setText(*m_staticTextSpeed, perf->getBytesPerSecond(), &layoutChanged); + Opt<std::wstring> bps = perf->getBytesPerSecond(); + Opt<std::wstring> ips = perf->getItemsPerSecond(); + pnl.m_panelGraphBytes->setAttributes(pnl.m_panelGraphBytes->getAttributes().setCornerText(bps ? *bps : L"", Graph2D::CORNER_TOP_LEFT)); + pnl.m_panelGraphItems->setAttributes(pnl.m_panelGraphItems->getAttributes().setCornerText(ips ? *ips : L"", Graph2D::CORNER_TOP_LEFT)); + //setText(*pnl.m_staticTextSpeed, perf->getBytesPerSecond(), &layoutChanged); //remaining time: display with relative error of 10% - based on samples taken every 0.5 sec only //-> call more often than once per second to correctly show last few seconds countdown, but don't call too often to avoid occasional jitter - setText(*m_staticTextRemTime, perf->getRemainingTime(to<double>(dataTotal - dataCurrent)), &layoutChanged); + Opt<std::wstring> rt = perf->getRemainingTime(to<double>(dataTotal - dataCurrent)); + setText(*pnl.m_staticTextRemTime, rt ? *rt : L"-", &layoutChanged); } } break; } - m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMinX(graphDataBytes->getXBegin())); - m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMaxX(graphDataBytes->getXEnd())); - m_panelGraph->Refresh(); + pnl.m_panelGraphBytes->Refresh(); + pnl.m_panelGraphItems->Refresh(); //time elapsed const long timeElapSec = timeNow / 1000; - setText(*m_staticTextTimeElapsed, + setText(*pnl.m_staticTextTimeElapsed, timeElapSec < 3600 ? wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") : wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged); - //do the ui update + //adapt layout after content changes above if (layoutChanged) { - // Layout(); - // bSizerItemsRem->Layout(); - // bSizer171->Layout(); - //bSizerProgressStat->Layout(); // - m_panelProgress->Layout(); //both needed - //m_panelBackground->Layout(); //we use a dummy panel as actual background: replaces simple "Layout()" call - //-> it seems this layout is not required, and even harmful: resets m_comboBoxExecFinished dropdown while user is selecting! + pnl.m_panelProgress->Layout(); + //small statistics panels: + //pnl.m_panelItemsProcessed->Layout(); + pnl.m_panelItemsRemaining->Layout(); + pnl.m_panelTimeRemaining ->Layout(); + //pnl.m_panelTimeElapsed->Layout(); -> needed? } #ifdef ZEN_WIN //workaround Windows 7 bug messing up z-order after temporary application hangs: https://sourceforge.net/tracker/index.php?func=detail&aid=3376523&group_id=234430&atid=1093080 - if (mainDialog) - if (evaluateZorder(*this, *mainDialog) == ZORDER_WRONG) + //This is still needed no matter if wxDialog or wxPanel is used! (2013-07) + if (parentFrame_) + if (evaluateZorder(*this, *parentFrame_) == ZORDER_WRONG) { - HWND hProgress = static_cast<HWND>(GetHWND()); + HWND hProgress = static_cast<HWND>(this->GetHWND()); if (::IsWindowVisible(hProgress)) { ::ShowWindow(hProgress, SW_HIDE); //make Windows recalculate z-order @@ -1342,47 +1570,58 @@ void SyncProgressDialogImpl::updateGuiInt(bool allowYield) //support for pause button if (paused_) { + /* + ZEN_ON_SCOPE_EXIT(resumeTimer()); -> crashes on Fedora; WHY??? + => likely compiler bug!!! + 1. no crash on Fedora for: ZEN_ON_SCOPE_EXIT(this->resumeTimer()); + 1. no crash if we derive from wxFrame instead of template "TopLevelDialog" + 2. no crash on Ubuntu GCC + 3. following makes GCC crash already during compilation: auto dfd = zen::makeGuard([this]{ resumeTimer(); }); + */ + stopTimer(); - ZEN_ON_SCOPE_EXIT(resumeTimer()); + while (paused_) { - wxMilliSleep(UI_UPDATE_INTERVAL); - updateUiNow(); //receive UI message that end pause + wxTheApp->Yield(); //receive UI message that end pause OR forceful termination! + //*first* refresh GUI (removing flicker) before sleeping! + boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)); } + //if SyncProgressDialogImpl::OnClose() already wxWindow::Destroy() on OS X then this instance is already toast! + if (wereDead) + return; //GTFO and don't call this->resumeTimer() + + resumeTimer(); } - /* - /|\ - | keep this sequence to ensure one full progress update before entering pause mode! - \|/ - */ - updateUiNow(); //receive UI message that sets pause status + else + /* + /|\ + | keep this sequence to ensure one full progress update before entering pause mode! + \|/ + */ + wxTheApp->Yield(); //receive UI message that sets pause status OR forceful termination! } else - Update(); //don't wait until next idle event (who knows what blocking process comes next?) + this->Update(); //don't wait until next idle event (who knows what blocking process comes next?) } -std::wstring SyncProgressDialogImpl::getExecWhenFinishedCommand() const -{ - return m_comboBoxExecFinished->getValue(); -} - - -void SyncProgressDialogImpl::updateDialogStatus() //depends on "syncStat_, paused_, finalResult" +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::updateDialogStatus() //depends on "syncStat_, paused_, finalResult" { const wxString dlgStatusTxt = getDialogPhaseText(syncStat_, paused_, finalResult); - m_staticTextPhase->SetLabel(dlgStatusTxt); + pnl.m_staticTextPhase->SetLabel(dlgStatusTxt); //status bitmap if (syncStat_) //sync running { auto setStatusBitmap = [&](const wchar_t* bmpName) { - m_animCtrlSyncing->Hide(); - m_bitmapStatus->SetBitmap(getResourceImage(bmpName)); - m_bitmapStatus->SetToolTip(dlgStatusTxt); - m_bitmapStatus->Show(); + pnl.m_animCtrlSyncing->Hide(); + pnl.m_bitmapStatus->SetBitmap(getResourceImage(bmpName)); + pnl.m_bitmapStatus->SetToolTip(dlgStatusTxt); + pnl.m_bitmapStatus->Show(); }; if (paused_) @@ -1391,8 +1630,8 @@ void SyncProgressDialogImpl::updateDialogStatus() //depends on "syncStat_, pause switch (syncStat_->currentPhase()) { case ProcessCallback::PHASE_NONE: - m_animCtrlSyncing->Hide(); - m_bitmapStatus->Hide(); + pnl.m_animCtrlSyncing->Hide(); + pnl.m_bitmapStatus->Hide(); break; case ProcessCallback::PHASE_SCANNING: @@ -1404,11 +1643,11 @@ void SyncProgressDialogImpl::updateDialogStatus() //depends on "syncStat_, pause break; case ProcessCallback::PHASE_SYNCHRONIZING: - m_bitmapStatus->SetBitmap(getResourceImage(L"status_syncing")); - m_bitmapStatus->SetToolTip(dlgStatusTxt); - m_bitmapStatus->Show(); - m_animCtrlSyncing->Show(); - m_animCtrlSyncing->SetToolTip(dlgStatusTxt); + pnl.m_bitmapStatus->SetBitmap(getResourceImage(L"status_syncing")); + pnl.m_bitmapStatus->SetToolTip(dlgStatusTxt); + pnl.m_bitmapStatus->Show(); + pnl.m_animCtrlSyncing->Show(); + pnl.m_animCtrlSyncing->SetToolTip(dlgStatusTxt); break; } } @@ -1416,10 +1655,10 @@ void SyncProgressDialogImpl::updateDialogStatus() //depends on "syncStat_, pause { auto setStatusBitmap = [&](const wchar_t* bmpName, const std::wstring& tooltip) { - m_animCtrlSyncing->Hide(); - m_bitmapStatus->SetBitmap(getResourceImage(bmpName)); - m_bitmapStatus->Show(); - m_bitmapStatus->SetToolTip(tooltip); + pnl.m_animCtrlSyncing->Hide(); + pnl.m_bitmapStatus->SetBitmap(getResourceImage(bmpName)); + pnl.m_bitmapStatus->Show(); + pnl.m_bitmapStatus->SetToolTip(tooltip); }; switch (finalResult) { @@ -1479,21 +1718,15 @@ void SyncProgressDialogImpl::updateDialogStatus() //depends on "syncStat_, pause //pause button if (syncStat_) //sync running - { - if (paused_) - m_buttonPause->SetLabel(_("Continue")); - else - m_buttonPause->SetLabel(_("Pause")); - } + pnl.m_buttonPause->SetLabel(paused_ ? _("&Continue") : _("&Pause")); - Layout(); - Refresh(); //a few pixels below the status text need refreshing + pnl.Layout(); + this->Refresh(); //a few pixels below the status text need refreshing } -warn_static("osx: minimize to systray?") - -void SyncProgressDialogImpl::closeWindowDirectly() //this should really be called: do not call back + schedule deletion +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::closeWindowDirectly() //this should really be called: do not call back + schedule deletion { paused_ = false; //you never know? //ATTENTION: dialog may live a little longer, so watch callbacks! @@ -1502,11 +1735,12 @@ void SyncProgressDialogImpl::closeWindowDirectly() //this should really be calle abortCb_ = nullptr; //resumeFromSystray(); -> NO, instead ~SyncProgressDialogImpl() makes sure that main dialog is shown again! - Close(); //generate close event: do NOT destroy window unconditionally! + this->Close(); //generate close event: do NOT destroy window unconditionally! } -void SyncProgressDialogImpl::processHasFinished(SyncResult resultId, const ErrorLog& log) //essential to call this in StatusHandler derived class destructor +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::processHasFinished(SyncResult resultId, const ErrorLog& log) //essential to call this in StatusHandler derived class destructor { //at the LATEST(!) to prevent access to currentStatusHandler //enable okay and close events; may be set in this method ONLY @@ -1530,36 +1764,30 @@ void SyncProgressDialogImpl::processHasFinished(SyncResult resultId, const Error case ProcessCallback::PHASE_COMPARING_CONTENT: case ProcessCallback::PHASE_SYNCHRONIZING: { - auto objectsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase()); - auto objectsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase()); - auto dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase()); - auto dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase()); + const int itemsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase()); + const int itemsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase()); + const Int64 dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase()); + const Int64 dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase()); assert(dataCurrent <= dataTotal); //set overall speed (instead of current speed) - auto getOverallBytesPerSecond = [&]() -> wxString - { - const long timeDelta = timeElapsed.Time() - phaseStartMs; //we need to consider "time within current phase" not total "timeElapsed"! - if (timeDelta != 0) - return filesizeToShortString(dataCurrent * 1000 / timeDelta) + _("/sec"); - return L"-"; //fallback - }; + const long timeDelta = timeElapsed.Time() - phaseStartMs; //we need to consider "time within current phase" not total "timeElapsed"! + + const wxString overallBytesPerSecond = timeDelta == 0 ? wxString() : filesizeToShortString(dataCurrent * 1000 / timeDelta) + _("/sec"); + const wxString overallItemsPerSecond = timeDelta == 0 ? wxString() : replaceCpy(_("%x items"), L"%x", formatThreeDigitPrecision(itemsCurrent * 1000.0 / timeDelta)) + _("/sec"); - m_staticTextSpeed->SetLabel(getOverallBytesPerSecond()); + pnl.m_panelGraphBytes->setAttributes(pnl.m_panelGraphBytes->getAttributes().setCornerText(overallBytesPerSecond, Graph2D::CORNER_TOP_LEFT)); + pnl.m_panelGraphItems->setAttributes(pnl.m_panelGraphItems->getAttributes().setCornerText(overallItemsPerSecond, Graph2D::CORNER_TOP_LEFT)); //show new element "items processed" - m_staticTextLabelItemsProc->Show(true); - bSizerItemsProc ->Show(true); - m_staticTextProcessedObj ->SetLabel(toGuiString(objectsCurrent)); - m_staticTextDataProcessed->SetLabel(L"(" + filesizeToShortString(dataCurrent) + L")"); + pnl.m_panelItemsProcessed->Show(); + pnl.m_staticTextProcessedObj ->SetLabel(toGuiString(itemsCurrent)); + pnl.m_staticTextDataProcessed->SetLabel(L"(" + filesizeToShortString(dataCurrent) + L")"); //hide remaining elements... - if (objectsCurrent == objectsTotal && //...if everything was processed successfully - dataCurrent == dataTotal) - { - m_staticTextLabelItemsRem->Show(false); - bSizerItemsRem ->Show(false); - } + if (itemsCurrent == itemsTotal && //...if everything was processed successfully + dataCurrent == dataTotal) + pnl.m_panelItemsRemaining->Hide(); } break; } @@ -1576,62 +1804,64 @@ void SyncProgressDialogImpl::processHasFinished(SyncResult resultId, const Error resumeFromSystray(); //if in tray mode... - EnableCloseButton(true); + this->EnableCloseButton(true); - m_buttonCancel->Disable(); - m_buttonCancel->Hide(); - m_buttonPause->Disable(); - m_buttonPause->Hide(); - m_buttonClose->Show(); - m_buttonClose->Enable(); + pnl.m_bpButtonMinimizeToTray->Hide(); + pnl.m_buttonCancel->Disable(); + pnl.m_buttonCancel->Hide(); + pnl.m_buttonPause->Disable(); + pnl.m_buttonPause->Hide(); + pnl.m_buttonClose->Show(); + pnl.m_buttonClose->Enable(); - bSizerExecFinished->Show(false); + pnl.m_buttonClose->SetFocus(); - //set std order after button visibility was set - setStandardButtonOrder(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonClose)); - - if (IsShown()) //don't steal focus when residing in sys-tray! - m_buttonClose->SetFocus(); + pnl.bSizerExecFinished->Show(false); - //m_animCtrlSyncing->Stop(); - //m_animCtrlSyncing->Hide(); + //set std order after button visibility was set + setStandardButtonOrder(*pnl.bSizerStdButtons, StdButtons().setAffirmative(pnl.m_buttonClose)); //hide current operation status - m_staticTextStatus->Hide(); + pnl.bSizerStatusText->Show(false); - //show and prepare final statistics - m_notebookResult->Show(); + //show and prepare final statistics + pnl.m_notebookResult->Show(); #if defined ZEN_WIN || defined ZEN_LINUX - m_staticlineFooter->Hide(); //win: m_notebookResult already has a window frame + pnl.m_staticlineFooter->Hide(); //win: m_notebookResult already has a window frame #endif - //show total time - m_staticTextLabelElapsedTime->SetLabel(_("Total time:")); //it's not "elapsed time" anymore - //hide remaining time - m_staticTextLabelRemTime->Show(false); - m_staticTextRemTime ->Show(false); + pnl.m_panelTimeRemaining->Hide(); //1. re-arrange graph into results listbook - bSizerRoot->Detach(m_panelProgress); - m_panelProgress->Reparent(m_notebookResult); + pnl.bSizerRoot->Detach(pnl.m_panelProgress); + pnl.m_panelProgress->Reparent(pnl.m_notebookResult); #ifdef ZEN_LINUX //does not seem to be required on Win or OS X wxTheApp->Yield(); //wxGTK 2.9.3 fails miserably at "reparent" whithout this #endif - m_notebookResult->AddPage(m_panelProgress, _("Statistics"), true); //AddPage() takes ownership! + pnl.m_notebookResult->AddPage(pnl.m_panelProgress, _("Statistics"), true); //AddPage() takes ownership! //2. log file const size_t posLog = 1; - LogPanel* logPanel = new LogPanel(m_notebookResult, log); //owned by m_notebookResult - m_notebookResult->AddPage(logPanel, _("Logging"), false); + LogPanel* logPanel = new LogPanel(pnl.m_notebookResult, log); //owned by m_notebookResult + pnl.m_notebookResult->AddPage(logPanel, _("Log"), false); //bSizerHoldStretch->Insert(0, logPanel, 1, wxEXPAND); //show log instead of graph if errors occurred! (not required for ignored warnings) if (log.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR) > 0) - m_notebookResult->ChangeSelection(posLog); + pnl.m_notebookResult->ChangeSelection(posLog); + + //this->Fit(); //not a good idea: will shrink even if window is maximized or was enlarged by the user + pnl.Layout(); + + pnl.m_panelProgress->Layout(); + //small statistics panels: + pnl.m_panelItemsProcessed->Layout(); + pnl.m_panelItemsRemaining->Layout(); + //pnl.m_panelTimeRemaining->Layout(); + //pnl.m_panelTimeElapsed->Layout(); -> needed? - Layout(); //play (optional) sound notification after sync has completed -> only play when waiting on results dialog, seems to be pointless otherwise! switch (finalResult) { @@ -1648,19 +1878,19 @@ void SyncProgressDialogImpl::processHasFinished(SyncResult resultId, const Error break; } - //Raise(); -> don't! user may be watching a movie in the meantime ;) - warn_static("was ist mit resumeFromSystray:: Raise()??") + //Raise(); -> don't! user may be watching a movie in the meantime ;) note: resumeFromSystray() also calls Raise()! } -void SyncProgressDialogImpl::OnOkay(wxCommandEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnOkay(wxCommandEvent& event) { - isZombie = true; //on Fedora an iconize event is issued *before* entering SyncProgressDialogImpl::OnClose()!!! - Close(); //generate close event: do NOT destroy window unconditionally! + this->Close(); //generate close event: do NOT destroy window unconditionally! } -void SyncProgressDialogImpl::OnCancel(wxCommandEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnCancel(wxCommandEvent& event) { paused_ = false; updateDialogStatus(); //update status + pause button @@ -1671,14 +1901,16 @@ void SyncProgressDialogImpl::OnCancel(wxCommandEvent& event) } -void SyncProgressDialogImpl::OnPause(wxCommandEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnPause(wxCommandEvent& event) { paused_ = !paused_; updateDialogStatus(); //update status + pause button } -void SyncProgressDialogImpl::OnClose(wxCloseEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnClose(wxCloseEvent& event) { //this event handler may be called *during* sync, e.g. due to a system shutdown (Windows), anytime (OS X) //try to stop sync gracefully and cross fingers: @@ -1695,68 +1927,86 @@ void SyncProgressDialogImpl::OnClose(wxCloseEvent& event) syncStat_ = nullptr; abortCb_ = nullptr; - isZombie = true; //it "lives" until cleanup in next idle event - Destroy(); -} - - -void SyncProgressDialogImpl::OnIconize(wxIconizeEvent& event) -{ - if (isZombie) return; //wxGTK sends iconize event *after* wxWindow::Destroy, sigh... - - if (event.IsIconized()) //ATTENTION: iconize event is also triggered on "Restore"! (at least under Linux) - minimizeToTray(); - else - resumeFromSystray(); //may be initiated by "show desktop" although all windows are hidden! + wereDead = true; + this->Destroy(); //wxWidgets OS X: simple "delete"!!!!!!! } -void SyncProgressDialogImpl::OnResumeFromTray(wxCommandEvent& event) +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::OnIconize(wxIconizeEvent& event) { - resumeFromSystray(); + /* + propagate progress dialog minimize/maximize to parent + ----------------------------------------------------- + Fedora/Debian/Ubuntu: + - wxDialog cannot be minimized + - worse, wxGTK sends stray iconize events *after* wxDialog::Destroy() + - worse, on Fedora an iconize event is issued directly after calling Close() + - worse, even wxDialog::Hide() causes iconize event! + => nothing to do + SUSE: + - wxDialog can be minimized (it just vanishes!) and in general also minimizes parent: except for our progress wxDialog!!! + - worse, wxDialog::Hide() causes iconize event + - probably the same issues with stray iconize events like Fedora/Debian/Ubuntu + - minimize button is always shown, even if wxMINIMIZE_BOX is omitted! + => nothing to do + Mac OS X: + - wxDialog can be minimized and automatically minimizes parent + - no iconize events seen by wxWidgets! + => nothing to do + Windows: + - wxDialog can be minimized but does not also minimize parent + - iconize events only seen for manual minimize + => propagate event to parent + */ +#ifdef ZEN_WIN + if (parentFrame_) + if (parentFrame_->IsIconized() != event.IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! + parentFrame_->Iconize(event.IsIconized()); +#endif + event.Skip(); } -void SyncProgressDialogImpl::minimizeToTray() +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::minimizeToTray() { -// wxMessageBox(L"hi"); - if (!trayIcon.get()) { - trayIcon = make_unique<FfsTrayIcon>(); - trayIcon->Connect(FFS_REQUEST_RESUME_TRAY_EVENT, wxCommandEventHandler(SyncProgressDialogImpl::OnResumeFromTray), nullptr, this); - //tray icon has shorter lifetime than this => no need to disconnect event later + trayIcon = make_unique<FfsTrayIcon>([this] { this->resumeFromSystray(); }); //FfsTrayIcon lifetime is a subset of "this"'s lifetime! + //we may destroy FfsTrayIcon even while in the FfsTrayIcon callback!!!! updateGuiInt(false); //set tray tooltip + progress: e.g. no updates while paused - Hide(); - if (mainDialog) - mainDialog->Hide(); + this->Hide(); + if (parentFrame_) + parentFrame_->Hide(); } } -void SyncProgressDialogImpl::resumeFromSystray() +template <class TopLevelDialog> +void SyncProgressDialogImpl<TopLevelDialog>::resumeFromSystray() { if (trayIcon) { trayIcon.reset(); - if (mainDialog) + if (parentFrame_) { - if (mainDialog->IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! - mainDialog->Iconize(false); - mainDialog->Show(); - mainDialog->Raise(); + //if (parentFrame_->IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! + // parentFrame_->Iconize(false); + parentFrame_->Show(); + parentFrame_->Raise(); } - if (IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! - Iconize(false); - Show(); - Raise(); - SetFocus(); + //if (IsIconized()) //caveat: if window is maximized calling Iconize(false) will erroneously un-maximize! + // Iconize(false); + this->Show(); + this->Raise(); + this->SetFocus(); - updateDialogStatus(); //restore Windows 7 task bar status (e.g. required in pause mode) + updateDialogStatus(); //restore Windows 7 task bar status (e.g. required in pause mode) updateGuiInt(false); //restore Windows 7 task bar progress (e.g. required in pause mode) } } @@ -1766,11 +2016,18 @@ void SyncProgressDialogImpl::resumeFromSystray() SyncProgressDialog* createProgressDialog(zen::AbortCallback& abortCb, const std::function<void()>& notifyWindowTerminate, //note: user closing window cannot be prevented on OS X! (And neither on Windows during system shutdown!) const zen::Statistics& syncStat, - wxTopLevelWindow* parentWindow, //may be nullptr + wxFrame* parentWindow, //may be nullptr bool showProgress, const wxString& jobName, const std::wstring& execWhenFinished, std::vector<std::wstring>& execFinishedHistory) { - return new SyncProgressDialogImpl(abortCb, notifyWindowTerminate, syncStat, parentWindow, showProgress, jobName, execWhenFinished, execFinishedHistory); + if (parentWindow) //sync from GUI + return new SyncProgressDialogImpl<wxDialog>(wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxRESIZE_BORDER, + [&](wxDialog& progDlg) { return parentWindow; }, abortCb, + notifyWindowTerminate, syncStat, parentWindow, showProgress, jobName, execWhenFinished, execFinishedHistory); + else //FFS batch job + return new SyncProgressDialogImpl<wxFrame>(wxDEFAULT_FRAME_STYLE, + [](wxFrame& progDlg) { return &progDlg; }, abortCb, + notifyWindowTerminate, syncStat, parentWindow, showProgress, jobName, execWhenFinished, execFinishedHistory); } diff --git a/ui/progress_indicator.h b/ui/progress_indicator.h index 0789ca80..e2dbb99c 100644 --- a/ui/progress_indicator.h +++ b/ui/progress_indicator.h @@ -10,7 +10,7 @@ #include <functional> #include <zen/error_log.h> //#include <zen/zstring.h> -#include <wx/toplevel.h> +#include <wx/frame.h> #include "../lib/status_handler.h" //#include "main_dlg.h" @@ -18,7 +18,7 @@ class CompareProgressDialog { public: - CompareProgressDialog(wxTopLevelWindow& parentWindow); //CompareProgressDialog will be owned by parentWindow! + CompareProgressDialog(wxFrame& parentWindow); //CompareProgressDialog will be owned by parentWindow! wxWindow* getAsWindow(); //convenience! don't abuse! @@ -52,7 +52,7 @@ struct SyncProgressDialog //--------------------------------------------------------------------------- - virtual wxWindow* getAsWindow() = 0; //convenience! don't abuse! + virtual wxWindow* getWindowIfVisible() = 0; //may be nullptr; don't abuse, use as parent for modal dialogs only! virtual void initNewPhase() = 0; //call after "StatusHandler::initNewPhase" virtual void notifyProgressChange() = 0; //throw (), required by graph! @@ -71,7 +71,7 @@ protected: SyncProgressDialog* createProgressDialog(zen::AbortCallback& abortCb, const std::function<void()>& notifyWindowTerminate, //note: user closing window cannot be prevented on OS X! (And neither on Windows during system shutdown!) const zen::Statistics& syncStat, - wxTopLevelWindow* parentWindow, //may be nullptr + wxFrame* parentWindow, //may be nullptr bool showProgress, const wxString& jobName, const std::wstring& execWhenFinished, diff --git a/ui/small_dlgs.cpp b/ui/small_dlgs.cpp index 304e4269..b7b7828b 100644 --- a/ui/small_dlgs.cpp +++ b/ui/small_dlgs.cpp @@ -384,10 +384,9 @@ void DeleteDialog::updateGui() { wxWindowUpdateLocker dummy(this); //avoid display distortion - const std::pair<Zstring, int> delInfo = zen::deleteFromGridAndHDPreview( - rowsToDeleteOnLeft, - rowsToDeleteOnRight, - m_checkBoxDeleteBothSides->GetValue()); + const std::pair<Zstring, int> delInfo = zen::deleteFromGridAndHDPreview(rowsToDeleteOnLeft, + rowsToDeleteOnRight, + m_checkBoxDeleteBothSides->GetValue()); wxString header; if (m_checkBoxUseRecycler->GetValue()) { @@ -406,7 +405,13 @@ void DeleteDialog::updateGui() const wxString& fileList = utfCvrtTo<wxString>(delInfo.first); m_textCtrlFileList->ChangeValue(fileList); - + /* + There is a nasty bug on wxGTK under Ubuntu: If a multi-line wxTextCtrl contains so many lines that scrollbars are shown, + it re-enables all windows that are supposed to be disabled during the current modal loop! + This only affects Ubuntu/wxGTK! No such issue on Debian/wxGTK or Suse/wxGTK + => another Unity problem like the following? + http://trac.wxwidgets.org/ticket/14823 "Menu not disabled when showing modal dialogs in wxGTK under Unity" + */ Layout(); } diff --git a/ui/switch_to_gui.h b/ui/switch_to_gui.h index a3cf6827..20fe81de 100644 --- a/ui/switch_to_gui.h +++ b/ui/switch_to_gui.h @@ -27,7 +27,7 @@ public: void execute() const { - MainDialog::create(guiCfg, referenceFiles, globalSettings_, true); //new toplevel window + MainDialog::create(guiCfg, referenceFiles, &globalSettings_, true); //new toplevel window } private: diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp index 806914a3..97518be1 100644 --- a/ui/sync_cfg.cpp +++ b/ui/sync_cfg.cpp @@ -107,15 +107,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.exLeftSideOnly) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonLeftOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_create_right"))); buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_CREATE_NEW_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonLeftOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_delete_left"))); buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_DELETE_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonLeftOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_none"))); buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; @@ -123,15 +123,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.exRightSideOnly) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonRightOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_delete_right"))); buttonRightOnly->SetToolTip(getSyncOpDescription(SO_DELETE_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonRightOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_create_left"))); buttonRightOnly->SetToolTip(getSyncOpDescription(SO_CREATE_NEW_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonRightOnly->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_none"))); buttonRightOnly->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; @@ -139,15 +139,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.leftNewer) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonLeftNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_right"))); buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonLeftNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_left"))); buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonLeftNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_none"))); buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; @@ -155,15 +155,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.rightNewer) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonRightNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_right"))); buttonRightNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonRightNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_left"))); buttonRightNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonRightNewer->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_none"))); buttonRightNewer->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; @@ -171,15 +171,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.different) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonDifferent->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_right"))); buttonDifferent->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonDifferent->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_left"))); buttonDifferent->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonDifferent->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_none"))); buttonDifferent->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; @@ -187,15 +187,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, switch (dirCfg.conflict) { - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: buttonConflict->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_right"))); buttonConflict->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: buttonConflict->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"so_update_left"))); buttonConflict->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; - case SYNC_DIR_NONE: + case SyncDirection::NONE: buttonConflict->SetBitmapLabel(mirrorIfRtl(getResourceImage(L"cat_conflict"))); //silent dependency to algorithm.cpp::Redetermine!!! buttonConflict->SetToolTip(_("Leave as unresolved conflict")); break; @@ -495,14 +495,14 @@ void toggleSyncDirection(SyncDirection& current) { switch (current) { - case SYNC_DIR_RIGHT: - current = SYNC_DIR_LEFT; + case SyncDirection::RIGHT: + current = SyncDirection::LEFT; break; - case SYNC_DIR_LEFT: - current = SYNC_DIR_NONE; + case SyncDirection::LEFT: + current = SyncDirection::NONE; break; - case SYNC_DIR_NONE: - current = SYNC_DIR_RIGHT; + case SyncDirection::NONE: + current = SyncDirection::RIGHT; break; } } diff --git a/ui/taskbar.cpp b/ui/taskbar.cpp index 0e019d04..e6aadc90 100644 --- a/ui/taskbar.cpp +++ b/ui/taskbar.cpp @@ -30,7 +30,7 @@ using namespace tbseven; class Taskbar::Pimpl //throw TaskbarNotAvailable { public: - Pimpl(const wxTopLevelWindow& window) : + Pimpl(const wxFrame& window) : assocWindow(window.GetHWND()), setStatus_ (getDllName(), funName_setStatus), setProgress_(getDllName(), funName_setProgress) @@ -86,7 +86,7 @@ const char FFS_DESKTOP_FILE[] = "freefilesync.desktop"; class Taskbar::Pimpl //throw (TaskbarNotAvailable) { public: - Pimpl(const wxTopLevelWindow& window) : + Pimpl(const wxFrame& window) : tbEntry(unity_launcher_entry_get_for_desktop_id(FFS_DESKTOP_FILE)) //tbEntry(unity_launcher_entry_get_for_app_uri("application://freefilesync.desktop")) { @@ -133,7 +133,7 @@ private: class Taskbar::Pimpl { public: - Pimpl(const wxTopLevelWindow& window) {} + Pimpl(const wxFrame& window) {} ~Pimpl() { setDockText(""); } @@ -161,7 +161,7 @@ private: class Taskbar::Pimpl { public: - Pimpl(const wxTopLevelWindow& window) { throw TaskbarNotAvailable(); } + Pimpl(const wxFrame& window) { throw TaskbarNotAvailable(); } void setStatus(Status status) {} void setProgress(double fraction) {} }; @@ -169,7 +169,7 @@ public: //######################################################################################################## -Taskbar::Taskbar(const wxTopLevelWindow& window) : pimpl_(new Pimpl(window)) {} //throw TaskbarNotAvailable +Taskbar::Taskbar(const wxFrame& window) : pimpl_(new Pimpl(window)) {} //throw TaskbarNotAvailable Taskbar::~Taskbar() {} void Taskbar::setStatus(Status status) { pimpl_->setStatus(status); } diff --git a/ui/taskbar.h b/ui/taskbar.h index ad708794..82e08656 100644 --- a/ui/taskbar.h +++ b/ui/taskbar.h @@ -8,7 +8,7 @@ #define TASKBARPROGRESS_H_INCLUDED #include <memory> -#include <wx/toplevel.h> +#include <wx/frame.h> /* Windows 7; show progress in windows superbar via ITaskbarList3 Interface: http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx @@ -27,7 +27,7 @@ class TaskbarNotAvailable {}; class Taskbar { public: - Taskbar(const wxTopLevelWindow& window); //throw TaskbarNotAvailable() + Taskbar(const wxFrame& window); //throw TaskbarNotAvailable ~Taskbar(); enum Status diff --git a/ui/tray_icon.cpp b/ui/tray_icon.cpp index 6a9c640c..3826458f 100644 --- a/ui/tray_icon.cpp +++ b/ui/tray_icon.cpp @@ -14,8 +14,6 @@ #include "../lib/resources.h" -const wxEventType FFS_REQUEST_RESUME_TRAY_EVENT = wxNewEventType(); - namespace { void fillRange(wxImage& img, int pixelFirst, int pixelLast, const wxColor& col) //tolerant input range @@ -52,90 +50,56 @@ void fillRange(wxImage& img, int pixelFirst, int pixelLast, const wxColor& col) wxIcon generateProgressIcon(const wxImage& logo, double fraction) //generate icon with progress indicator { - if (!logo.IsOk()) + if (!logo.IsOk() || logo.GetWidth() <= 0 || logo.GetHeight() <= 0) return wxIcon(); const int pixelCount = logo.GetWidth() * logo.GetHeight(); - const int startFillPixel = std::min(numeric::round(fraction * pixelCount), pixelCount); + const int startFillPixel = numeric::confineCpy(numeric::round(fraction * pixelCount), 0, pixelCount); //minor optimization static std::pair<int, wxIcon> buffer = std::make_pair(-1, wxNullIcon); if (buffer.first != startFillPixel) { - //progress bar - if (logo.GetWidth() > 0 && - logo.GetHeight() > 0) - { - wxImage genImage(logo.Copy()); //workaround wxWidgets' screwed-up design from hell: their copy-construction implements reference-counting WITHOUT copy-on-write! - - //gradually make FFS icon brighter while nearing completion - zen::brighten(genImage, -200 * (1 - fraction)); - - //fill black border row - if (startFillPixel <= pixelCount - genImage.GetWidth()) - { - /* - -------- - ---bbbbb - bbbbSyyy S : start yellow remainder - yyyyyyyy - */ - int bStart = startFillPixel - genImage.GetWidth(); - if (bStart % genImage.GetWidth() != 0) //add one more black pixel, see ascii-art - --bStart; - fillRange(genImage, bStart, startFillPixel, *wxBLACK); - } - else if (startFillPixel < pixelCount) - { - //special handling for last row - /* - -------- - -------- - ---bbbbb - ---bSyyy S : start yellow remainder - */ - int bStart = startFillPixel - genImage.GetWidth() - 1; - int bEnd = (bStart / genImage.GetWidth() + 1) * genImage.GetWidth(); - - fillRange(genImage, bStart, bEnd, *wxBLACK); - fillRange(genImage, startFillPixel - 1, startFillPixel, *wxBLACK); - } + wxImage genImage(logo.Copy()); //workaround wxWidgets' screwed-up design from hell: their copy-construction implements reference-counting WITHOUT copy-on-write! - //fill yellow remainder - fillRange(genImage, startFillPixel, pixelCount, wxColour(240, 200, 0)); + //gradually make FFS icon brighter while nearing completion + zen::brighten(genImage, -200 * (1 - fraction)); + //fill black border row + if (startFillPixel <= pixelCount - genImage.GetWidth()) + { /* - const int indicatorWidth = genImage.GetWidth() * .4; - const int indicatorXBegin = std::ceil((genImage.GetWidth() - indicatorWidth) / 2.0); - const int indicatorYBegin = genImage.GetHeight() - indicatorHeight; - - //draw progress indicator: do NOT use wxDC::DrawRectangle! Doesn't respect alpha in Windows, but does in Linux! - //We need a simple, working solution: - - for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row) - { - for (int col = indicatorXBegin; col < indicatorXBegin + indicatorWidth; ++col) - { - unsigned char* const pixelBegin = data + (row * genImage.GetWidth() + col) * 3; - pixelBegin[0] = 240; //red - pixelBegin[1] = 200; //green - pixelBegin[2] = 0; //blue - } - } - - if (genImage.HasAlpha()) - { - unsigned char* const alpha = genImage.GetAlpha(); - //make progress indicator fully opaque: - for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row) - ::memset(alpha + row * genImage.GetWidth() + indicatorXBegin, wxIMAGE_ALPHA_OPAQUE, indicatorWidth); - } + -------- + ---bbbbb + bbbbSyyy S : start yellow remainder + yyyyyyyy */ - buffer.second.CopyFromBitmap(wxBitmap(genImage)); + int bStart = startFillPixel - genImage.GetWidth(); + if (bStart % genImage.GetWidth() != 0) //add one more black pixel, see ascii-art + --bStart; + fillRange(genImage, bStart, startFillPixel, *wxBLACK); + } + else if (startFillPixel < pixelCount) + { + //special handling for last row + /* + -------- + -------- + ---bbbbb + ---bSyyy S : start yellow remainder + */ + int bStart = startFillPixel - genImage.GetWidth() - 1; + int bEnd = (bStart / genImage.GetWidth() + 1) * genImage.GetWidth(); + + fillRange(genImage, bStart, bEnd, *wxBLACK); + fillRange(genImage, startFillPixel - 1, startFillPixel, *wxBLACK); } - else - buffer.second = wxIcon(); + + //fill yellow remainder + fillRange(genImage, startFillPixel, pixelCount, wxColour(240, 200, 0)); + + buffer.second.CopyFromBitmap(wxBitmap(genImage)); } return buffer.second; @@ -145,7 +109,7 @@ wxIcon generateProgressIcon(const wxImage& logo, double fraction) //generate ico enum Selection { - CONTEXT_RESTORE = 1, //wxWidgets: "A MenuItem ID of Zero does not work under Mac" + CONTEXT_RESTORE = 1, //wxWidgets: "A MenuItem ID of zero does not work under Mac" CONTEXT_ABOUT = wxID_ABOUT }; } @@ -154,95 +118,107 @@ enum Selection class FfsTrayIcon::TaskBarImpl : public wxTaskBarIcon { public: - TaskBarImpl(FfsTrayIcon& parent) : parent_(&parent) {} + TaskBarImpl(const std::function<void()>& onRequestResume) : onRequestResume_(onRequestResume) + { + Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TaskBarImpl::OnDoubleClick), nullptr, this); //register double-click + } - void parentHasDied() { parent_ = nullptr; } + //virtual ~TaskBarImpl(){} + + void dontCallbackAnymore() { onRequestResume_ = nullptr; } private: virtual wxMenu* CreatePopupMenu() { - if (!parent_) + if (!onRequestResume_) return nullptr; wxMenu* contextMenu = new wxMenu; - contextMenu->Append(CONTEXT_ABOUT, _("&About")); - contextMenu->AppendSeparator(); contextMenu->Append(CONTEXT_RESTORE, _("&Restore")); + contextMenu->AppendSeparator(); + contextMenu->Append(CONTEXT_ABOUT, _("&About")); //event handling - contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(FfsTrayIcon::OnContextMenuSelection), nullptr, parent_); + contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TaskBarImpl::OnContextMenuSelection), nullptr, this); return contextMenu; //ownership transferred to caller } - FfsTrayIcon* parent_; + void OnContextMenuSelection(wxCommandEvent& event) + { + switch (static_cast<Selection>(event.GetId())) + { + case CONTEXT_ABOUT: + { + //ATTENTION: the modal dialog below does NOT disable all GUI input, e.g. user may still double-click on tray icon + //which will implicitly destroy the tray icon while still showing the modal dialog + SetEvtHandlerEnabled(false); + ZEN_ON_SCOPE_EXIT(SetEvtHandlerEnabled(true)); + + zen::showAboutDialog(nullptr); + } + break; + + case CONTEXT_RESTORE: + if (onRequestResume_) + onRequestResume_(); + break; + } + } + + void OnDoubleClick(wxCommandEvent& event) + { + if (onRequestResume_) + onRequestResume_(); + } + + std::function<void()> onRequestResume_; }; -FfsTrayIcon::FfsTrayIcon() : - trayIcon(new TaskBarImpl(*this)), - fractionLast(1), //show FFS logo by default +FfsTrayIcon::FfsTrayIcon(const std::function<void()>& onRequestResume) : + trayIcon(new TaskBarImpl(onRequestResume)), + activeFraction(1), //show FFS logo by default #if defined ZEN_WIN || defined ZEN_MAC //16x16 seems to be the only size that is shown correctly on OS X logo(getResourceImage(L"FFS_tray_16x16").ConvertToImage()) #elif defined ZEN_LINUX logo(getResourceImage(L"FFS_tray_24x24").ConvertToImage()) #endif { - trayIcon->SetIcon(generateProgressIcon(logo, fractionLast), L"FreeFileSync"); - trayIcon->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(FfsTrayIcon::OnDoubleClick), nullptr, this); //register double-click + trayIcon->SetIcon(generateProgressIcon(logo, activeFraction), L"FreeFileSync"); } FfsTrayIcon::~FfsTrayIcon() { - trayIcon->RemoveIcon(); //hide icon until final deletion takes place - trayIcon->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(FfsTrayIcon::OnDoubleClick), nullptr, this); - trayIcon->parentHasDied(); //TaskBarImpl (potentially) has longer lifetime than FfsTrayIcon: avoid callback! - - //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking) - if (!wxPendingDelete.Member(trayIcon)) - wxPendingDelete.Append(trayIcon); -} + trayIcon->dontCallbackAnymore(); //TaskBarImpl has longer lifetime than FfsTrayIcon: avoid callback! + /* + This is not working correctly on OS X! It seems both wxTaskBarIcon::RemoveIcon() and ~wxTaskBarIcon() are broken and do NOT immediately + remove the icon from the system tray! Only some time later in the event loop which called these functions they will be removed. + Maybe some system component has still shared ownership? Objective C auto release pools are freed at the end of the current event loop... + Anyway, wxWidgets fails to disconnect the wxTaskBarIcon event handlers before calling "[m_statusitem release]"! -void FfsTrayIcon::setToolTip(const wxString& toolTip) -{ - toolTipLast = toolTip; - trayIcon->SetIcon(generateProgressIcon(logo, fractionLast), toolTip); //another wxWidgets design bug: non-orthogonal method! -} + => !!!clicking on the icon after ~wxTaskBarIcon ran crashes the application!!! + - if ~wxTaskBarIcon() ran from the SyncProgressDialog::updateGui() event loop (e.g. user manually clicking the icon) => icon removed on return + - if ~wxTaskBarIcon() ran from SyncProgressDialog::closeWindowDirectly() => leaves the icon dangling until user closes this dialog and outter event loop runs! + */ -void FfsTrayIcon::setProgress(double fraction) -{ - fractionLast = fraction; - trayIcon->SetIcon(generateProgressIcon(logo, fraction), toolTipLast); + trayIcon->RemoveIcon(); //required on Windows: unlike on OS X, wxPendingDelete does not kick in before main event loop! + //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking) + wxPendingDelete.Append(trayIcon); } -void FfsTrayIcon::OnContextMenuSelection(wxCommandEvent& event) +void FfsTrayIcon::setToolTip(const wxString& toolTip) { - switch (static_cast<Selection>(event.GetId())) - { - case CONTEXT_ABOUT: - { - //ATTENTION: the modal dialog below does NOT disable all GUI input, e.g. user may still double-click on tray icon - //which will implicitly destroy the tray icon while still showing the modal dialog - trayIcon->SetEvtHandlerEnabled(false); - zen::showAboutDialog(nullptr); - trayIcon->SetEvtHandlerEnabled(true); - } - break; - case CONTEXT_RESTORE: - { - wxCommandEvent dummy(FFS_REQUEST_RESUME_TRAY_EVENT); - ProcessEvent(dummy); - } - } + activeToolTip = toolTip; + trayIcon->SetIcon(generateProgressIcon(logo, activeFraction), activeToolTip); //another wxWidgets design bug: non-orthogonal method! } -void FfsTrayIcon::OnDoubleClick(wxCommandEvent& event) +void FfsTrayIcon::setProgress(double fraction) { - wxCommandEvent dummy(FFS_REQUEST_RESUME_TRAY_EVENT); - ProcessEvent(dummy); + activeFraction = fraction; + trayIcon->SetIcon(generateProgressIcon(logo, activeFraction), activeToolTip); } - diff --git a/ui/tray_icon.h b/ui/tray_icon.h index 866d79d5..24c97eb0 100644 --- a/ui/tray_icon.h +++ b/ui/tray_icon.h @@ -4,38 +4,42 @@ // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** -#ifndef TRAYICON_H_INCLUDED -#define TRAYICON_H_INCLUDED +#ifndef TRAYICON_H_84217830427534285 +#define TRAYICON_H_84217830427534285 -#include <wx/event.h> +#include <functional> #include <wx/image.h> -//show tray icon with progress during lifetime of this instance -//emits the following wxCommandEvent in case user double-clicks on tray icon or selects corresponding context menu item: -extern const wxEventType FFS_REQUEST_RESUME_TRAY_EVENT; +/* +show tray icon with progress during lifetime of this instance -class FfsTrayIcon : public wxEvtHandler +ATTENTION: wxWidgets never assumes that an object indirectly destroys itself while processing an event! + this includes wxEvtHandler-derived objects!!! + it seems ProcessEvent() works (on Windows), but AddPendingEvent() will crash since it uses "this" after the event processing! + +=> don't derive from wxEvtHandler or any other wxWidgets object here!!!!!! +=> use simple std::function as callback instead => instance may now be safely deleted in callback! +*/ + +class FfsTrayIcon { public: - FfsTrayIcon(); + FfsTrayIcon(const std::function<void()>& onRequestResume); //callback only held during lifetime of this instance ~FfsTrayIcon(); void setToolTip(const wxString& toolTip); void setProgress(double fraction); //number between [0, 1], for small progress indicator private: - FfsTrayIcon(const FfsTrayIcon&); - FfsTrayIcon& operator=(const FfsTrayIcon&); - - void OnContextMenuSelection(wxCommandEvent& event); - void OnDoubleClick(wxCommandEvent& event); + FfsTrayIcon(const FfsTrayIcon&); //=delete + FfsTrayIcon& operator=(const FfsTrayIcon&); //=delete class TaskBarImpl; - TaskBarImpl* trayIcon; //actual tray icon (don't use inheritance to enable delayed deletion) + TaskBarImpl* trayIcon; - wxString toolTipLast; - double fractionLast; + wxString activeToolTip; + double activeFraction; wxImage logo; }; -#endif // TRAYICON_H_INCLUDED +#endif //TRAYICON_H_84217830427534285 diff --git a/ui/tree_view.cpp b/ui/tree_view.cpp index 10037380..791fa6cc 100644 --- a/ui/tree_view.cpp +++ b/ui/tree_view.cpp @@ -46,11 +46,11 @@ void TreeView::extractVisibleSubtree(HierarchyObject& hierObj, //in if (fileObj.isActive()) switch (fileObj.getSyncDir()) { - case SYNC_DIR_LEFT: + case SyncDirection::LEFT: return fileObj.getFileSize<RIGHT_SIDE>(); - case SYNC_DIR_RIGHT: + case SyncDirection::RIGHT: return fileObj.getFileSize<LEFT_SIDE>(); - case SYNC_DIR_NONE: + case SyncDirection::NONE: break; } return std::max(fileObj.getFileSize<LEFT_SIDE>(), fileObj.getFileSize<RIGHT_SIDE>()); |