summaryrefslogtreecommitdiff
path: root/RealtimeSync/main_dlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'RealtimeSync/main_dlg.cpp')
-rw-r--r--RealtimeSync/main_dlg.cpp534
1 files changed, 0 insertions, 534 deletions
diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp
deleted file mode 100644
index f29f396b..00000000
--- a/RealtimeSync/main_dlg.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#include "main_dlg.h"
-#include <wx/wupdlock.h>
-#include <wx/filedlg.h>
-#include <wx+/bitmap_button.h>
-#include <wx+/string_conv.h>
-#include <wx+/mouse_move_dlg.h>
-#include <wx+/font_size.h>
-#include <wx+/popup_dlg.h>
-#include <wx+/image_resources.h>
-#include <zen/assert_static.h>
-#include <zen/file_handling.h>
-#include <zen/build_info.h>
-#include "xml_proc.h"
-#include "tray_menu.h"
-#include "xml_ffs.h"
-#include "app_icon.h"
-#include "../lib/help_provider.h"
-#include "../lib/process_xml.h"
-#include "../lib/ffs_paths.h"
-#ifdef ZEN_LINUX
-#include <gtk/gtk.h>
-#elif defined ZEN_MAC
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-using namespace zen;
-
-
-class DirectoryPanel : public FolderGenerated
-{
-public:
- DirectoryPanel(wxWindow* parent) :
- FolderGenerated(parent),
- dirName(*this, *m_buttonSelectDir, *m_txtCtrlDirectory)
- {
-#ifdef ZEN_LINUX
- //file drag and drop directly into the text control unhelpfully inserts in format "file://..<cr><nl>"; see folder_history_box.cpp
- if (GtkWidget* widget = m_txtCtrlDirectory->GetConnectWidget())
- ::gtk_drag_dest_unset(widget);
-#endif
- }
-
- void setName(const wxString& dirname) { dirName.setName(dirname); }
- wxString getName() const { return dirName.getName(); }
-
-private:
- zen::DirectoryName<wxTextCtrl> dirName;
-};
-
-
-void MainDialog::create(const Zstring& cfgFile)
-{
- /*MainDialog* frame = */ new MainDialog(nullptr, cfgFile);
-}
-
-
-MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
- : MainDlgGenerated(dlg)
-{
-#ifdef ZEN_WIN
- new MouseMoveWindow(*this); //ownership passed to "this"
- wxWindowUpdateLocker dummy(this); //leads to GUI corruption problems on Linux/OS X!
-#endif
-
-#ifdef ZEN_LINUX
- //file drag and drop directly into the text control unhelpfully inserts in format "file://..<cr><nl>"; see folder_history_box.cpp
- if (GtkWidget* widget = m_txtCtrlDirectoryMain->GetConnectWidget())
- ::gtk_drag_dest_unset(widget);
-#endif
-
- SetIcon(getRtsIcon()); //set application icon
-
- setRelativeFontSize(*m_buttonStart, 1.5);
-
- m_bpButtonRemoveTopFolder->Hide();
- m_panelMainFolder->Layout();
-
- m_bpButtonAddFolder ->SetBitmapLabel(getResourceImage(L"item_add"));
- m_bpButtonRemoveTopFolder->SetBitmapLabel(getResourceImage(L"item_remove"));
- setBitmapTextLabel(*m_buttonStart, getResourceImage(L"startRts").ConvertToImage(), m_buttonStart->GetLabel(), 5, 8);
-
-
- //register key event
- Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MainDialog::OnKeyPressed), nullptr, this);
-
- //prepare drag & drop
- dirNameFirst.reset(new DirectoryName<wxTextCtrl>(*m_panelMainFolder, *m_buttonSelectDirMain, *m_txtCtrlDirectoryMain, m_staticTextFinalPath));
-
- //--------------------------- load config values ------------------------------------
- xmlAccess::XmlRealConfig newConfig;
-
- const Zstring currentConfigFile = cfgFileName.empty() ? lastConfigFileName() : cfgFileName;
- bool loadCfgSuccess = false;
- if (!cfgFileName.empty() || fileExists(lastConfigFileName()))
- try
- {
- rts::readRealOrBatchConfig(currentConfigFile, newConfig); //throw FfsXmlError
- loadCfgSuccess = true;
- }
- catch (const xmlAccess::FfsXmlError& e)
- {
- if (e.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(e.toString()));
- else
- showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
- }
-
- const bool startWatchingImmediately = loadCfgSuccess && !cfgFileName.empty();
-
- setConfiguration(newConfig);
- setLastUsedConfig(currentConfigFile);
- //-----------------------------------------------------------------------------------------
-
- if (startWatchingImmediately) //start watch mode directly
- {
- wxCommandEvent dummy2(wxEVT_COMMAND_BUTTON_CLICKED);
- this->OnStart(dummy2);
- //don't Show()!
- }
- else
- {
- m_buttonStart->SetFocus(); //don't "steal" focus if program is running from sys-tray"
- Show();
-#ifdef ZEN_MAC
- ProcessSerialNumber psn = { 0, kCurrentProcess };
- ::SetFrontProcess(&psn); //call before TransformProcessType() so that OSX menu is updated correctly
- ::TransformProcessType(&psn, kProcessTransformToForegroundApplication); //show dock icon, even if we're not an application bundle
- //if the executable is not yet in a bundle or if it is called through a launcher, we need to set focus manually:
-#endif
- }
-
- //drag and drop .ffs_real and .ffs_batch on main dialog
- setupFileDrop(*m_panelMain);
- m_panelMain->Connect(EVENT_DROP_FILE, FileDropEventHandler(MainDialog::onFilesDropped), nullptr, this);
-
- timerForAsyncTasks.Connect(wxEVT_TIMER, wxEventHandler(MainDialog::onProcessAsyncTasks), nullptr, this);
-}
-
-
-MainDialog::~MainDialog()
-{
- //save current configuration
- const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
-
- try //write config to XML
- {
- writeRealConfig(currentCfg, lastConfigFileName()); //throw FfsXmlError
- }
- catch (const xmlAccess::FfsXmlError& e)
- {
- showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
- }
-}
-
-
-void MainDialog::onProcessAsyncTasks(wxEvent& event)
-{
- //schedule and run long-running tasks asynchronously
- asyncTasks.evalResults(); //process results on GUI queue
- if (asyncTasks.empty())
- timerForAsyncTasks.Stop();
-}
-
-
-const Zstring& MainDialog::lastConfigFileName()
-{
- static Zstring instance = zen::getConfigDir() + Zstr("LastRun.ffs_real");
- return instance;
-}
-
-
-void MainDialog::OnShowHelp(wxCommandEvent& event)
-{
- zen::displayHelpEntry(L"html/RealtimeSync.html", this);
-}
-
-
-void MainDialog::OnMenuAbout(wxCommandEvent& event)
-{
- //build information
- wxString build = __TDATE__;
-#if wxUSE_UNICODE
- build += L" - Unicode";
-#else
- build += L" - ANSI";
-#endif //wxUSE_UNICODE
-
- //compile time info about 32/64-bit build
- if (zen::is64BitBuild)
- build += L" x64";
- else
- build += L" x86";
- assert_static(zen::is32BitBuild || zen::is64BitBuild);
-
- showNotificationDialog(this, DialogInfoType::INFO, PopupDialogCfg().
- setTitle(_("About")).
- setMainInstructions(L"RealtimeSync" L"\n\n" + replaceCpy(_("Build: %x"), L"%x", build)));
-}
-
-
-void MainDialog::OnKeyPressed(wxKeyEvent& event)
-{
- const int keyCode = event.GetKeyCode();
- if (keyCode == WXK_ESCAPE)
- {
- Close();
- return;
- }
- event.Skip();
-}
-
-
-void MainDialog::OnStart(wxCommandEvent& event)
-{
- xmlAccess::XmlRealConfig currentCfg = getConfiguration();
-
- Hide();
-#ifdef ZEN_MAC
- //hide dock icon: else user is able to forcefully show the hidden main dialog by clicking on the icon!!
- ProcessSerialNumber psn = { 0, kCurrentProcess };
- ::TransformProcessType(&psn, kProcessTransformToUIElementApplication);
-#endif
-
- switch (rts::startDirectoryMonitor(currentCfg, xmlAccess::extractJobName(utfCvrtTo<Zstring>(currentConfigFileName))))
- {
- case rts::EXIT_APP:
- Close();
- return;
-
- case rts::SHOW_GUI:
- break;
- }
- Show(); //don't show for EXIT_APP
-#ifdef ZEN_MAC
- ::SetFrontProcess(&psn); //call before TransformProcessType() so that OSX menu is updated correctly
- //why isn't this covered by wxWindows::Raise()??
- ::TransformProcessType(&psn, kProcessTransformToForegroundApplication); //show dock icon again
-#endif
- Raise();
-}
-
-
-void MainDialog::OnConfigSave(wxCommandEvent& event)
-{
- Zstring defaultFileName = currentConfigFileName.empty() ? Zstr("Realtime.ffs_real") : currentConfigFileName;
- //attention: currentConfigFileName may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
- if (endsWith(defaultFileName, Zstr(".ffs_batch")))
- replace(defaultFileName, Zstr(".ffs_batch"), Zstr(".ffs_real"), false);
-
-
- wxFileDialog filePicker(this,
- wxEmptyString,
- //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"RealtimeSync (*.ffs_real)|*.ffs_real") + L"|" +_("All files") + L" (*.*)|*",
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- if (filePicker.ShowModal() != wxID_OK)
- return;
-
- const Zstring newFileName = utfCvrtTo<Zstring>(filePicker.GetPath());
-
- //write config to XML
- const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
- try
- {
- writeRealConfig(currentCfg, newFileName); //throw FfsXmlError
- setLastUsedConfig(newFileName);
- }
- catch (const xmlAccess::FfsXmlError& e)
- {
- showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
- }
-}
-
-
-void MainDialog::loadConfig(const Zstring& filename)
-{
- xmlAccess::XmlRealConfig newConfig;
-
- try
- {
- rts::readRealOrBatchConfig(filename, newConfig);
- }
- catch (const xmlAccess::FfsXmlError& e)
- {
- if (e.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(e.toString()));
- else
- {
- showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
- return;
- }
- }
-
- setConfiguration(newConfig);
- setLastUsedConfig(filename);
-}
-
-
-void MainDialog::setLastUsedConfig(const Zstring& filename)
-{
- //set title
- if (filename == lastConfigFileName())
- {
- SetTitle(L"RealtimeSync - " + _("Automated Synchronization"));
- currentConfigFileName.clear();
- }
- else
- {
- SetTitle(utfCvrtTo<wxString>(filename));
- currentConfigFileName = filename;
- }
-}
-
-
-void MainDialog::OnConfigLoad(wxCommandEvent& event)
-{
- wxFileDialog filePicker(this,
- wxEmptyString,
- utfCvrtTo<wxString>(beforeLast(currentConfigFileName, FILE_NAME_SEPARATOR)), //default dir; empty string if / not found
- wxEmptyString,
- wxString(L"RealtimeSync (*.ffs_real; *.ffs_batch)|*.ffs_real;*.ffs_batch") + L"|" +_("All files") + L" (*.*)|*",
- wxFD_OPEN);
- if (filePicker.ShowModal() == wxID_OK)
- loadConfig(utfCvrtTo<Zstring>(filePicker.GetPath()));
-}
-
-
-void MainDialog::onFilesDropped(FileDropEvent& event)
-{
- const auto& files = event.getFiles();
- if (!files.empty())
- loadConfig(utfCvrtTo<Zstring>(files[0]));
-}
-
-
-void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg)
-{
- //clear existing folders
- dirNameFirst->setName(wxString());
- clearAddFolders();
-
- if (!cfg.directories.empty())
- {
- //fill top folder
- dirNameFirst->setName(utfCvrtTo<wxString>(*cfg.directories.begin()));
-
- //fill additional folders
- addFolder(std::vector<Zstring>(cfg.directories.begin() + 1, cfg.directories.end()));
- }
-
- //fill commandline
- m_textCtrlCommand->SetValue(utfCvrtTo<wxString>(cfg.commandline));
-
- //set delay
- m_spinCtrlDelay->SetValue(static_cast<int>(cfg.delay));
-}
-
-
-xmlAccess::XmlRealConfig MainDialog::getConfiguration()
-{
- xmlAccess::XmlRealConfig output;
-
- output.directories.push_back(utfCvrtTo<Zstring>(dirNameFirst->getName()));
- for (auto it = dirNamesExtra.begin(); it != dirNamesExtra.end(); ++it)
- output.directories.push_back(utfCvrtTo<Zstring>((*it)->getName()));
-
- output.commandline = utfCvrtTo<Zstring>(m_textCtrlCommand->GetValue());
- output.delay = m_spinCtrlDelay->GetValue();
-
- return output;
-}
-
-
-void MainDialog::OnAddFolder(wxCommandEvent& event)
-{
- const Zstring topFolder = utfCvrtTo<Zstring>(dirNameFirst->getName());
-
- //clear existing top folder first
- dirNameFirst->setName(wxString());
-
- std::vector<Zstring> newFolders;
- newFolders.push_back(topFolder);
-
- addFolder(newFolders, true); //add pair in front of additonal pairs
-}
-
-
-void MainDialog::OnRemoveFolder(wxCommandEvent& event)
-{
- //find folder pair originating the event
- const wxObject* const eventObj = event.GetEventObject();
- for (auto it = dirNamesExtra.begin(); it != dirNamesExtra.end(); ++it)
- if (eventObj == static_cast<wxObject*>((*it)->m_bpButtonRemoveFolder))
- {
- removeAddFolder(it - dirNamesExtra.begin());
- return;
- }
-}
-
-
-void MainDialog::OnRemoveTopFolder(wxCommandEvent& event)
-{
- if (dirNamesExtra.size() > 0)
- {
- const wxString topDir = (*dirNamesExtra.begin())->getName();
-
- dirNameFirst->setName(topDir);
-
- removeAddFolder(0); //remove first of additional folders
- }
-}
-
-
-#ifdef ZEN_WIN
-static const size_t MAX_ADD_FOLDERS = 8;
-#elif defined ZEN_LINUX || defined ZEN_MAC
-static const size_t MAX_ADD_FOLDERS = 6;
-#endif
-
-
-void MainDialog::addFolder(const std::vector<Zstring>& newFolders, bool addFront)
-{
- if (newFolders.size() == 0)
- return;
-
-#ifdef ZEN_WIN
- wxWindowUpdateLocker dummy(this); //leads to GUI corruption problems on Linux/OS X!
-#endif
-
- int folderHeight = 0;
- for (auto it = newFolders.begin(); it != newFolders.end(); ++it)
- {
- //add new folder pair
- DirectoryPanel* newFolder = new DirectoryPanel(m_scrolledWinFolders);
- newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(getResourceImage(L"item_remove"));
-
- //get size of scrolled window
- folderHeight = newFolder->GetSize().GetHeight();
-
- if (addFront)
- {
- bSizerFolders->Insert(0, newFolder, 0, wxEXPAND, 5);
- dirNamesExtra.insert(dirNamesExtra.begin(), newFolder);
- }
- else
- {
- bSizerFolders->Add(newFolder, 0, wxEXPAND, 5);
- dirNamesExtra.push_back(newFolder);
- }
-
- //register events
- newFolder->m_bpButtonRemoveFolder->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainDialog::OnRemoveFolder), nullptr, this );
-
- //insert directory name
- newFolder->setName(utfCvrtTo<wxString>(*it));
- }
-
- //set size of scrolled window
- const size_t additionalRows = std::min(dirNamesExtra.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown
- m_scrolledWinFolders->SetMinSize(wxSize( -1, folderHeight * static_cast<int>(additionalRows)));
-
- //adapt delete top folder pair button
- m_bpButtonRemoveTopFolder->Show();
-
- GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
- Layout();
- Refresh(); //remove a little flicker near the start button
-}
-
-
-void MainDialog::removeAddFolder(size_t pos)
-{
-#ifdef ZEN_WIN
- wxWindowUpdateLocker dummy(this); //leads to GUI corruption problems on Linux/OS X!
-#endif
-
- if (pos < dirNamesExtra.size())
- {
- //remove folder pairs from window
- DirectoryPanel* pairToDelete = dirNamesExtra[pos];
- const int folderHeight = pairToDelete->GetSize().GetHeight();
-
- bSizerFolders->Detach(pairToDelete); //Remove() does not work on Window*, so do it manually
- dirNamesExtra.erase(dirNamesExtra.begin() + pos); //remove last element in vector
- //more (non-portable) wxWidgets bullshit: on OS X wxWindow::Destroy() screws up and calls "operator delete" directly rather than
- //the deferred deletion it is expected to do (and which is implemented correctly on Windows and Linux)
- //http://bb10.com/python-wxpython-devel/2012-09/msg00004.html
- //=> since we're in a mouse button callback of a sub-component of "pairToDelete" we need to delay deletion ourselves:
- processAsync2([] {}, [pairToDelete] { pairToDelete->Destroy(); });
-
- //set size of scrolled window
- const size_t additionalRows = std::min(dirNamesExtra.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown
- m_scrolledWinFolders->SetMinSize(wxSize( -1, folderHeight * static_cast<int>(additionalRows)));
-
- //adapt delete top folder pair button
- if (dirNamesExtra.size() == 0)
- {
- m_bpButtonRemoveTopFolder->Hide();
- m_panelMainFolder->Layout();
- }
-
- GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
- Layout();
- Refresh(); //remove a little flicker near the start button
- }
-}
-
-
-void MainDialog::clearAddFolders()
-{
-#ifdef ZEN_WIN
- wxWindowUpdateLocker dummy(this); //leads to GUI corruption problems on Linux/OS X!
-#endif
-
- bSizerFolders->Clear(true);
- dirNamesExtra.clear();
-
- m_scrolledWinFolders->SetMinSize(wxSize(-1, 0));
-
- m_bpButtonRemoveTopFolder->Hide();
- m_panelMainFolder->Layout();
-
- GetSizer()->SetSizeHints(this); //~=Fit()
- Layout();
- Refresh(); //remove a little flicker near the start button
-}
bgstack15