source: filezilla/trunk/fuentes/src/interface/Mainfrm.cpp @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 3 years ago

Update new version: 3.15.02

File size: 74.3 KB
Line 
1#include <filezilla.h>
2#include "Mainfrm.h"
3
4#include "LocalListView.h"
5#include "LocalTreeView.h"
6#include "queue.h"
7#include "RemoteListView.h"
8#include "RemoteTreeView.h"
9#include "StatusView.h"
10#include "state.h"
11#include "Options.h"
12#include "asyncrequestqueue.h"
13#include "commandqueue.h"
14#include "led.h"
15#include "sitemanager_dialog.h"
16#include "settings/settingsdialog.h"
17#include "themeprovider.h"
18#include "filezillaapp.h"
19#include "view.h"
20#include "viewheader.h"
21#include "aboutdialog.h"
22#include "filter.h"
23#include "netconfwizard.h"
24#include "quickconnectbar.h"
25#include "updater.h"
26#include "update_dialog.h"
27#include "defaultfileexistsdlg.h"
28#include "loginmanager.h"
29#include "conditionaldialog.h"
30#include "clearprivatedata.h"
31#include "export.h"
32#include "import.h"
33#include "recursive_operation.h"
34#include <wx/tokenzr.h>
35#include "edithandler.h"
36#include "inputdialog.h"
37#include "window_state_manager.h"
38#include "cmdline.h"
39#include "buildinfo.h"
40#include "filelist_statusbar.h"
41#include "manual_transfer.h"
42#include "auto_ascii_files.h"
43#include "splitter.h"
44#include "bookmarks_dialog.h"
45#include "search.h"
46#include "power_management.h"
47#include "welcome_dialog.h"
48#include "context_control.h"
49#include "speedlimits_dialog.h"
50#include "toolbar.h"
51#include "menu_bar.h"
52
53#ifdef __WXMSW__
54#include <wx/module.h>
55#endif
56#ifndef __WXMAC__
57#include <wx/taskbar.h>
58#else
59#include <wx/combobox.h>
60#endif
61
62#include <functional>
63#include <map>
64
65#ifdef __WXGTK__
66DECLARE_EVENT_TYPE(fzEVT_TASKBAR_CLICK_DELAYED, -1)
67DEFINE_EVENT_TYPE(fzEVT_TASKBAR_CLICK_DELAYED)
68#endif
69
70static int tab_hotkey_ids[10];
71
72#if FZ_MANUALUPDATECHECK
73static int GetAvailableUpdateMenuId()
74{
75        static int updateAvailableMenuId = wxNewId();
76        return updateAvailableMenuId;
77}
78#endif
79
80std::map<int, std::pair<std::function<void(wxTextEntry*)>, wxChar>> keyboardCommands;
81
82#ifdef __WXMAC__
83wxTextEntry* GetSpecialTextEntry(wxWindow* w, wxChar cmd)
84{
85        if (cmd == 'A' || cmd == 'V') {
86                wxTextCtrl* text = dynamic_cast<wxTextCtrl*>(w);
87                if (text && text->GetWindowStyle() & wxTE_PASSWORD) {
88                        return text;
89                }
90        }
91        return dynamic_cast<wxComboBox*>(w);
92}
93#else
94wxTextEntry* GetSpecialTextEntry(wxWindow*, wxChar)
95{
96        return 0;
97}
98#endif
99
100bool HandleKeyboardCommand(wxCommandEvent& event, wxWindow& parent)
101{
102        auto const& it = keyboardCommands.find(event.GetId());
103        if (it == keyboardCommands.end()) {
104                return false;
105        }
106
107        wxTextEntry* e = GetSpecialTextEntry(parent.FindFocus(), it->second.second);
108        if (e) {
109                it->second.first(e);
110        }
111        else {
112                event.Skip();
113        }
114        return true;
115}
116
117BEGIN_EVENT_TABLE(CMainFrame, wxNavigationEnabled<wxFrame>)
118        EVT_SIZE(CMainFrame::OnSize)
119        EVT_MENU(wxID_ANY, CMainFrame::OnMenuHandler)
120        EVT_FZ_NOTIFICATION(wxID_ANY, CMainFrame::OnEngineEvent)
121        EVT_COMMAND(wxID_ANY, fzEVT_UPDATE_LED_TOOLTIP, CMainFrame::OnUpdateLedTooltip)
122        EVT_TOOL(XRCID("ID_TOOLBAR_DISCONNECT"), CMainFrame::OnDisconnect)
123        EVT_MENU(XRCID("ID_MENU_SERVER_DISCONNECT"), CMainFrame::OnDisconnect)
124        EVT_TOOL(XRCID("ID_TOOLBAR_CANCEL"), CMainFrame::OnCancel)
125        EVT_MENU(XRCID("ID_CANCEL"), CMainFrame::OnCancel)
126        EVT_TOOL(XRCID("ID_TOOLBAR_RECONNECT"), CMainFrame::OnReconnect)
127        EVT_TOOL(XRCID("ID_MENU_SERVER_RECONNECT"), CMainFrame::OnReconnect)
128        EVT_TOOL(XRCID("ID_TOOLBAR_REFRESH"), CMainFrame::OnRefresh)
129        EVT_MENU(XRCID("ID_REFRESH"), CMainFrame::OnRefresh)
130        EVT_TOOL(XRCID("ID_TOOLBAR_SITEMANAGER"), CMainFrame::OnSiteManager)
131        EVT_CLOSE(CMainFrame::OnClose)
132#ifdef WITH_LIBDBUS
133        EVT_END_SESSION(CMainFrame::OnClose)
134#endif
135        EVT_TIMER(wxID_ANY, CMainFrame::OnTimer)
136        EVT_TOOL(XRCID("ID_TOOLBAR_PROCESSQUEUE"), CMainFrame::OnProcessQueue)
137        EVT_TOOL(XRCID("ID_TOOLBAR_LOGVIEW"), CMainFrame::OnToggleLogView)
138        EVT_TOOL(XRCID("ID_TOOLBAR_LOCALTREEVIEW"), CMainFrame::OnToggleDirectoryTreeView)
139        EVT_TOOL(XRCID("ID_TOOLBAR_REMOTETREEVIEW"), CMainFrame::OnToggleDirectoryTreeView)
140        EVT_TOOL(XRCID("ID_TOOLBAR_QUEUEVIEW"), CMainFrame::OnToggleQueueView)
141        EVT_MENU(XRCID("ID_VIEW_TOOLBAR"), CMainFrame::OnToggleToolBar)
142        EVT_MENU(XRCID("ID_VIEW_MESSAGELOG"), CMainFrame::OnToggleLogView)
143        EVT_MENU(XRCID("ID_VIEW_LOCALTREE"), CMainFrame::OnToggleDirectoryTreeView)
144        EVT_MENU(XRCID("ID_VIEW_REMOTETREE"), CMainFrame::OnToggleDirectoryTreeView)
145        EVT_MENU(XRCID("ID_VIEW_QUEUE"), CMainFrame::OnToggleQueueView)
146        EVT_MENU(wxID_ABOUT, CMainFrame::OnMenuHelpAbout)
147        EVT_TOOL(XRCID("ID_TOOLBAR_FILTER"), CMainFrame::OnFilter)
148        EVT_TOOL_RCLICKED(XRCID("ID_TOOLBAR_FILTER"), CMainFrame::OnFilterRightclicked)
149#if FZ_MANUALUPDATECHECK
150        EVT_MENU(XRCID("ID_CHECKFORUPDATES"), CMainFrame::OnCheckForUpdates)
151        EVT_MENU(GetAvailableUpdateMenuId(), CMainFrame::OnCheckForUpdates)
152#endif //FZ_MANUALUPDATECHECK
153        EVT_TOOL_RCLICKED(XRCID("ID_TOOLBAR_SITEMANAGER"), CMainFrame::OnSitemanagerDropdown)
154#ifdef EVT_TOOL_DROPDOWN
155        EVT_TOOL_DROPDOWN(XRCID("ID_TOOLBAR_SITEMANAGER"), CMainFrame::OnSitemanagerDropdown)
156#endif
157        EVT_NAVIGATION_KEY(CMainFrame::OnNavigationKeyEvent)
158        EVT_CHAR_HOOK(CMainFrame::OnChar)
159        EVT_MENU(XRCID("ID_MENU_VIEW_FILTERS"), CMainFrame::OnFilter)
160        EVT_ACTIVATE(CMainFrame::OnActivate)
161        EVT_TOOL(XRCID("ID_TOOLBAR_COMPARISON"), CMainFrame::OnToolbarComparison)
162        EVT_TOOL_RCLICKED(XRCID("ID_TOOLBAR_COMPARISON"), CMainFrame::OnToolbarComparisonDropdown)
163#ifdef EVT_TOOL_DROPDOWN
164        EVT_TOOL_DROPDOWN(XRCID("ID_TOOLBAR_COMPARISON"), CMainFrame::OnToolbarComparisonDropdown)
165#endif
166        EVT_MENU(XRCID("ID_COMPARE_SIZE"), CMainFrame::OnDropdownComparisonMode)
167        EVT_MENU(XRCID("ID_COMPARE_DATE"), CMainFrame::OnDropdownComparisonMode)
168        EVT_MENU(XRCID("ID_COMPARE_HIDEIDENTICAL"), CMainFrame::OnDropdownComparisonHide)
169        EVT_TOOL(XRCID("ID_TOOLBAR_SYNCHRONIZED_BROWSING"), CMainFrame::OnSyncBrowse)
170#ifdef __WXMAC__
171        EVT_CHILD_FOCUS(CMainFrame::OnChildFocused)
172#else
173        EVT_ICONIZE(CMainFrame::OnIconize)
174#endif
175#ifdef __WXGTK__
176        EVT_COMMAND(wxID_ANY, fzEVT_TASKBAR_CLICK_DELAYED, CMainFrame::OnTaskBarClick_Delayed)
177#endif
178        EVT_TOOL(XRCID("ID_TOOLBAR_FIND"), CMainFrame::OnSearch)
179        EVT_MENU(XRCID("ID_MENU_SERVER_SEARCH"), CMainFrame::OnSearch)
180        EVT_MENU(XRCID("ID_MENU_FILE_NEWTAB"), CMainFrame::OnMenuNewTab)
181        EVT_MENU(XRCID("ID_MENU_FILE_CLOSETAB"), CMainFrame::OnMenuCloseTab)
182END_EVENT_TABLE()
183
184class CMainFrameStateEventHandler : public CStateEventHandler
185{
186public:
187        CMainFrameStateEventHandler(CMainFrame* pMainFrame)
188                : CStateEventHandler(0)
189        {
190                m_pMainFrame = pMainFrame;
191
192                CContextManager::Get()->RegisterHandler(this, STATECHANGE_REMOTE_IDLE, false);
193                CContextManager::Get()->RegisterHandler(this, STATECHANGE_SERVER, false);
194
195                CContextManager::Get()->RegisterHandler(this, STATECHANGE_CHANGEDCONTEXT, false);
196        }
197
198protected:
199        virtual void OnStateChange(CState* pState, enum t_statechange_notifications notification, const wxString&, const void*)
200        {
201                if (notification == STATECHANGE_CHANGEDCONTEXT)
202                {
203                        // Update window title
204                        const CServer* pServer = pState ? pState->GetServer() : 0;
205                        if (!pServer)
206                                m_pMainFrame->SetTitle(_T("FileZilla"));
207                        else
208                                m_pMainFrame->SetTitle(pState->GetTitle() + _T(" - FileZilla"));
209
210                        return;
211                }
212
213                if (!pState)
214                        return;
215
216                CContextControl::_context_controls* controls = m_pMainFrame->m_pContextControl->GetControlsFromState(pState);
217                if (!controls)
218                        return;
219
220                if (controls->tab_index == -1)
221                {
222                        if (notification == STATECHANGE_REMOTE_IDLE || notification == STATECHANGE_SERVER)
223                                pState->Disconnect();
224
225                        return;
226                }
227
228                if (notification == STATECHANGE_SERVER)
229                {
230                        const CServer* pServer = pState->GetServer();
231
232                        if (pState == CContextManager::Get()->GetCurrentContext())
233                        {
234                                if (!pServer)
235                                        m_pMainFrame->SetTitle(_T("FileZilla"));
236                                else
237                                {
238                                        m_pMainFrame->SetTitle(pState->GetTitle() + _T(" - FileZilla"));
239                                        if (pServer->GetName().empty())
240                                        {
241                                                // Can only happen through quickconnect bar
242                                                CMenuBar* pMenuBar = wxDynamicCast(m_pMainFrame->GetMenuBar(), CMenuBar);
243                                                if (pMenuBar)
244                                                        pMenuBar->ClearBookmarks();
245                                        }
246                                }
247                        }
248
249                        return;
250                }
251        }
252
253        CMainFrame* m_pMainFrame;
254};
255
256CMainFrame::CMainFrame()
257        : m_engineContext(*COptions::Get())
258        , m_comparisonToggleAcceleratorId(wxNewId())
259{
260        m_pActivityLed[0] = m_pActivityLed[1] = 0;
261
262        wxGetApp().AddStartupProfileRecord(_T("CMainFrame::CMainFrame"));
263        wxRect screen_size = CWindowStateManager::GetScreenDimensions();
264
265        wxSize initial_size;
266        initial_size.x = wxMin(1200, screen_size.GetWidth() - 10);
267        initial_size.y = wxMin(950, screen_size.GetHeight() - 50);
268
269        Create(NULL, -1, _T("FileZilla"), wxDefaultPosition, initial_size);
270        SetSizeHints(350, 300);
271
272#ifdef __WXMSW__
273        // In order for the --close commandline argument to work,
274        // there has to be a way to find other instances.
275        // Create a hidden window with a title no other program uses
276        wxWindow* pChild = new wxWindow();
277        pChild->Hide();
278        pChild->Create(this, wxID_ANY);
279        ::SetWindowText((HWND)pChild->GetHandle(), _T("FileZilla process identificator 3919DB0A-082D-4560-8E2F-381A35969FB4"));
280#endif
281
282#ifdef __WXMSW__
283        SetIcon(wxICON(appicon));
284#else
285        SetIcons(CThemeProvider::GetIconBundle(_T("ART_FILEZILLA")));
286#endif
287
288        m_pThemeProvider = new CThemeProvider();
289
290        CPowerManagement::Create(this);
291
292        // It's important that the context control gets created before our own state handler
293        // so that contextchange events can be processed in the right order.
294        m_pContextControl = new CContextControl(*this);
295
296        m_pStatusBar = new CStatusBar(this);
297        if (m_pStatusBar) {
298                m_pActivityLed[0] = new CLed(m_pStatusBar, 0);
299                m_pActivityLed[1] = new CLed(m_pStatusBar, 1);
300
301                m_pStatusBar->AddField(-1, widget_led_recv, m_pActivityLed[1]);
302                m_pStatusBar->AddField(-1, widget_led_send, m_pActivityLed[0]);
303
304                SetStatusBar(m_pStatusBar);
305        }
306
307        m_closeEventTimer.SetOwner(this);
308
309        if (CFilterManager::HasActiveFilters(true)) {
310                if (COptions::Get()->GetOptionVal(OPTION_FILTERTOGGLESTATE))
311                        CFilterManager::ToggleFilters();
312        }
313
314        CreateMenus();
315        CreateMainToolBar();
316        if (COptions::Get()->GetOptionVal(OPTION_SHOW_QUICKCONNECT))
317                CreateQuickconnectBar();
318
319        m_pAsyncRequestQueue = new CAsyncRequestQueue(this);
320
321#ifdef __WXMSW__
322        long style = wxSP_NOBORDER | wxSP_LIVE_UPDATE;
323#elif !defined(__WXMAC__)
324        long style = wxSP_3DBORDER | wxSP_LIVE_UPDATE;
325#else
326        long style = wxSP_LIVE_UPDATE;
327#endif
328
329        wxSize clientSize = GetClientSize();
330
331        m_pTopSplitter = new CSplitterWindowEx(this, -1, wxDefaultPosition, clientSize, style);
332        m_pTopSplitter->SetMinimumPaneSize(50);
333
334        m_pBottomSplitter = new CSplitterWindowEx(m_pTopSplitter, -1, wxDefaultPosition, wxDefaultSize, wxSP_NOBORDER | wxSP_LIVE_UPDATE);
335        m_pBottomSplitter->SetMinimumPaneSize(20, 70);
336        m_pBottomSplitter->SetSashGravity(1.0);
337
338        const int message_log_position = COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION);
339        m_pQueueLogSplitter = new CSplitterWindowEx(m_pBottomSplitter, -1, wxDefaultPosition, wxDefaultSize, wxSP_NOBORDER | wxSP_LIVE_UPDATE);
340        m_pQueueLogSplitter->SetMinimumPaneSize(50, 250);
341        m_pQueueLogSplitter->SetSashGravity(0.5);
342        m_pQueuePane = new CQueue(m_pQueueLogSplitter, this, m_pAsyncRequestQueue);
343
344        if (message_log_position == 1)
345                m_pStatusView = new CStatusView(m_pQueueLogSplitter, -1);
346        else
347                m_pStatusView = new CStatusView(m_pTopSplitter, -1);
348
349        m_pQueueView = m_pQueuePane->GetQueueView();
350
351        m_pContextControl->Create(m_pBottomSplitter);
352
353        m_pStateEventHandler = new CMainFrameStateEventHandler(this);
354
355        m_pContextControl->CreateTab();
356
357        switch (message_log_position) {
358        case 1:
359                m_pTopSplitter->Initialize(m_pBottomSplitter);
360                if (COptions::Get()->GetOptionVal(OPTION_SHOW_MESSAGELOG)) {
361                        if (COptions::Get()->GetOptionVal(OPTION_SHOW_QUEUE))
362                                m_pQueueLogSplitter->SplitVertically(m_pQueuePane, m_pStatusView);
363                        else {
364                                m_pQueueLogSplitter->Initialize(m_pStatusView);
365                                m_pQueuePane->Hide();
366                        }
367                }
368                else {
369                        if (COptions::Get()->GetOptionVal(OPTION_SHOW_QUEUE)) {
370                                m_pStatusView->Hide();
371                                m_pQueueLogSplitter->Initialize(m_pQueuePane);
372                        }
373                        else {
374                                m_pQueuePane->Hide();
375                                m_pStatusView->Hide();
376                                m_pQueueLogSplitter->Hide();
377                        }
378                }
379                break;
380        case 2:
381                m_pTopSplitter->Initialize(m_pBottomSplitter);
382                if (COptions::Get()->GetOptionVal(OPTION_SHOW_QUEUE))
383                        m_pQueueLogSplitter->Initialize(m_pQueuePane);
384                else {
385                        m_pQueueLogSplitter->Hide();
386                        m_pQueuePane->Hide();
387                }
388                m_pQueuePane->AddPage(m_pStatusView, _("Message log"));
389                break;
390        default:
391                if (COptions::Get()->GetOptionVal(OPTION_SHOW_QUEUE))
392                        m_pQueueLogSplitter->Initialize(m_pQueuePane);
393                else {
394                        m_pQueuePane->Hide();
395                        m_pQueueLogSplitter->Hide();
396                }
397                if (COptions::Get()->GetOptionVal(OPTION_SHOW_MESSAGELOG))
398                        m_pTopSplitter->SplitHorizontally(m_pStatusView, m_pBottomSplitter);
399                else {
400                        m_pStatusView->Hide();
401                        m_pTopSplitter->Initialize(m_pBottomSplitter);
402                }
403                break;
404        }
405
406        if (m_pQueueLogSplitter->IsShown())
407                m_pBottomSplitter->SplitHorizontally(m_pContextControl, m_pQueueLogSplitter);
408        else {
409                m_pQueueLogSplitter->Hide();
410                m_pBottomSplitter->Initialize(m_pContextControl);
411        }
412
413        m_pWindowStateManager = new CWindowStateManager(this);
414        m_pWindowStateManager->Restore(OPTION_MAINWINDOW_POSITION);
415
416        Layout();
417        HandleResize();
418
419        if (!RestoreSplitterPositions())
420                SetDefaultSplitterPositions();
421
422        SetupKeyboardAccelerators();
423
424        ConnectNavigationHandler(m_pStatusView);
425        ConnectNavigationHandler(m_pQueuePane);
426
427        CEditHandler::Create()->SetQueue(m_pQueueView);
428
429        CAutoAsciiFiles::SettingsChanged();
430
431        FixTabOrder();
432
433        RegisterOption(OPTION_LANGUAGE);
434        RegisterOption(OPTION_THEME);
435        RegisterOption(OPTION_THEME_ICONSIZE);
436        RegisterOption(OPTION_MESSAGELOG_POSITION);
437        RegisterOption(OPTION_FILEPANE_LAYOUT);
438        RegisterOption(OPTION_FILEPANE_SWAP);
439}
440
441CMainFrame::~CMainFrame()
442{
443        UnregisterAllOptions();
444
445        CPowerManagement::Destroy();
446
447        delete m_pStateEventHandler;
448
449        CContextManager::Get()->DestroyAllStates();
450        delete m_pAsyncRequestQueue;
451#if FZ_MANUALUPDATECHECK
452        delete m_pUpdater;
453#endif
454
455        CEditHandler* pEditHandler = CEditHandler::Get();
456        if (pEditHandler) {
457                // This might leave temporary files behind,
458                // edit handler should clean them on next startup
459                pEditHandler->Release();
460        }
461
462#ifndef __WXMAC__
463        delete m_taskBarIcon;
464#endif
465}
466
467void CMainFrame::HandleResize()
468{
469        wxSize clientSize = GetClientSize();
470        if (clientSize.y <= 0) // Can happen if restoring from tray on XP if using ugly XP themes
471                return;
472
473        if (m_pQuickconnectBar)
474                m_pQuickconnectBar->SetSize(0, 0, clientSize.GetWidth(), -1, wxSIZE_USE_EXISTING);
475        if (m_pTopSplitter)
476        {
477                if (!m_pQuickconnectBar)
478                        m_pTopSplitter->SetSize(0, 0, clientSize.GetWidth(), clientSize.GetHeight());
479                else
480                {
481                        wxSize panelSize = m_pQuickconnectBar->GetSize();
482                        m_pTopSplitter->SetSize(0, panelSize.GetHeight(), clientSize.GetWidth(), clientSize.GetHeight() - panelSize.GetHeight());
483                }
484        }
485}
486
487void CMainFrame::OnSize(wxSizeEvent &event)
488{
489        wxFrame::OnSize(event);
490
491        if (!m_pBottomSplitter)
492                return;
493
494        HandleResize();
495
496#ifdef __WXGTK__
497        if (m_pWindowStateManager && m_pWindowStateManager->m_maximize_requested && IsMaximized())
498        {
499                m_pWindowStateManager->m_maximize_requested = 0;
500                if (!RestoreSplitterPositions())
501                        SetDefaultSplitterPositions();
502        }
503#endif
504}
505
506bool CMainFrame::CreateMenus()
507{
508        wxGetApp().AddStartupProfileRecord(_T("CMainFrame::CreateMenus"));
509        CMenuBar* old = m_pMenuBar;
510
511        m_pMenuBar = CMenuBar::Load(this);
512
513        if (!m_pMenuBar) {
514                m_pMenuBar = old;
515                return false;
516        }
517
518        SetMenuBar(m_pMenuBar);
519        delete old;
520
521        return true;
522}
523
524bool CMainFrame::CreateQuickconnectBar()
525{
526        wxGetApp().AddStartupProfileRecord(_T("CMainFrame::CreateQuickconnectBar"));
527        delete m_pQuickconnectBar;
528
529        m_pQuickconnectBar = new CQuickconnectBar();
530        if (!m_pQuickconnectBar->Create(this))
531        {
532                delete m_pQuickconnectBar;
533                m_pQuickconnectBar = 0;
534        }
535        else
536        {
537                wxSize clientSize = GetClientSize();
538                if (m_pTopSplitter)
539                {
540                        wxSize panelSize = m_pQuickconnectBar->GetSize();
541                        m_pTopSplitter->SetSize(-1, panelSize.GetHeight(), -1, clientSize.GetHeight() - panelSize.GetHeight(), wxSIZE_USE_EXISTING);
542                }
543                m_pQuickconnectBar->SetSize(0, 0, clientSize.GetWidth(), -1);
544        }
545
546        return true;
547}
548
549void CMainFrame::OnMenuHandler(wxCommandEvent &event)
550{
551        if (event.GetId() == XRCID("wxID_EXIT")) {
552                Close();
553        }
554        else if (event.GetId() == XRCID("ID_MENU_FILE_SITEMANAGER")) {
555                OpenSiteManager();
556        }
557        else if (event.GetId() == XRCID("ID_MENU_FILE_COPYSITEMANAGER")) {
558                CState* pState = CContextManager::Get()->GetCurrentContext();
559                const CServer* pServer = pState ? pState->GetServer() : 0;
560                if (!pServer) {
561                        wxMessageBoxEx(_("Not connected to any server."), _("Cannot add server to Site Manager"), wxICON_EXCLAMATION);
562                        return;
563                }
564                OpenSiteManager(pServer);
565        }
566        else if (event.GetId() == XRCID("ID_MENU_SERVER_CMD")) {
567                CState* pState = CContextManager::Get()->GetCurrentContext();
568                if (!pState || !pState->m_pCommandQueue || !pState->IsRemoteConnected() || !pState->IsRemoteIdle())
569                        return;
570
571                CInputDialog dlg;
572                dlg.Create(this, _("Enter custom command"), _("Please enter raw FTP command.\nUsing raw ftp commands will clear the directory cache."));
573                if (dlg.ShowModal() != wxID_OK)
574                        return;
575
576                pState = CContextManager::Get()->GetCurrentContext();
577                if (!pState || !pState->m_pCommandQueue || !pState->IsRemoteConnected() || !pState->IsRemoteIdle()) {
578                        wxBell();
579                        return;
580                }
581
582                const wxString &command = dlg.GetValue();
583
584                if (!command.Left(5).CmpNoCase(_T("quote")) || !command.Left(6).CmpNoCase(_T("quote "))) {
585                        CConditionalDialog condDlg(this, CConditionalDialog::rawcommand_quote, CConditionalDialog::yesno);
586                        condDlg.SetTitle(_("Raw FTP command"));
587
588                        condDlg.AddText(_("'quote' is usually a local command used by commandline clients to send the arguments following 'quote' to the server. You might want to enter the raw command without the leading 'quote'."));
589                        condDlg.AddText(wxString::Format(_("Do you really want to send '%s' to the server?"), command));
590
591                        if (!condDlg.Run())
592                                return;
593                }
594
595                pState = CContextManager::Get()->GetCurrentContext();
596                if (!pState || !pState->m_pCommandQueue || !pState->IsRemoteConnected() || !pState->IsRemoteIdle()) {
597                        wxBell();
598                        return;
599                }
600                pState->m_pCommandQueue->ProcessCommand(new CRawCommand(dlg.GetValue()));
601        }
602        else if (event.GetId() == XRCID("wxID_PREFERENCES")) {
603                OnMenuEditSettings(event);
604        }
605        else if (event.GetId() == XRCID("ID_MENU_EDIT_NETCONFWIZARD")) {
606                CNetConfWizard wizard(this, COptions::Get(), m_engineContext);
607                wizard.Load();
608                wizard.Run();
609        }
610        // Debug menu
611        else if (event.GetId() == XRCID("ID_CIPHERS")) {
612                CInputDialog dlg;
613                dlg.Create(this, _T("Ciphers"), _T("Priority string:"));
614                dlg.AllowEmpty(true);
615                if (dlg.ShowModal() == wxID_OK)
616                        wxMessageBoxEx(ListTlsCiphers(dlg.GetValue()), _T("Ciphers"));
617        }
618        else if (event.GetId() == XRCID("ID_CLEARCACHE_LAYOUT")) {
619                CWrapEngine::ClearCache();
620        }
621        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_FILEEXISTS")) {
622                CDefaultFileExistsDlg dlg;
623                if (!dlg.Load(this, false))
624                        return;
625
626                dlg.Run();
627        }
628        else if (event.GetId() == XRCID("ID_MENU_EDIT_CLEARPRIVATEDATA")) {
629                CClearPrivateDataDialog* pDlg = CClearPrivateDataDialog::Create(this);
630                if (!pDlg)
631                        return;
632
633                pDlg->Run();
634                pDlg->Delete();
635
636                if (m_pMenuBar)
637                        m_pMenuBar->UpdateMenubarState();
638                if (m_pToolBar)
639                        m_pToolBar->UpdateToolbarState();
640        }
641        else if (event.GetId() == XRCID("ID_MENU_SERVER_VIEWHIDDEN")) {
642                bool showHidden = COptions::Get()->GetOptionVal(OPTION_VIEW_HIDDEN_FILES) ? 0 : 1;
643                if (showHidden) {
644                        CConditionalDialog dlg(this, CConditionalDialog::viewhidden, CConditionalDialog::ok, false);
645                        dlg.SetTitle(_("Force showing hidden files"));
646
647                        dlg.AddText(_("Note that this feature is only supported using the FTP protocol."));
648                        dlg.AddText(_("A proper server always shows all files, but some broken servers hide files from the user. Use this option to force the server to show all files."));
649                        dlg.AddText(_("Keep in mind that not all servers support this feature and may return incorrect listings if this option is enabled. Although FileZilla performs some tests to check if the server supports this feature, the test may fail."));
650                        dlg.AddText(_("Disable this option again if you will not be able to see the correct directory contents anymore."));
651                        (void)dlg.Run();
652                }
653
654                COptions::Get()->SetOption(OPTION_VIEW_HIDDEN_FILES, showHidden ? 1 : 0);
655                const std::vector<CState*> *pStates = CContextManager::Get()->GetAllStates();
656                for (auto & pState : *pStates) {
657                        CServerPath path = pState->GetRemotePath();
658                        if (!path.empty() && pState->m_pCommandQueue)
659                                pState->ChangeRemoteDir(path, _T(""), LIST_FLAG_REFRESH);
660                }
661        }
662        else if (event.GetId() == XRCID("ID_EXPORT")) {
663                CExportDialog dlg(this, m_pQueueView);
664                dlg.Run();
665        }
666        else if (event.GetId() == XRCID("ID_IMPORT")) {
667                CImportDialog dlg(this, m_pQueueView);
668                dlg.Run();
669        }
670        else if (event.GetId() == XRCID("ID_MENU_FILE_EDITED")) {
671                CEditHandlerStatusDialog dlg(this);
672                dlg.ShowModal();
673        }
674        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_TYPE_AUTO")) {
675                COptions::Get()->SetOption(OPTION_ASCIIBINARY, 0);
676        }
677        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_TYPE_ASCII")) {
678                COptions::Get()->SetOption(OPTION_ASCIIBINARY, 1);
679        }
680        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_TYPE_BINARY")) {
681                COptions::Get()->SetOption(OPTION_ASCIIBINARY, 2);
682        }
683        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_PRESERVETIMES")) {
684                if (event.IsChecked()) {
685                        CConditionalDialog dlg(this, CConditionalDialog::confirm_preserve_timestamps, CConditionalDialog::ok, true);
686                        dlg.SetTitle(_("Preserving file timestamps"));
687                        dlg.AddText(_("Please note that preserving timestamps on uploads on FTP, FTPS and FTPES servers only works if they support the MFMT command."));
688                        dlg.Run();
689                }
690                COptions::Get()->SetOption(OPTION_PRESERVE_TIMESTAMPS, event.IsChecked() ? 1 : 0);
691        }
692        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_PROCESSQUEUE")) {
693                if (m_pQueueView)
694                        m_pQueueView->SetActive(event.IsChecked());
695        }
696        else if (event.GetId() == XRCID("ID_MENU_HELP_GETTINGHELP") ||
697                         event.GetId() == XRCID("ID_MENU_HELP_BUGREPORT"))
698        {
699                wxString url(_T("https://filezilla-project.org/support.php?type=client&mode="));
700                if (event.GetId() == XRCID("ID_MENU_HELP_GETTINGHELP"))
701                        url += _T("help");
702                else
703                        url += _T("bugreport");
704                wxString version = CBuildInfo::GetVersion();
705                if (version != _T("custom build")) {
706                        url += _T("&version=");
707                        // We need to urlencode version number
708
709                        // Unbelievable, but wxWidgets does not have any method
710                        // to urlencode strings.
711                        // Do a crude approach: Drop everything unexpected...
712                        for (unsigned int i = 0; i < version.Len(); i++) {
713                                wxChar c = version.GetChar(i);
714                                if ((c >= '0' && c <= '9') ||
715                                        (c >= 'a' && c <= 'z') ||
716                                        (c >= 'A' && c <= 'Z') ||
717                                        c == '-' || c == '.' ||
718                                        c == '_')
719                                {
720                                        url.Append(c);
721                                }
722                        }
723                }
724                wxLaunchDefaultBrowser(url);
725        }
726        else if (event.GetId() == XRCID("ID_MENU_VIEW_FILELISTSTATUSBAR")) {
727                bool show = COptions::Get()->GetOptionVal(OPTION_FILELIST_STATUSBAR) == 0;
728                COptions::Get()->SetOption(OPTION_FILELIST_STATUSBAR, show ? 1 : 0);
729                CContextControl::_context_controls* controls = m_pContextControl ? m_pContextControl->GetCurrentControls() : 0;
730                if (controls && controls->pLocalListViewPanel) {
731                        wxStatusBar* pStatusBar = controls->pLocalListViewPanel->GetStatusBar();
732                        if (pStatusBar) {
733                                pStatusBar->Show(show);
734                                wxSizeEvent evt;
735                                controls->pLocalListViewPanel->ProcessWindowEvent(evt);
736                        }
737                }
738                if (controls && controls->pRemoteListViewPanel) {
739                        wxStatusBar* pStatusBar = controls->pRemoteListViewPanel->GetStatusBar();
740                        if (pStatusBar) {
741                                pStatusBar->Show(show);
742                                wxSizeEvent evt;
743                                controls->pRemoteListViewPanel->ProcessWindowEvent(evt);
744                        }
745                }
746        }
747        else if (event.GetId() == XRCID("ID_VIEW_QUICKCONNECT")) {
748                if (!m_pQuickconnectBar)
749                        CreateQuickconnectBar();
750                else {
751                        m_pQuickconnectBar->Destroy();
752                        m_pQuickconnectBar = 0;
753                        wxSize clientSize = GetClientSize();
754                        m_pTopSplitter->SetSize(0, 0, clientSize.GetWidth(), clientSize.GetHeight());
755                }
756                COptions::Get()->SetOption(OPTION_SHOW_QUICKCONNECT, m_pQuickconnectBar != 0);
757        }
758        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_MANUAL")) {
759                CState* pState = CContextManager::Get()->GetCurrentContext();
760                if (!pState || !m_pQueueView) {
761                        wxBell();
762                        return;
763                }
764                CManualTransfer dlg(m_pQueueView);
765                dlg.Run(this, pState);
766        }
767        else if (event.GetId() == XRCID("ID_BOOKMARK_ADD") || event.GetId() == XRCID("ID_BOOKMARK_MANAGE")) {
768                CServer server;
769                CState* pState = CContextManager::Get()->GetCurrentContext();
770                if (!pState) {
771                        return;
772                }
773                CServer const* pServer = pState->GetServer();
774
775                CContextControl::_context_controls* controls = m_pContextControl->GetCurrentControls();
776                if (!controls)
777                        return;
778                if (!pServer && !controls->site_bookmarks->path.empty()) {
779                        // Get server from site manager
780                        std::unique_ptr<CSiteManagerItemData_Site> data = CSiteManager::GetSiteByPath(controls->site_bookmarks->path);
781                        if (data) {
782                                server = data->m_server;
783                                pServer = &server;
784                        }
785                        else {
786                                controls->site_bookmarks->path.clear();
787                                controls->site_bookmarks->bookmarks.clear();
788                                if (m_pMenuBar)
789                                        m_pMenuBar->UpdateBookmarkMenu();
790                        }
791                }
792
793                // controls->last_bookmark_path can get modified if it's empty now
794                int res;
795                if (event.GetId() == XRCID("ID_BOOKMARK_ADD")) {
796                        CNewBookmarkDialog dlg(this, controls->site_bookmarks->path, pServer);
797                        res = dlg.Run(pState->GetLocalDir().GetPath(), pState->GetRemotePath());
798                }
799                else {
800                        CBookmarksDialog dlg(this, controls->site_bookmarks->path, pServer);
801
802                        res = dlg.Run();
803                }
804                if (res == wxID_OK) {
805                        controls->site_bookmarks->bookmarks.clear();
806                        CSiteManager::GetBookmarks(controls->site_bookmarks->path, controls->site_bookmarks->bookmarks);
807                        if (m_pMenuBar)
808                                m_pMenuBar->UpdateBookmarkMenu();
809                }
810        }
811        else if (event.GetId() == XRCID("ID_MENU_HELP_WELCOME")) {
812                CWelcomeDialog dlg;
813                dlg.Run(this, true);
814        }
815        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_SPEEDLIMITS_ENABLE")) {
816                bool enable = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_ENABLE) == 0;
817
818                const int downloadLimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_INBOUND);
819                const int uploadLimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_OUTBOUND);
820                if (enable && !downloadLimit && !uploadLimit) {
821                        CSpeedLimitsDialog dlg;
822                        dlg.Run(this);
823                }
824                else
825                        COptions::Get()->SetOption(OPTION_SPEEDLIMIT_ENABLE, enable ? 1 : 0);
826        }
827        else if (event.GetId() == XRCID("ID_MENU_TRANSFER_SPEEDLIMITS_CONFIGURE")) {
828                CSpeedLimitsDialog dlg;
829                dlg.Run(this);
830        }
831        else if (event.GetId() == m_comparisonToggleAcceleratorId) {
832                CState* pState = CContextManager::Get()->GetCurrentContext();
833                if (!pState)
834                        return;
835
836                int old_mode = COptions::Get()->GetOptionVal(OPTION_COMPARISONMODE);
837                COptions::Get()->SetOption(OPTION_COMPARISONMODE, old_mode ? 0 : 1);
838
839                CComparisonManager* pComparisonManager = pState->GetComparisonManager();
840                if (pComparisonManager && pComparisonManager->IsComparing())
841                        pComparisonManager->CompareListings();
842        }
843        else if (HandleKeyboardCommand(event, *this)) {
844                return;
845        }
846        else {
847                for (int i = 0; i < 10; ++i) {
848                        if (event.GetId() != tab_hotkey_ids[i])
849                                continue;
850
851                        if (!m_pContextControl)
852                                return;
853
854                        int sel = i - 1;
855                        if (sel < 0)
856                                sel = 9;
857                        m_pContextControl->SelectTab(sel);
858
859                        return;
860                }
861
862                std::unique_ptr<CSiteManagerItemData_Site> pData = CSiteManager::GetSiteById(event.GetId());
863
864                if (!pData) {
865                        event.Skip();
866                }
867                else {
868                        ConnectToSite(*pData);
869                }
870        }
871}
872
873void CMainFrame::OnEngineEvent(wxFzEvent &event)
874{
875        const std::vector<CState*> *pStates = CContextManager::Get()->GetAllStates();
876        CState* pState = 0;
877        for (std::vector<CState*>::const_iterator iter = pStates->begin(); iter != pStates->end(); ++iter) {
878                if ((*iter)->m_pEngine != event.engine_)
879                        continue;
880
881                pState = *iter;
882                break;
883        }
884        if (!pState)
885                return;
886
887        std::unique_ptr<CNotification> pNotification = pState->m_pEngine->GetNextNotification();
888        while (pNotification) {
889                switch (pNotification->GetID())
890                {
891                case nId_logmsg:
892                        m_pStatusView->AddToLog(static_cast<CLogmsgNotification&>(*pNotification.get()));
893                        if (COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION) == 2)
894                                m_pQueuePane->Highlight(3);
895                        break;
896                case nId_operation:
897                        pState->m_pCommandQueue->Finish(unique_static_cast<COperationNotification>(std::move(pNotification)));
898                        if (m_bQuit) {
899                                Close();
900                                return;
901                        }
902                        break;
903                case nId_listing:
904                        {
905                                auto const& listingNotification = static_cast<CDirectoryListingNotification const&>(*pNotification.get());
906                                pState->m_pCommandQueue->ProcessDirectoryListing(listingNotification);
907                        }
908                        break;
909                case nId_asyncrequest:
910                        {
911                                auto pAsyncRequest = unique_static_cast<CAsyncRequestNotification>(std::move(pNotification));
912                                if (pAsyncRequest->GetRequestID() == reqId_fileexists)
913                                        m_pQueueView->ProcessNotification(pState->m_pEngine, std::move(pAsyncRequest));
914                                else {
915                                        if (pAsyncRequest->GetRequestID() == reqId_certificate)
916                                                pState->SetSecurityInfo(static_cast<CCertificateNotification&>(*pAsyncRequest));
917                                        m_pAsyncRequestQueue->AddRequest(pState->m_pEngine, std::move(pAsyncRequest));
918                                }
919                        }
920                        break;
921                case nId_active:
922                        {
923                                CActiveNotification const& activeNotification = static_cast<CActiveNotification const&>(*pNotification.get());
924                                UpdateActivityLed(activeNotification.GetDirection());
925                        }
926                        break;
927                case nId_transferstatus:
928                        m_pQueueView->ProcessNotification(pState->m_pEngine, std::move(pNotification));
929                        break;
930                case nId_sftp_encryption:
931                        {
932                                pState->SetSecurityInfo(static_cast<CSftpEncryptionNotification&>(*pNotification));
933                        }
934                        break;
935                case nId_local_dir_created:
936                        if (pState) {
937                                auto const& localDirCreatedNotification = static_cast<CLocalDirCreatedNotification const&>(*pNotification.get());
938                                pState->LocalDirCreated(localDirCreatedNotification.dir);
939                        }
940                        break;
941                default:
942                        break;
943                }
944
945                pNotification = pState->m_pEngine->GetNextNotification();
946        }
947}
948
949void CMainFrame::OnUpdateLedTooltip(wxCommandEvent&)
950{
951        wxString tooltipText;
952
953        wxFileOffset downloadSpeed = m_pQueueView ? m_pQueueView->GetCurrentDownloadSpeed() : 0;
954        wxFileOffset uploadSpeed = m_pQueueView ? m_pQueueView->GetCurrentUploadSpeed() : 0;
955
956        CSizeFormat::_format format = static_cast<CSizeFormat::_format>(COptions::Get()->GetOptionVal(OPTION_SIZE_FORMAT));
957        if (format == CSizeFormat::bytes)
958                format = CSizeFormat::iec;
959
960        const wxString downloadSpeedStr = CSizeFormat::Format(downloadSpeed, true, format,
961                                                                                                                  COptions::Get()->GetOptionVal(OPTION_SIZE_USETHOUSANDSEP) != 0,
962                                                                                                                  COptions::Get()->GetOptionVal(OPTION_SIZE_DECIMALPLACES));
963        const wxString uploadSpeedStr = CSizeFormat::Format(uploadSpeed, true, format,
964                                                                                                                COptions::Get()->GetOptionVal(OPTION_SIZE_USETHOUSANDSEP) != 0,
965                                                                                                                COptions::Get()->GetOptionVal(OPTION_SIZE_DECIMALPLACES));
966        tooltipText.Printf(_("Download speed: %s/s\nUpload speed: %s/s"), downloadSpeedStr, uploadSpeedStr);
967
968        m_pActivityLed[0]->SetToolTip(tooltipText);
969        m_pActivityLed[1]->SetToolTip(tooltipText);
970}
971
972bool CMainFrame::CreateMainToolBar()
973{
974        wxGetApp().AddStartupProfileRecord(_T("CMainFrame::CreateMainToolBar"));
975        if (m_pToolBar)
976        {
977#ifdef __WXMAC__
978                if (m_pToolBar)
979                        COptions::Get()->SetOption(OPTION_TOOLBAR_HIDDEN, m_pToolBar->IsShown() ? 0 : 1);
980#endif
981                SetToolBar(0);
982                delete m_pToolBar;
983                m_pToolBar = 0;
984        }
985
986#ifndef __WXMAC__
987        if (COptions::Get()->GetOptionVal(OPTION_TOOLBAR_HIDDEN) != 0)
988                return true;
989#endif
990
991        m_pToolBar = CToolBar::Load(this);
992        if (!m_pToolBar)
993        {
994                wxLogError(_("Cannot load toolbar from resource file"));
995                return false;
996        }
997        SetToolBar(m_pToolBar);
998
999        if (m_pQuickconnectBar)
1000                m_pQuickconnectBar->Refresh();
1001
1002        return true;
1003}
1004
1005void CMainFrame::OnDisconnect(wxCommandEvent&)
1006{
1007        CState* pState = CContextManager::Get()->GetCurrentContext();
1008        if (!pState || !pState->IsRemoteConnected())
1009                return;
1010
1011        if (!pState->IsRemoteIdle())
1012                return;
1013
1014        pState->Disconnect();
1015}
1016
1017void CMainFrame::OnCancel(wxCommandEvent&)
1018{
1019        CState* pState = CContextManager::Get()->GetCurrentContext();
1020        if (!pState || pState->m_pCommandQueue->Idle())
1021                return;
1022
1023        if (wxMessageBoxEx(_("Really cancel current operation?"), _T("FileZilla"), wxYES_NO | wxICON_QUESTION) == wxYES)
1024        {
1025                pState->m_pCommandQueue->Cancel();
1026                pState->GetRecursiveOperationHandler()->StopRecursiveOperation();
1027        }
1028}
1029
1030#ifdef __WXMSW__
1031
1032BOOL CALLBACK FzEnumThreadWndProc(HWND hwnd, LPARAM lParam)
1033{
1034        // This function enumerates all dialogs and calls EndDialog for them
1035        TCHAR buffer[10];
1036        int c = GetClassName(hwnd, buffer, 9);
1037        // #32770 is the dialog window class.
1038        if (c && !_tcscmp(buffer, _T("#32770")))
1039        {
1040                *((bool*)lParam) = true;
1041                EndDialog(hwnd, IDCANCEL);
1042                return FALSE;
1043        }
1044
1045        return TRUE;
1046}
1047#endif //__WXMSW__
1048
1049
1050bool CMainFrame::CloseDialogsAndQuit(wxCloseEvent &event)
1051{
1052#ifndef __WXMAC__
1053        if (m_taskBarIcon)
1054        {
1055                delete m_taskBarIcon;
1056                m_taskBarIcon = 0;
1057                m_closeEvent = event.GetEventType();
1058                m_closeEventTimer.Start(1, true);
1059                return false;
1060        }
1061#endif
1062
1063        // We need to close all other top level windows on the stack before closing the main frame.
1064        // In other words, all open dialogs need to be closed.
1065        static int prev_size = 0;
1066
1067        int size = wxTopLevelWindows.size();
1068        static wxTopLevelWindow* pLast = 0;
1069        if (wxTopLevelWindows.size())
1070        {
1071                wxWindowList::reverse_iterator iter = wxTopLevelWindows.rbegin();
1072                wxTopLevelWindow* pTop = (wxTopLevelWindow*)(*iter);
1073                while (pTop != this && (size != prev_size || pLast != pTop))
1074                {
1075                        wxDialog* pDialog = wxDynamicCast(pTop, wxDialog);
1076                        if (pDialog)
1077                                pDialog->EndModal(wxID_CANCEL);
1078                        else
1079                        {
1080                                wxWindow* pParent = pTop->GetParent();
1081                                if (m_pQueuePane && pParent == m_pQueuePane)
1082                                {
1083                                        // It's the AUI frame manager hint window. Ignore it
1084                                        ++iter;
1085                                        if (iter == wxTopLevelWindows.rend())
1086                                                break;
1087                                        pTop = (wxTopLevelWindow*)(*iter);
1088                                        continue;
1089                                }
1090                                wxString title = pTop->GetTitle();
1091                                pTop->Destroy();
1092                        }
1093
1094                        prev_size = size;
1095                        pLast = pTop;
1096
1097                        m_closeEvent = event.GetEventType();
1098                        m_closeEventTimer.Start(1, true);
1099
1100                        return false;
1101                }
1102        }
1103
1104#ifdef __WXMSW__
1105        // wxMessageBoxEx does not use wxTopLevelWindow, close it too
1106        bool dialog = false;
1107        EnumThreadWindows(GetCurrentThreadId(), FzEnumThreadWndProc, (LPARAM)&dialog);
1108        if (dialog)
1109        {
1110                m_closeEvent = event.GetEventType();
1111                m_closeEventTimer.Start(1, true);
1112
1113                return false;
1114        }
1115#endif //__WXMSW__
1116
1117        // At this point all other top level windows should be closed.
1118        return true;
1119}
1120
1121
1122void CMainFrame::OnClose(wxCloseEvent &event)
1123{
1124        if (!m_bQuit) {
1125                static bool quit_confirmation_displayed = false;
1126                if (quit_confirmation_displayed && event.CanVeto()) {
1127                        event.Veto();
1128                        return;
1129                }
1130                if (event.CanVeto()) {
1131                        quit_confirmation_displayed = true;
1132
1133                        if (m_pQueueView && m_pQueueView->IsActive()) {
1134                                CConditionalDialog dlg(this, CConditionalDialog::confirmexit, CConditionalDialog::yesno);
1135                                dlg.SetTitle(_("Close FileZilla"));
1136
1137                                dlg.AddText(_("File transfers still in progress."));
1138                                dlg.AddText(_("Do you really want to close FileZilla?"));
1139
1140                                if (!dlg.Run()) {
1141                                        event.Veto();
1142                                        quit_confirmation_displayed = false;
1143                                        return;
1144                                }
1145                                if (m_bQuit)
1146                                        return;
1147                        }
1148
1149                        CEditHandler* pEditHandler = CEditHandler::Get();
1150                        if (pEditHandler) {
1151                                if (pEditHandler->GetFileCount(CEditHandler::remote, CEditHandler::edit) || pEditHandler->GetFileCount(CEditHandler::none, CEditHandler::upload) ||
1152                                        pEditHandler->GetFileCount(CEditHandler::none, CEditHandler::upload_and_remove) ||
1153                                        pEditHandler->GetFileCount(CEditHandler::none, CEditHandler::upload_and_remove_failed))
1154                                {
1155                                        CConditionalDialog dlg(this, CConditionalDialog::confirmexit_edit, CConditionalDialog::yesno);
1156                                        dlg.SetTitle(_("Close FileZilla"));
1157
1158                                        dlg.AddText(_("Some files are still being edited or need to be uploaded."));
1159                                        dlg.AddText(_("If you close FileZilla, your changes will be lost."));
1160                                        dlg.AddText(_("Do you really want to close FileZilla?"));
1161
1162                                        if (!dlg.Run()) {
1163                                                event.Veto();
1164                                                quit_confirmation_displayed = false;
1165                                                return;
1166                                        }
1167                                        if (m_bQuit)
1168                                                return;
1169                                }
1170                        }
1171                        quit_confirmation_displayed = false;
1172                }
1173
1174                if (m_pWindowStateManager) {
1175                        m_pWindowStateManager->Remember(OPTION_MAINWINDOW_POSITION);
1176                        delete m_pWindowStateManager;
1177                        m_pWindowStateManager = 0;
1178                }
1179
1180                RememberSplitterPositions();
1181
1182#ifdef __WXMAC__
1183                if (m_pToolBar)
1184                        COptions::Get()->SetOption(OPTION_TOOLBAR_HIDDEN, m_pToolBar->IsShown() ? 0 : 1);
1185#endif
1186                m_bQuit = true;
1187        }
1188
1189        Show(false);
1190        if (!CloseDialogsAndQuit(event))
1191                return;
1192
1193        // Getting deleted by wxWidgets
1194        for (int i = 0; i < 2; i++)
1195                m_pActivityLed[i] = 0;
1196        m_pStatusBar = 0;
1197        m_pMenuBar = 0;
1198        m_pToolBar = 0;
1199
1200        // We're no longer interested in these events
1201        delete m_pStateEventHandler;
1202        m_pStateEventHandler = 0;
1203
1204        if (m_pQueueView && !m_pQueueView->Quit()) {
1205                if( event.CanVeto() ) {
1206                        event.Veto();
1207                }
1208                return;
1209        }
1210
1211        CEditHandler* pEditHandler = CEditHandler::Get();
1212        if (pEditHandler) {
1213                pEditHandler->RemoveAll(true);
1214                pEditHandler->Release();
1215        }
1216
1217        bool res = true;
1218        const std::vector<CState*> *pStates = CContextManager::Get()->GetAllStates();
1219        for (CState* pState : *pStates) {
1220                if( pState->GetRecursiveOperationHandler() ) {
1221                        pState->GetRecursiveOperationHandler()->StopRecursiveOperation();
1222                }
1223
1224                if (pState->m_pCommandQueue) {
1225                        if (!pState->m_pCommandQueue->Quit())
1226                                res = false;
1227                }
1228        }
1229
1230        if (!res) {
1231                if( event.CanVeto() ) {
1232                        event.Veto();
1233                }
1234                return;
1235        }
1236
1237        CContextControl::_context_controls* controls = m_pContextControl ? m_pContextControl->GetCurrentControls() : 0;
1238        if (controls) {
1239                COptions::Get()->SetLastServer(controls->pState->GetLastServer());
1240                COptions::Get()->SetOption(OPTION_LASTSERVERPATH, controls->pState->GetLastServerPath().GetSafePath());
1241                COptions::Get()->SetOption(OPTION_LAST_CONNECTED_SITE, controls->site_bookmarks ? controls->site_bookmarks->path : wxString());
1242        }
1243
1244        for (std::vector<CState*>::const_iterator iter = pStates->begin(); iter != pStates->end(); ++iter) {
1245                CState *pState = *iter;
1246                pState->DestroyEngine();
1247        }
1248
1249        CSiteManager::ClearIdMap();
1250
1251        if (controls) {
1252                controls->pLocalListView->SaveColumnSettings(OPTION_LOCALFILELIST_COLUMN_WIDTHS, OPTION_LOCALFILELIST_COLUMN_SHOWN, OPTION_LOCALFILELIST_COLUMN_ORDER);
1253                controls->pRemoteListView->SaveColumnSettings(OPTION_REMOTEFILELIST_COLUMN_WIDTHS, OPTION_REMOTEFILELIST_COLUMN_SHOWN, OPTION_REMOTEFILELIST_COLUMN_ORDER);
1254        }
1255
1256        bool filters_toggled = CFilterManager::HasActiveFilters(true) && !CFilterManager::HasActiveFilters(false);
1257        COptions::Get()->SetOption(OPTION_FILTERTOGGLESTATE, filters_toggled ? 1 : 0);
1258
1259        Destroy();
1260}
1261
1262void CMainFrame::OnReconnect(wxCommandEvent &)
1263{
1264        CState* pState = CContextManager::Get()->GetCurrentContext();
1265        if (!pState)
1266                return;
1267
1268        if (pState->IsRemoteConnected() || !pState->IsRemoteIdle())
1269                return;
1270
1271        CServer server = pState->GetLastServer();
1272
1273        if (server.GetLogonType() == ASK) {
1274                if (!CLoginManager::Get().GetPassword(server, false))
1275                        return;
1276        }
1277
1278        CServerPath path = pState->GetLastServerPath();
1279        ConnectToServer(server, path, true);
1280}
1281
1282void CMainFrame::OnRefresh(wxCommandEvent &)
1283{
1284        CState* pState = CContextManager::Get()->GetCurrentContext();
1285        if (!pState)
1286                return;
1287
1288        pState->RefreshRemote();
1289        pState->RefreshLocal();
1290}
1291
1292void CMainFrame::OnTimer(wxTimerEvent& event)
1293{
1294        if (event.GetId() == m_closeEventTimer.GetId())
1295        {
1296                if (m_closeEvent == 0)
1297                        return;
1298
1299                // When we get idle event, a dialog's event loop has been left.
1300                // Now we can close the top level window on the stack.
1301                wxCloseEvent *evt = new wxCloseEvent(m_closeEvent);
1302                evt->SetCanVeto(false);
1303                QueueEvent(evt);
1304        }
1305#if FZ_MANUALUPDATECHECK
1306        else if( event.GetId() == update_dialog_timer_.GetId() ) {
1307                TriggerUpdateDialog();
1308        }
1309#endif
1310}
1311
1312void CMainFrame::OpenSiteManager(const CServer* pServer /*=0*/)
1313{
1314        CState* pState = CContextManager::Get()->GetCurrentContext();
1315        if (!pState)
1316                return;
1317
1318        CSiteManagerDialog dlg;
1319
1320        std::set<wxString> handled_paths;
1321        std::vector<CSiteManagerDialog::_connected_site> connected_sites;
1322
1323        if (pServer)
1324        {
1325                CSiteManagerDialog::_connected_site connected_site;
1326                connected_site.server = *pServer;
1327                connected_sites.push_back(connected_site);
1328        }
1329
1330        for (int i = 0; i < m_pContextControl->GetTabCount(); i++)
1331        {
1332                CContextControl::_context_controls *controls =  m_pContextControl->GetControlsFromTabIndex(i);
1333                if (!controls)
1334                        continue;
1335
1336                const wxString& path = controls->site_bookmarks->path;
1337                if (path.empty())
1338                        continue;
1339                if (handled_paths.find(path) != handled_paths.end())
1340                        continue;
1341
1342                CSiteManagerDialog::_connected_site connected_site;
1343                connected_site.old_path = path;
1344                connected_site.server = controls->pState->GetLastServer();
1345                connected_sites.push_back(connected_site);
1346                handled_paths.insert(path);
1347        }
1348
1349        if (!dlg.Create(this, &connected_sites, pServer))
1350                return;
1351
1352        int res = dlg.ShowModal();
1353        if (res == wxID_YES || res == wxID_OK)
1354        {
1355                // Update bookmark paths
1356                for (size_t j = 0; j < connected_sites.size(); j++)
1357                {
1358                        for (int i = 0; i < m_pContextControl->GetTabCount(); i++)
1359                        {
1360                                CContextControl::_context_controls *controls =  m_pContextControl->GetControlsFromTabIndex(i);
1361                                if (!controls)
1362                                        continue;
1363
1364                                if (connected_sites[j].old_path != controls->site_bookmarks->path)
1365                                        continue;
1366
1367                                controls->site_bookmarks->path = connected_sites[j].new_path;
1368
1369                                controls->site_bookmarks->bookmarks.clear();
1370                                CSiteManager::GetBookmarks(controls->site_bookmarks->path, controls->site_bookmarks->bookmarks);
1371
1372                                break;
1373                        }
1374                }
1375        }
1376
1377        if (res == wxID_YES)
1378        {
1379                CSiteManagerItemData_Site data;
1380                if (!dlg.GetServer(data))
1381                        return;
1382
1383                ConnectToSite(data);
1384        }
1385
1386        if (m_pMenuBar)
1387                m_pMenuBar->UpdateBookmarkMenu();
1388}
1389
1390void CMainFrame::OnSiteManager(wxCommandEvent& e)
1391{
1392#ifdef __WXMAC__
1393        if (wxGetKeyState(WXK_SHIFT) ||
1394                wxGetKeyState(WXK_ALT) ||
1395                wxGetKeyState(WXK_CONTROL))
1396        {
1397                OnSitemanagerDropdown(e);
1398                return;
1399        }
1400#endif
1401        (void)e;
1402        OpenSiteManager();
1403}
1404
1405void CMainFrame::UpdateActivityLed(int direction)
1406{
1407        if (m_pActivityLed[direction])
1408                m_pActivityLed[direction]->Ping();
1409}
1410
1411void CMainFrame::OnProcessQueue(wxCommandEvent& event)
1412{
1413        if (m_pQueueView)
1414                m_pQueueView->SetActive(event.IsChecked());
1415}
1416
1417void CMainFrame::OnMenuEditSettings(wxCommandEvent&)
1418{
1419        CSettingsDialog dlg(m_engineContext);
1420        if (!dlg.Create(this))
1421                return;
1422
1423        COptions* pOptions = COptions::Get();
1424
1425        wxString oldLang = pOptions->GetOption(OPTION_LANGUAGE);
1426
1427        int oldShowDebugMenu = pOptions->GetOptionVal(OPTION_DEBUG_MENU) != 0;
1428
1429        int res = dlg.ShowModal();
1430        if (res != wxID_OK) {
1431                return;
1432        }
1433
1434        wxString newLang = pOptions->GetOption(OPTION_LANGUAGE);
1435
1436        if (oldLang != newLang ||
1437                oldShowDebugMenu != pOptions->GetOptionVal(OPTION_DEBUG_MENU))
1438        {
1439                CreateMenus();
1440        }
1441        if (oldLang != newLang) {
1442                wxMessageBoxEx(_("FileZilla needs to be restarted for the language change to take effect."), _("Language changed"), wxICON_INFORMATION, this);
1443        }
1444
1445        CheckChangedSettings();
1446}
1447
1448void CMainFrame::OnToggleLogView(wxCommandEvent&)
1449{
1450        if (!m_pTopSplitter)
1451                return;
1452
1453        bool shown;
1454
1455        if (COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION) == 1) {
1456                if (!m_pQueueLogSplitter)
1457                        return;
1458                if (m_pQueueLogSplitter->IsSplit()) {
1459                        m_pQueueLogSplitter->Unsplit(m_pStatusView);
1460                        shown = false;
1461                }
1462                else if (m_pStatusView->IsShown()) {
1463                        m_pStatusView->Hide();
1464                        m_pBottomSplitter->Unsplit(m_pQueueLogSplitter);
1465                        shown = false;
1466                }
1467                else if (!m_pQueueLogSplitter->IsShown()) {
1468                        m_pQueueLogSplitter->Initialize(m_pStatusView);
1469                        m_pBottomSplitter->SplitHorizontally(m_pContextControl, m_pQueueLogSplitter);
1470                        shown = true;
1471                }
1472                else {
1473                        m_pQueueLogSplitter->SplitVertically(m_pQueuePane, m_pStatusView);
1474                        shown = true;
1475                }
1476        }
1477        else {
1478                if (m_pTopSplitter->IsSplit()) {
1479                        m_pTopSplitter->Unsplit(m_pStatusView);
1480                        shown = false;
1481                }
1482                else {
1483                        m_pTopSplitter->SplitHorizontally(m_pStatusView, m_pBottomSplitter);
1484                        shown = true;
1485                }
1486        }
1487
1488        if (COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION) != 2)
1489                COptions::Get()->SetOption(OPTION_SHOW_MESSAGELOG, shown);
1490}
1491
1492void CMainFrame::OnToggleDirectoryTreeView(wxCommandEvent& event)
1493{
1494        if (!m_pContextControl)
1495                return;
1496
1497        CContextControl::_context_controls* controls = m_pContextControl->GetCurrentControls();
1498        if (!controls)
1499                return;
1500
1501        bool const local = event.GetId() == XRCID("ID_TOOLBAR_LOCALTREEVIEW") || event.GetId() == XRCID("ID_VIEW_LOCALTREE");
1502        CSplitterWindowEx* splitter = local ? controls->pLocalSplitter : controls->pRemoteSplitter;
1503        bool show = !splitter->IsSplit();
1504        ShowDirectoryTree(local, show);
1505}
1506
1507void CMainFrame::ShowDirectoryTree(bool local, bool show)
1508{
1509        if (!m_pContextControl)
1510                return;
1511
1512        const int layout = COptions::Get()->GetOptionVal(OPTION_FILEPANE_LAYOUT);
1513        const int swap = COptions::Get()->GetOptionVal(OPTION_FILEPANE_SWAP);
1514        for (int i = 0; i < m_pContextControl->GetTabCount(); ++i) {
1515                CContextControl::_context_controls* controls = m_pContextControl->GetControlsFromTabIndex(i);
1516                if (!controls)
1517                        continue;
1518
1519                CSplitterWindowEx* splitter = local ? controls->pLocalSplitter : controls->pRemoteSplitter;
1520                CView* tree = local ? controls->pLocalTreeViewPanel : controls->pRemoteTreeViewPanel;
1521                CView* list = local ? controls->pLocalListViewPanel : controls->pRemoteListViewPanel;
1522
1523                if (show && !splitter->IsSplit()) {
1524                        tree->SetHeader(list->DetachHeader());
1525
1526                        if (layout == 3 && swap)
1527                                splitter->SplitVertically(list, tree);
1528                        else if (layout)
1529                                splitter->SplitVertically(tree, list);
1530                        else
1531                                splitter->SplitHorizontally(tree, list);
1532                }
1533                else if (!show && splitter->IsSplit()) {
1534                        list->SetHeader(tree->DetachHeader());
1535                        splitter->Unsplit(tree);
1536                }
1537        }
1538
1539        COptions::Get()->SetOption(local ? OPTION_SHOW_TREE_LOCAL : OPTION_SHOW_TREE_REMOTE, show);
1540}
1541
1542void CMainFrame::OnToggleQueueView(wxCommandEvent&)
1543{
1544        if (!m_pBottomSplitter)
1545                return;
1546
1547        bool shown;
1548        if (COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION) == 1)
1549        {
1550                if (!m_pQueueLogSplitter)
1551                        return;
1552                if (m_pQueueLogSplitter->IsSplit())
1553                {
1554                        m_pQueueLogSplitter->Unsplit(m_pQueuePane);
1555                        shown = false;
1556                }
1557                else if (m_pQueuePane->IsShown())
1558                {
1559                        m_pQueuePane->Hide();
1560                        m_pBottomSplitter->Unsplit(m_pQueueLogSplitter);
1561                        shown = false;
1562                }
1563                else if (!m_pQueueLogSplitter->IsShown())
1564                {
1565                        m_pQueueLogSplitter->Initialize(m_pQueuePane);
1566                        m_pBottomSplitter->SplitHorizontally(m_pContextControl, m_pQueueLogSplitter);
1567                        shown = true;
1568                }
1569                else
1570                {
1571                        m_pQueueLogSplitter->SplitVertically(m_pQueuePane, m_pStatusView);
1572                        shown = true;
1573                }
1574        }
1575        else
1576        {
1577                if (m_pBottomSplitter->IsSplit())
1578                        m_pBottomSplitter->Unsplit(m_pQueueLogSplitter);
1579                else
1580                {
1581                        m_pQueueLogSplitter->Initialize(m_pQueuePane);
1582                        m_pBottomSplitter->SplitHorizontally(m_pContextControl, m_pQueueLogSplitter);
1583                }
1584                shown = m_pBottomSplitter->IsSplit();
1585        }
1586
1587        COptions::Get()->SetOption(OPTION_SHOW_QUEUE, shown);
1588}
1589
1590void CMainFrame::OnMenuHelpAbout(wxCommandEvent&)
1591{
1592        CAboutDialog dlg;
1593        if (!dlg.Create(this))
1594                return;
1595
1596        dlg.ShowModal();
1597}
1598
1599void CMainFrame::OnFilter(wxCommandEvent& event)
1600{
1601        if (wxGetKeyState(WXK_SHIFT)) {
1602                OnFilterRightclicked(event);
1603                return;
1604        }
1605
1606        bool const oldActive = CFilterManager::HasActiveFilters();
1607
1608        CFilterDialog dlg;
1609        dlg.Create(this);
1610        dlg.ShowModal();
1611
1612        if (oldActive == CFilterManager::HasActiveFilters() && m_pToolBar) {
1613                // Restore state
1614                m_pToolBar->ToggleTool(XRCID("ID_TOOLBAR_FILTER"), oldActive);
1615        }
1616}
1617
1618#if FZ_MANUALUPDATECHECK
1619void CMainFrame::OnCheckForUpdates(wxCommandEvent&)
1620{
1621        if (!m_pUpdater) {
1622                return;
1623        }
1624
1625        update_dialog_timer_.Stop();
1626        CUpdateDialog dlg(this, *m_pUpdater);
1627        dlg.ShowModal();
1628        update_dialog_timer_.Stop();
1629}
1630
1631void CMainFrame::UpdaterStateChanged(UpdaterState s, build const& v)
1632{
1633#if FZ_AUTOUPDATECHECK
1634        if( !m_pMenuBar ) {
1635                return;
1636        }
1637
1638        if( s == UpdaterState::idle ) {
1639                wxMenu* m = 0;
1640                wxMenuItem* pItem = m_pMenuBar->FindItem(GetAvailableUpdateMenuId(), &m);
1641                if( pItem && m ) {
1642                        for( size_t i = 0; i != m_pMenuBar->GetMenuCount(); ++i ) {
1643                                if( m_pMenuBar->GetMenu(i) == m ) {
1644                                        m_pMenuBar->Remove(i);
1645                                        delete m;
1646                                        break;
1647                                }
1648                        }
1649                }
1650                return;
1651        }
1652        else if( s != UpdaterState::newversion && s != UpdaterState::newversion_ready ) {
1653                return;
1654        }
1655        else if( v.version_.empty() ) {
1656                return;
1657        }
1658
1659        wxString const name = wxString::Format(_("&Version %s"), v.version_);
1660
1661        wxMenuItem* pItem = m_pMenuBar->FindItem(GetAvailableUpdateMenuId());
1662        if( !pItem ) {
1663                wxMenu* pMenu = new wxMenu();
1664                pMenu->Append(GetAvailableUpdateMenuId(), name);
1665                m_pMenuBar->Append(pMenu, _("&New version available!"));
1666
1667                if( !update_dialog_timer_.IsRunning() ) {
1668                        update_dialog_timer_.Start(1, true);
1669                }
1670        }
1671        else {
1672                pItem->SetItemLabel(name);
1673        }
1674#endif
1675}
1676
1677void CMainFrame::TriggerUpdateDialog()
1678{
1679        if( CUpdateDialog::IsRunning() ) {
1680                return;
1681        }
1682
1683        if( !wxDialogEx::CanShowPopupDialog() ) {
1684                update_dialog_timer_.Start( 1000, true );
1685                return;
1686        }
1687
1688        CUpdateDialog dlg(this, *m_pUpdater);
1689        dlg.ShowModal();
1690
1691        // In case the timer was started while the dialog was up.
1692        update_dialog_timer_.Stop();
1693}
1694#endif
1695
1696void CMainFrame::UpdateLayout()
1697{
1698        int const layout = COptions::Get()->GetOptionVal(OPTION_FILEPANE_LAYOUT);
1699        int const swap = COptions::Get()->GetOptionVal(OPTION_FILEPANE_SWAP);
1700
1701        int const messagelog_position = COptions::Get()->GetOptionVal(OPTION_MESSAGELOG_POSITION);
1702
1703        // First handle changes in message log position as it can make size of the other panes change
1704        {
1705                bool shown = m_pStatusView->IsShown();
1706                wxWindow* parent = m_pStatusView->GetParent();
1707
1708                bool changed;
1709                if (parent == m_pTopSplitter && messagelog_position != 0) {
1710                        if (shown)
1711                                m_pTopSplitter->Unsplit(m_pStatusView);
1712                        changed = true;
1713                }
1714                else if (parent == m_pQueueLogSplitter && messagelog_position != 1) {
1715                        if (shown) {
1716                                if (m_pQueueLogSplitter->IsSplit())
1717                                        m_pQueueLogSplitter->Unsplit(m_pStatusView);
1718                                else
1719                                        m_pBottomSplitter->Unsplit(m_pQueueLogSplitter);
1720                        }
1721                        changed = true;
1722                }
1723                else if (parent != m_pTopSplitter && parent != m_pQueueLogSplitter && messagelog_position != 2) {
1724                        m_pQueuePane->RemovePage(3);
1725                        changed = true;
1726                        shown = true;
1727                }
1728                else
1729                        changed = false;
1730
1731                if (changed) {
1732                        switch (messagelog_position) {
1733                        default:
1734                                m_pStatusView->Reparent(m_pTopSplitter);
1735                                if (shown)
1736                                        m_pTopSplitter->SplitHorizontally(m_pStatusView, m_pBottomSplitter);
1737                                break;
1738                        case 1:
1739                                m_pStatusView->Reparent(m_pQueueLogSplitter);
1740                                if (shown)
1741                                {
1742                                        if (m_pQueueLogSplitter->IsShown())
1743                                                m_pQueueLogSplitter->SplitVertically(m_pQueuePane, m_pStatusView);
1744                                        else
1745                                        {
1746                                                m_pQueueLogSplitter->Initialize(m_pStatusView);
1747                                                m_pBottomSplitter->SplitHorizontally(m_pContextControl, m_pQueueLogSplitter);
1748                                        }
1749                                }
1750                                break;
1751                        case 2:
1752                                m_pQueuePane->AddPage(m_pStatusView, _("Message log"));
1753                                break;
1754                        }
1755                }
1756        }
1757
1758        // Now the other panes
1759        for (int i = 0; i < m_pContextControl->GetTabCount(); i++)
1760        {
1761                struct CContextControl::_context_controls *controls = m_pContextControl->GetControlsFromTabIndex(i);
1762                if (!controls)
1763                        continue;
1764
1765                int mode;
1766                if (!layout || layout == 2 || layout == 3)
1767                        mode = wxSPLIT_VERTICAL;
1768                else
1769                        mode = wxSPLIT_HORIZONTAL;
1770
1771                int isMode = controls->pViewSplitter->GetSplitMode();
1772
1773                int isSwap = controls->pViewSplitter->GetWindow1() == controls->pRemoteSplitter ? 1 : 0;
1774
1775                if (mode != isMode || swap != isSwap)
1776                {
1777                        controls->pViewSplitter->Unsplit();
1778                        if (mode == wxSPLIT_VERTICAL)
1779                        {
1780                                if (swap)
1781                                        controls->pViewSplitter->SplitVertically(controls->pRemoteSplitter, controls->pLocalSplitter);
1782                                else
1783                                        controls->pViewSplitter->SplitVertically(controls->pLocalSplitter, controls->pRemoteSplitter);
1784                        }
1785                        else
1786                        {
1787                                if (swap)
1788                                        controls->pViewSplitter->SplitHorizontally(controls->pRemoteSplitter, controls->pLocalSplitter);
1789                                else
1790                                        controls->pViewSplitter->SplitHorizontally(controls->pLocalSplitter, controls->pRemoteSplitter);
1791                        }
1792                }
1793
1794                if (controls->pLocalSplitter->IsSplit())
1795                {
1796                        if (!layout)
1797                                mode = wxSPLIT_HORIZONTAL;
1798                        else
1799                                mode = wxSPLIT_VERTICAL;
1800
1801                        wxWindow* pFirst;
1802                        wxWindow* pSecond;
1803                        if (layout == 3 && swap)
1804                        {
1805                                pFirst = controls->pLocalListViewPanel;
1806                                pSecond = controls->pLocalTreeViewPanel;
1807                        }
1808                        else
1809                        {
1810                                pFirst = controls->pLocalTreeViewPanel;
1811                                pSecond = controls->pLocalListViewPanel;
1812                        }
1813
1814                        if (mode != controls->pLocalSplitter->GetSplitMode() || pFirst != controls->pLocalSplitter->GetWindow1())
1815                        {
1816                                controls->pLocalSplitter->Unsplit();
1817                                if (mode == wxSPLIT_VERTICAL)
1818                                        controls->pLocalSplitter->SplitVertically(pFirst, pSecond);
1819                                else
1820                                        controls->pLocalSplitter->SplitHorizontally(pFirst, pSecond);
1821                        }
1822                }
1823
1824                if (controls->pRemoteSplitter->IsSplit())
1825                {
1826                        if (!layout)
1827                                mode = wxSPLIT_HORIZONTAL;
1828                        else
1829                                mode = wxSPLIT_VERTICAL;
1830
1831                        wxWindow* pFirst;
1832                        wxWindow* pSecond;
1833                        if (layout == 3 && !swap)
1834                        {
1835                                pFirst = controls->pRemoteListViewPanel;
1836                                pSecond = controls->pRemoteTreeViewPanel;
1837                        }
1838                        else
1839                        {
1840                                pFirst = controls->pRemoteTreeViewPanel;
1841                                pSecond = controls->pRemoteListViewPanel;
1842                        }
1843
1844                        if (mode != controls->pRemoteSplitter->GetSplitMode() || pFirst != controls->pRemoteSplitter->GetWindow1())
1845                        {
1846                                controls->pRemoteSplitter->Unsplit();
1847                                if (mode == wxSPLIT_VERTICAL)
1848                                        controls->pRemoteSplitter->SplitVertically(pFirst, pSecond);
1849                                else
1850                                        controls->pRemoteSplitter->SplitHorizontally(pFirst, pSecond);
1851                        }
1852                }
1853
1854                if (layout == 3)
1855                {
1856                        if (!swap)
1857                        {
1858                                controls->pRemoteSplitter->SetSashGravity(1.0);
1859                                controls->pLocalSplitter->SetSashGravity(0.0);
1860                        }
1861                        else
1862                        {
1863                                controls->pLocalSplitter->SetSashGravity(1.0);
1864                                controls->pRemoteSplitter->SetSashGravity(0.0);
1865                        }
1866                }
1867                else
1868                {
1869                        controls->pLocalSplitter->SetSashGravity(0.0);
1870                        controls->pRemoteSplitter->SetSashGravity(0.0);
1871                }
1872        }
1873}
1874
1875void CMainFrame::OnSitemanagerDropdown(wxCommandEvent& event)
1876{
1877        if (!m_pToolBar)
1878                return;
1879
1880        std::unique_ptr<wxMenu> pMenu = CSiteManager::GetSitesMenu();
1881        if (pMenu) {
1882                ShowDropdownMenu(pMenu.release(), m_pToolBar, event);
1883        }
1884}
1885
1886bool CMainFrame::ConnectToSite(CSiteManagerItemData_Site & data, bool newTab)
1887{
1888        if (data.m_server.GetLogonType() == ASK ||
1889                (data.m_server.GetLogonType() == INTERACTIVE && data.m_server.GetUser().empty()))
1890        {
1891                if (!CLoginManager::Get().GetPassword(data.m_server, false, data.m_server.GetName()))
1892                        return false;
1893        }
1894
1895        if (newTab)
1896                m_pContextControl->CreateTab();
1897
1898        if (!ConnectToServer(data.m_server, data.m_remoteDir))
1899                return false;
1900
1901        CState *pState = CContextManager::Get()->GetCurrentContext();
1902        if (pState) {
1903                if (!data.m_localDir.empty()) {
1904                        bool set = pState->SetLocalDir(data.m_localDir, 0, false);
1905
1906                        if (set && data.m_sync) {
1907                                wxASSERT(!data.m_remoteDir.empty());
1908                                pState->SetSyncBrowse(true, data.m_remoteDir);
1909                        }
1910                }
1911
1912                if (data.m_comparison && pState->GetComparisonManager()) {
1913                        pState->GetComparisonManager()->CompareListings();
1914                }
1915        }
1916
1917        SetBookmarksFromPath(data.m_path);
1918        if (m_pMenuBar)
1919                m_pMenuBar->UpdateBookmarkMenu();
1920
1921        return true;
1922}
1923
1924void CMainFrame::CheckChangedSettings()
1925{
1926        m_pAsyncRequestQueue->RecheckDefaults();
1927
1928        CAutoAsciiFiles::SettingsChanged();
1929
1930#if FZ_MANUALUPDATECHECK
1931        m_pUpdater->Init();
1932#endif
1933}
1934
1935void CMainFrame::ConnectNavigationHandler(wxEvtHandler* handler)
1936{
1937        if (!handler)
1938                return;
1939
1940        handler->Connect(wxEVT_NAVIGATION_KEY, wxNavigationKeyEventHandler(CMainFrame::OnNavigationKeyEvent), 0, this);
1941}
1942
1943void CMainFrame::OnNavigationKeyEvent(wxNavigationKeyEvent& event)
1944{
1945        if (wxGetKeyState(WXK_CONTROL) && event.IsFromTab()) {
1946                if (m_pContextControl)
1947                        m_pContextControl->AdvanceTab(event.GetDirection());
1948                return;
1949        }
1950
1951        event.Skip();
1952}
1953
1954void CMainFrame::OnChar(wxKeyEvent& event)
1955{
1956        if (event.GetKeyCode() != WXK_F6) {
1957                event.Skip();
1958                return;
1959        }
1960
1961        // Jump between quickconnect bar and view headers
1962
1963        std::list<wxWindow*> windowOrder;
1964        if (m_pQuickconnectBar)
1965                windowOrder.push_back(m_pQuickconnectBar);
1966        CContextControl::_context_controls* controls = m_pContextControl->GetCurrentControls();
1967        if (controls) {
1968                windowOrder.push_back(controls->pLocalViewHeader);
1969                windowOrder.push_back(controls->pRemoteViewHeader);
1970        }
1971
1972        wxWindow* focused = FindFocus();
1973
1974        bool skipFirst = false;
1975        std::list<wxWindow*>::iterator iter;
1976        if (!focused) {
1977                iter = windowOrder.begin();
1978                skipFirst = false;
1979        }
1980        else {
1981                wxWindow *parent = focused->GetParent();
1982                for (iter = windowOrder.begin(); iter != windowOrder.end(); ++iter) {
1983                        if (*iter == focused || *iter == parent) {
1984                                skipFirst = true;
1985                                break;
1986                        }
1987                }
1988                if (iter == windowOrder.end()) {
1989                        iter = windowOrder.begin();
1990                        skipFirst = false;
1991                }
1992        }
1993
1994        FocusNextEnabled(windowOrder, iter, skipFirst, !event.ShiftDown());
1995}
1996
1997void CMainFrame::FocusNextEnabled(std::list<wxWindow*>& windowOrder, std::list<wxWindow*>::iterator iter, bool skipFirst, bool forward)
1998{
1999        std::list<wxWindow*>::iterator start = iter;
2000
2001        while (skipFirst || !(*iter)->IsShownOnScreen() || !(*iter)->IsEnabled()) {
2002                skipFirst = false;
2003                if (forward) {
2004                        ++iter;
2005                        if (iter == windowOrder.end())
2006                                iter = windowOrder.begin();
2007                }
2008                else {
2009                        if (iter == windowOrder.begin())
2010                                iter = windowOrder.end();
2011                        --iter;
2012                }
2013
2014                if (iter == start) {
2015                        wxBell();
2016                        return;
2017                }
2018        }
2019
2020        (*iter)->SetFocus();
2021}
2022
2023void CMainFrame::RememberSplitterPositions()
2024{
2025        CContextControl::_context_controls* controls = m_pContextControl ? m_pContextControl->GetCurrentControls() : 0;
2026        if (!controls)
2027                return;
2028
2029        wxString posString;
2030
2031        // top_pos
2032        posString += wxString::Format(_T("%d "), m_pTopSplitter->GetSashPosition());
2033
2034        // bottom_height
2035        posString += wxString::Format(_T("%d "), m_pBottomSplitter->GetSashPosition());
2036
2037        // view_pos
2038        posString += wxString::Format(_T("%d "), (int)(controls->pViewSplitter->GetRelativeSashPosition() * 1000000000));
2039
2040        // local_pos
2041        posString += wxString::Format(_T("%d "), controls->pLocalSplitter->GetSashPosition());
2042
2043        // remote_pos
2044        posString += wxString::Format(_T("%d "), controls->pRemoteSplitter->GetSashPosition());
2045
2046        // queuelog splitter
2047        // Note that we cannot use %f, it is locale-dependent
2048        // m_lastQueueLogSplitterPos is a value between 0 and 1
2049        posString += wxString::Format(_T("%d"), (int)(m_pQueueLogSplitter->GetRelativeSashPosition() * 1000000000));
2050
2051        COptions::Get()->SetOption(OPTION_MAINWINDOW_SPLITTER_POSITION, posString);
2052}
2053
2054bool CMainFrame::RestoreSplitterPositions()
2055{
2056        if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_ALT) && wxGetKeyState(WXK_CONTROL))
2057                return false;
2058
2059        // top_pos bottom_height view_pos view_height_width local_pos remote_pos
2060        wxString posString = COptions::Get()->GetOption(OPTION_MAINWINDOW_SPLITTER_POSITION);
2061        wxStringTokenizer tokens(posString, _T(" "));
2062        int count = tokens.CountTokens();
2063        if (count < 6)
2064                return false;
2065
2066        long * aPosValues = new long[count];
2067        for (int i = 0; i < count; ++i) {
2068                wxString token = tokens.GetNextToken();
2069                if (!token.ToLong(aPosValues + i)) {
2070                        delete [] aPosValues;
2071                        return false;
2072                }
2073        }
2074
2075        m_pTopSplitter->SetSashPosition(aPosValues[0]);
2076
2077        m_pBottomSplitter->SetSashPosition(aPosValues[1]);
2078
2079        CContextControl::_context_controls* controls = m_pContextControl ? m_pContextControl->GetCurrentControls() : 0;
2080        if (!controls) {
2081                delete [] aPosValues;
2082                return false;
2083        }
2084
2085        double pos = (double)aPosValues[2] / 1000000000;
2086        if (pos >= 0 && pos <= 1)
2087                controls->pViewSplitter->SetRelativeSashPosition(pos);
2088
2089        controls->pLocalSplitter->SetSashPosition(aPosValues[3]);
2090        controls->pRemoteSplitter->SetSashPosition(aPosValues[4]);
2091
2092        pos = (double)aPosValues[5] / 1000000000;
2093        if (pos >= 0 && pos <= 1)
2094                m_pQueueLogSplitter->SetRelativeSashPosition(pos);
2095        delete [] aPosValues;
2096
2097        return true;
2098}
2099
2100void CMainFrame::SetDefaultSplitterPositions()
2101{
2102        m_pTopSplitter->SetSashPosition(97);
2103
2104        wxSize size = m_pBottomSplitter->GetClientSize();
2105        int h = size.GetHeight() - 135;
2106        if (h < 50)
2107                h = 50;
2108        m_pBottomSplitter->SetSashPosition(h);
2109
2110        m_pQueueLogSplitter->SetSashPosition(0);
2111
2112        CContextControl::_context_controls* controls = m_pContextControl ? m_pContextControl->GetCurrentControls() : 0;
2113        if (controls) {
2114                controls->pViewSplitter->SetSashPosition(0);
2115                controls->pLocalSplitter->SetRelativeSashPosition(0.4);
2116                controls->pRemoteSplitter->SetRelativeSashPosition(0.4);
2117        }
2118}
2119
2120void CMainFrame::OnActivate(wxActivateEvent& event)
2121{
2122        // According to the wx docs we should do this
2123        event.Skip();
2124
2125        if (!event.GetActive())
2126                return;
2127
2128#ifdef __WXMAC__
2129        // wxMac looses focus information if the window becomes inactive.
2130        // Restore focus to the previously focused child, otherwise focus ends up
2131        // in the quickconnect bar.
2132        // Go via ID of the last focused child to avoid issues with window lifetime.
2133        if (m_lastFocusedChild != -1)
2134                m_winLastFocused = FindWindow(m_lastFocusedChild);
2135#endif
2136
2137        CEditHandler* pEditHandler = CEditHandler::Get();
2138        if (pEditHandler)
2139                pEditHandler->CheckForModifications(true);
2140
2141        if (m_pAsyncRequestQueue)
2142                m_pAsyncRequestQueue->TriggerProcessing();
2143}
2144
2145void CMainFrame::OnToolbarComparison(wxCommandEvent&)
2146{
2147        CState* pState = CContextManager::Get()->GetCurrentContext();
2148        if (!pState)
2149                return;
2150
2151        CComparisonManager* pComparisonManager = pState->GetComparisonManager();
2152        if (pComparisonManager->IsComparing())
2153        {
2154                pComparisonManager->ExitComparisonMode();
2155                return;
2156        }
2157
2158        if (!COptions::Get()->GetOptionVal(OPTION_FILEPANE_LAYOUT)) {
2159                CContextControl::_context_controls* controls = m_pContextControl->GetCurrentControls();
2160                if (!controls)
2161                        return;
2162
2163                if ((controls->pLocalSplitter->IsSplit() && !controls->pRemoteSplitter->IsSplit()) ||
2164                        (!controls->pLocalSplitter->IsSplit() && controls->pRemoteSplitter->IsSplit()))
2165                {
2166                        CConditionalDialog dlg(this, CConditionalDialog::compare_treeviewmismatch, CConditionalDialog::yesno);
2167                        dlg.SetTitle(_("Directory comparison"));
2168                        dlg.AddText(_("To compare directories, both file lists have to be aligned."));
2169                        dlg.AddText(_("To do this, the directory trees need to be both shown or both hidden."));
2170                        dlg.AddText(_("Show both directory trees and continue comparing?"));
2171                        if (!dlg.Run()) {
2172                                // Needed to restore non-toggle state of button
2173                                pState->NotifyHandlers(STATECHANGE_COMPARISON);
2174                                return;
2175                        }
2176
2177                        ShowDirectoryTree(true, true);
2178                        ShowDirectoryTree(false, true);
2179                }
2180
2181                int pos = (controls->pLocalSplitter->GetSashPosition() + controls->pRemoteSplitter->GetSashPosition()) / 2;
2182                controls->pLocalSplitter->SetSashPosition(pos);
2183                controls->pRemoteSplitter->SetSashPosition(pos);
2184        }
2185
2186        pComparisonManager->CompareListings();
2187}
2188
2189void CMainFrame::OnToolbarComparisonDropdown(wxCommandEvent& event)
2190{
2191        if (!m_pToolBar)
2192                return;
2193
2194        wxMenu* pMenu = wxXmlResource::Get()->LoadMenu(_T("ID_MENU_TOOLBAR_COMPARISON_DROPDOWN"));
2195        if (!pMenu)
2196                return;
2197
2198        CState* pState = CContextManager::Get()->GetCurrentContext();
2199        if (!pState)
2200                return;
2201
2202        CComparisonManager* pComparisonManager = pState->GetComparisonManager();
2203        pMenu->FindItem(XRCID("ID_TOOLBAR_COMPARISON"))->Check(pComparisonManager->IsComparing());
2204
2205        const int mode = COptions::Get()->GetOptionVal(OPTION_COMPARISONMODE);
2206        if (mode == 0)
2207                pMenu->FindItem(XRCID("ID_COMPARE_SIZE"))->Check();
2208        else
2209                pMenu->FindItem(XRCID("ID_COMPARE_DATE"))->Check();
2210
2211        pMenu->Check(XRCID("ID_COMPARE_HIDEIDENTICAL"), COptions::Get()->GetOptionVal(OPTION_COMPARE_HIDEIDENTICAL) != 0);
2212
2213        ShowDropdownMenu(pMenu, m_pToolBar, event);
2214}
2215
2216void CMainFrame::ShowDropdownMenu(wxMenu* pMenu, wxToolBar* pToolBar, wxCommandEvent& event)
2217{
2218#ifdef EVT_TOOL_DROPDOWN
2219        if (event.GetEventType() == wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED)
2220        {
2221                pToolBar->SetDropdownMenu(event.GetId(), pMenu);
2222                event.Skip();
2223        }
2224        else
2225#endif
2226        {
2227#ifdef __WXMSW__
2228                RECT r;
2229                if (::SendMessage((HWND)pToolBar->GetHandle(), TB_GETITEMRECT, pToolBar->GetToolPos(event.GetId()), (LPARAM)&r))
2230                        pToolBar->PopupMenu(pMenu, r.left, r.bottom);
2231                else
2232#endif
2233                        pToolBar->PopupMenu(pMenu);
2234
2235                delete pMenu;
2236        }
2237}
2238
2239void CMainFrame::OnDropdownComparisonMode(wxCommandEvent& event)
2240{
2241        CState* pState = CContextManager::Get()->GetCurrentContext();
2242        if (!pState)
2243                return;
2244
2245        int old_mode = COptions::Get()->GetOptionVal(OPTION_COMPARISONMODE);
2246        int new_mode = (event.GetId() == XRCID("ID_COMPARE_SIZE")) ? 0 : 1;
2247        COptions::Get()->SetOption(OPTION_COMPARISONMODE, new_mode);
2248
2249        CComparisonManager* pComparisonManager = pState->GetComparisonManager();
2250        if (old_mode != new_mode && pComparisonManager && pComparisonManager->IsComparing())
2251                pComparisonManager->CompareListings();
2252}
2253
2254void CMainFrame::OnDropdownComparisonHide(wxCommandEvent&)
2255{
2256        CState* pState = CContextManager::Get()->GetCurrentContext();
2257        if (!pState)
2258                return;
2259
2260        bool old_mode = COptions::Get()->GetOptionVal(OPTION_COMPARE_HIDEIDENTICAL) != 0;
2261        COptions::Get()->SetOption(OPTION_COMPARE_HIDEIDENTICAL, old_mode ? 0 : 1);
2262
2263        CComparisonManager* pComparisonManager = pState->GetComparisonManager();
2264        if (pComparisonManager && pComparisonManager->IsComparing())
2265                pComparisonManager->CompareListings();
2266}
2267
2268void CMainFrame::ProcessCommandLine()
2269{
2270        const CCommandLine* pCommandLine = wxGetApp().GetCommandLine();
2271        if (!pCommandLine)
2272                return;
2273
2274        wxString local;
2275        if ((local = pCommandLine->GetOption(CCommandLine::local)) != _T(""))
2276        {
2277
2278                if (!wxDir::Exists(local))
2279                {
2280                        wxString str = _("Path not found:");
2281                        str += _T("\n") + local;
2282                        wxMessageBoxEx(str, _("Syntax error in command line"));
2283                        return;
2284                }
2285
2286                CState *pState = CContextManager::Get()->GetCurrentContext();
2287                if (!pState)
2288                        return;
2289
2290                pState->SetLocalDir(local);
2291        }
2292
2293        wxString site;
2294        if (pCommandLine->HasSwitch(CCommandLine::sitemanager)) {
2295                if (COptions::Get()->GetOptionVal(OPTION_INTERFACE_SITEMANAGER_ON_STARTUP) == 0) {
2296                        Show();
2297                        OpenSiteManager();
2298                }
2299        }
2300        else if ((site = pCommandLine->GetOption(CCommandLine::site)) != _T("")) {
2301                std::unique_ptr<CSiteManagerItemData_Site> pData = CSiteManager::GetSiteByPath(site);
2302
2303                if (pData) {
2304                        ConnectToSite(*pData);
2305                }
2306        }
2307
2308        wxString param = pCommandLine->GetParameter();
2309        if (!param.empty()) {
2310                wxString error;
2311
2312                CServer server;
2313
2314                wxString logontype = pCommandLine->GetOption(CCommandLine::logontype);
2315                if (logontype == _T("ask"))
2316                        server.SetLogonType(ASK);
2317                else if (logontype == _T("interactive"))
2318                        server.SetLogonType(INTERACTIVE);
2319
2320                CServerPath path;
2321                if (!server.ParseUrl(param, 0, _T(""), _T(""), error, path)) {
2322                        wxString str = _("Parameter not a valid URL");
2323                        str += _T("\n") + error;
2324                        wxMessageBoxEx(error, _("Syntax error in command line"));
2325                }
2326
2327                if (COptions::Get()->GetOptionVal(OPTION_DEFAULT_KIOSKMODE) && server.GetLogonType() == NORMAL) {
2328                        server.SetLogonType(ASK);
2329                        CLoginManager::Get().RememberPassword(server);
2330                }
2331                else if (server.GetLogonType() == ASK ||
2332                        (server.GetLogonType() == INTERACTIVE && server.GetUser().empty()))
2333                {
2334                        if (!CLoginManager::Get().GetPassword(server, false))
2335                                return;
2336                }
2337
2338                CState* pState = CContextManager::Get()->GetCurrentContext();
2339                if (!pState)
2340                        return;
2341
2342                ConnectToServer(server, path);
2343        }
2344}
2345
2346void CMainFrame::OnFilterRightclicked(wxCommandEvent&)
2347{
2348        const bool active = CFilterManager::HasActiveFilters();
2349
2350        CFilterManager::ToggleFilters();
2351
2352        if (active == CFilterManager::HasActiveFilters())
2353                return;
2354
2355        CContextManager::Get()->NotifyAllHandlers(STATECHANGE_APPLYFILTER);
2356}
2357
2358#ifdef __WXMSW__
2359WXLRESULT CMainFrame::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
2360{
2361        if (nMsg == WM_DEVICECHANGE)
2362        {
2363                // Let tree control handle device change message
2364                // They get sent by Windows on adding or removing drive
2365                // letters
2366
2367                if (!m_pContextControl)
2368                        return 0;
2369
2370                for (int i = 0; i < m_pContextControl->GetTabCount(); i++)
2371                {
2372                        CContextControl::_context_controls* controls = m_pContextControl->GetControlsFromTabIndex(i);
2373                        if (controls && controls->pLocalTreeView)
2374                                controls->pLocalTreeView->OnDevicechange(wParam, lParam);
2375                }
2376                return 0;
2377        }
2378        else if (nMsg == WM_DISPLAYCHANGE)
2379        {
2380                // wxDisplay caches the display configuration and does not
2381                // reset it if the display configuration changes.
2382                // wxDisplay uses this strange factory design pattern and uses a wxModule
2383                // to delete the factory on program shutdown.
2384                //
2385                // To reset the factory manually in response to WM_DISPLAYCHANGE,
2386                // create another instance of the module and call its Exit() member.
2387                // After that, the next call to a wxDisplay will create a new factory and
2388                // get the new display layout from Windows.
2389                //
2390                // Note: Both the factory pattern as well as the dynamic object system
2391                //         are perfect example of bad design.
2392                //
2393                wxModule* pDisplayModule = (wxModule*)wxCreateDynamicObject(_T("wxDisplayModule"));
2394                if (pDisplayModule)
2395                {
2396                        pDisplayModule->Exit();
2397                        delete pDisplayModule;
2398                }
2399        }
2400        return wxFrame::MSWWindowProc(nMsg, wParam, lParam);
2401}
2402#endif
2403
2404void CMainFrame::OnSyncBrowse(wxCommandEvent&)
2405{
2406        CState* pState = CContextManager::Get()->GetCurrentContext();
2407        if (!pState)
2408                return;
2409
2410        pState->SetSyncBrowse(!pState->GetSyncBrowse());
2411}
2412
2413#ifndef __WXMAC__
2414void CMainFrame::OnIconize(wxIconizeEvent& event)
2415{
2416#ifdef __WXGTK__
2417        if (m_taskbar_is_uniconizing)
2418                return;
2419        if (m_taskBarIcon && m_taskBarIcon->IsIconInstalled()) // Only way to uniconize is via the taskbar icon.
2420                return;
2421#endif
2422        if (!event.IsIconized())
2423        {
2424                if (m_taskBarIcon)
2425                        m_taskBarIcon->RemoveIcon();
2426                Show(true);
2427
2428                if (m_pAsyncRequestQueue)
2429                        m_pAsyncRequestQueue->TriggerProcessing();
2430
2431                return;
2432        }
2433
2434        if (!COptions::Get()->GetOptionVal(OPTION_MINIMIZE_TRAY))
2435                return;
2436
2437        if (!m_taskBarIcon)
2438        {
2439                m_taskBarIcon = new wxTaskBarIcon();
2440                m_taskBarIcon->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxTaskBarIconEventHandler(CMainFrame::OnTaskBarClick), 0, this);
2441                m_taskBarIcon->Connect(wxEVT_TASKBAR_LEFT_UP, wxTaskBarIconEventHandler(CMainFrame::OnTaskBarClick), 0, this);
2442                m_taskBarIcon->Connect(wxEVT_TASKBAR_RIGHT_UP, wxTaskBarIconEventHandler(CMainFrame::OnTaskBarClick), 0, this);
2443        }
2444
2445        bool installed;
2446        if (!m_taskBarIcon->IsIconInstalled())
2447                installed = m_taskBarIcon->SetIcon(CThemeProvider::GetIcon(_T("ART_FILEZILLA")), GetTitle());
2448        else
2449                installed = true;
2450
2451        if (installed)
2452                Show(false);
2453}
2454
2455void CMainFrame::OnTaskBarClick(wxTaskBarIconEvent&)
2456{
2457#ifdef __WXGTK__
2458        if (m_taskbar_is_uniconizing)
2459                return;
2460        m_taskbar_is_uniconizing = true;
2461#endif
2462
2463        if (m_taskBarIcon)
2464                m_taskBarIcon->RemoveIcon();
2465
2466        Show(true);
2467        Iconize(false);
2468
2469        if (m_pAsyncRequestQueue)
2470                m_pAsyncRequestQueue->TriggerProcessing();
2471
2472#ifdef __WXGTK__
2473        QueueEvent(new wxCommandEvent(fzEVT_TASKBAR_CLICK_DELAYED));
2474#endif
2475}
2476
2477#ifdef __WXGTK__
2478void CMainFrame::OnTaskBarClick_Delayed(wxCommandEvent&)
2479{
2480        m_taskbar_is_uniconizing = false;
2481}
2482#endif
2483
2484#endif
2485
2486void CMainFrame::OnSearch(wxCommandEvent&)
2487{
2488        CState* pState = CContextManager::Get()->GetCurrentContext();
2489        if (!pState)
2490                return;
2491
2492        if (!pState->IsRemoteConnected() || !pState->IsRemoteIdle()) {
2493                wxBell();
2494                return;
2495        }
2496
2497        CSearchDialog dlg(this, pState, m_pQueueView);
2498        if (!dlg.Load())
2499                return;
2500
2501        dlg.Run();
2502}
2503
2504void CMainFrame::PostInitialize()
2505{
2506#ifdef __WXMAC__
2507        // Focus first control
2508        NavigateIn(wxNavigationKeyEvent::IsForward);
2509#endif
2510
2511#if FZ_MANUALUPDATECHECK
2512        // Need to do this after welcome screen to avoid simultaneous display of multiple dialogs
2513        if( !m_pUpdater ) {
2514                update_dialog_timer_.SetOwner(this);
2515                m_pUpdater = new CUpdater(*this, m_engineContext);
2516                m_pUpdater->Init();
2517        }
2518#endif
2519
2520        if (COptions::Get()->GetOptionVal(OPTION_INTERFACE_SITEMANAGER_ON_STARTUP) != 0)
2521        {
2522                Show();
2523                OpenSiteManager();
2524        }
2525}
2526
2527void CMainFrame::OnMenuNewTab(wxCommandEvent&)
2528{
2529        if (m_pContextControl)
2530                m_pContextControl->CreateTab();
2531}
2532
2533void CMainFrame::OnMenuCloseTab(wxCommandEvent&)
2534{
2535        if (!m_pContextControl)
2536                return;
2537
2538        m_pContextControl->CloseTab(m_pContextControl->GetCurrentTab());
2539}
2540
2541void CMainFrame::SetBookmarksFromPath(const wxString& path)
2542{
2543        if (!m_pContextControl)
2544                return;
2545
2546        std::shared_ptr<CContextControl::_context_controls::_site_bookmarks> site_bookmarks;
2547        for (int i = 0; i < m_pContextControl->GetTabCount(); i++) {
2548                if (i == m_pContextControl->GetCurrentTab())
2549                        continue;
2550
2551                CContextControl::_context_controls *controls = m_pContextControl->GetControlsFromTabIndex(i);
2552                if (!controls || !controls->site_bookmarks || controls->site_bookmarks->path != path)
2553                        continue;
2554
2555                site_bookmarks = controls->site_bookmarks;
2556                site_bookmarks->bookmarks.clear();
2557        }
2558        if (!site_bookmarks) {
2559                site_bookmarks = std::make_shared<CContextControl::_context_controls::_site_bookmarks>();
2560                site_bookmarks->path = path;
2561        }
2562
2563        CContextControl::_context_controls *controls = m_pContextControl->GetCurrentControls();
2564        if (controls) {
2565                controls->site_bookmarks = site_bookmarks;
2566                CSiteManager::GetBookmarks(controls->site_bookmarks->path, controls->site_bookmarks->bookmarks);
2567        }
2568}
2569
2570bool CMainFrame::ConnectToServer(const CServer &server, const CServerPath &path /*=CServerPath()*/, bool isReconnect /*=true*/)
2571{
2572        CState* pState = CContextManager::Get()->GetCurrentContext();
2573        if (!pState)
2574                return false;
2575
2576        if (pState->IsRemoteConnected() || !pState->IsRemoteIdle()) {
2577                int action = COptions::Get()->GetOptionVal(OPTION_ALREADYCONNECTED_CHOICE);
2578                if( action < 2 ) {
2579                        wxDialogEx dlg;
2580                        if (!dlg.Load(this, _T("ID_ALREADYCONNECTED")))
2581                                return false;
2582
2583                        if (action != 0)
2584                                XRCCTRL(dlg, "ID_OLDTAB", wxRadioButton)->SetValue(true);
2585                        else
2586                                XRCCTRL(dlg, "ID_NEWTAB", wxRadioButton)->SetValue(true);
2587
2588                        if (dlg.ShowModal() != wxID_OK)
2589                                return false;
2590
2591                        if (XRCCTRL(dlg, "ID_NEWTAB", wxRadioButton)->GetValue()) {
2592                                action = 0;
2593                        }
2594                        else {
2595                                action = 1;
2596                        }
2597
2598                        if( XRCCTRL(dlg, "ID_REMEMBER", wxCheckBox)->IsChecked() ) {
2599                                action |= 2;
2600                        }
2601                        COptions::Get()->SetOption(OPTION_ALREADYCONNECTED_CHOICE, action);
2602                }
2603
2604                if( !(action & 1) ) {
2605                        m_pContextControl->CreateTab();
2606                        pState = CContextManager::Get()->GetCurrentContext();
2607                }
2608        }
2609
2610        CContextControl::_context_controls* controls = m_pContextControl->GetControlsFromState(pState);
2611        if (!isReconnect && controls) {
2612                controls->site_bookmarks.reset();
2613                m_pMenuBar->ClearBookmarks();
2614        }
2615
2616        return pState->Connect(server, path);
2617}
2618
2619void CMainFrame::OnToggleToolBar(wxCommandEvent& event)
2620{
2621        COptions::Get()->SetOption(OPTION_TOOLBAR_HIDDEN, event.IsChecked() ? 0 : 1);
2622#ifdef __WXMAC__
2623        if (m_pToolBar)
2624                m_pToolBar->Show( event.IsChecked() );
2625#else
2626        CreateMainToolBar();
2627        if (m_pToolBar)
2628                m_pToolBar->UpdateToolbarState();
2629        HandleResize();
2630#endif
2631}
2632
2633void CMainFrame::FixTabOrder()
2634{
2635        if (m_pQuickconnectBar && m_pTopSplitter) {
2636                m_pQuickconnectBar->MoveBeforeInTabOrder(m_pTopSplitter);
2637        }
2638}
2639
2640#ifdef __WXMAC__
2641void CMainFrame::OnChildFocused(wxChildFocusEvent& event)
2642{
2643        m_lastFocusedChild = event.GetWindow()->GetId();
2644}
2645#endif
2646
2647void CMainFrame::SetupKeyboardAccelerators()
2648{
2649        std::vector<wxAcceleratorEntry> entries;
2650        for (int i = 0; i < 10; i++) {
2651                tab_hotkey_ids[i] = wxNewId();
2652                entries.emplace_back(wxACCEL_CMD, (int)'0' + i, tab_hotkey_ids[i]);
2653        }
2654        entries.emplace_back(wxACCEL_CMD | wxACCEL_SHIFT, 'O', m_comparisonToggleAcceleratorId);
2655        entries.emplace_back(wxACCEL_CMD | wxACCEL_SHIFT, 'I', XRCID("ID_MENU_VIEW_FILTERS"));
2656#ifdef __WXMAC__
2657        entries.emplace_back(wxACCEL_CMD, ',', XRCID("wxID_PREFERENCES"));
2658
2659        keyboardCommands[wxNewId()] = std::make_pair([](wxTextEntry* e) { e->Cut(); }, 'X');
2660        keyboardCommands[wxNewId()] = std::make_pair([](wxTextEntry* e) { e->Copy(); }, 'C');
2661        keyboardCommands[wxNewId()] = std::make_pair([](wxTextEntry* e) { e->Paste(); }, 'V');
2662        keyboardCommands[wxNewId()] = std::make_pair([](wxTextEntry* e) { e->SelectAll(); }, 'A');
2663
2664        for (auto const& command : keyboardCommands) {
2665                entries.emplace_back(wxACCEL_CMD, command.second.second, command.first);
2666        }
2667#endif
2668        wxAcceleratorTable accel(entries.size(), &entries[0]);
2669        SetAcceleratorTable(accel);
2670}
2671
2672void CMainFrame::OnOptionsChanged(changed_options_t const& options)
2673{
2674        if (options.test(OPTION_FILEPANE_LAYOUT) || options.test(OPTION_FILEPANE_SWAP) || options.test(OPTION_MESSAGELOG_POSITION)) {
2675                UpdateLayout();
2676        }
2677
2678        bool const language_changed = options.test(OPTION_LANGUAGE);
2679        if (options.test(OPTION_THEME) || options.test(OPTION_THEME_ICONSIZE) || language_changed) {
2680                CreateMainToolBar();
2681                if (m_pToolBar) {
2682                        m_pToolBar->UpdateToolbarState();
2683                }
2684        }
2685}
Note: See TracBrowser for help on using the repository browser.