1 #include "filezilla.h"
2 #include "filter_manager.h"
3 #include "listingcomparison.h"
4 #include "Mainfrm.h"
5 #include "Options.h"
6 #include "QueueView.h"
7 #include "themeprovider.h"
8 #include "toolbar.h"
9
CToolBar()10 CToolBar::CToolBar()
11 : COptionChangeEventHandler(this)
12 {
13 }
14
~CToolBar()15 CToolBar::~CToolBar()
16 {
17 COptions::Get()->unwatch_all(this);
18 for (auto iter = m_hidden_tools.begin(); iter != m_hidden_tools.end(); ++iter) {
19 delete iter->second;
20 }
21 }
22
MakeTool(char const * id,std::wstring const & art,wxString const & tooltip,wxString const & help,wxItemKind type)23 void CToolBar::MakeTool(char const* id, std::wstring const& art, wxString const& tooltip, wxString const& help, wxItemKind type)
24 {
25 if (help.empty() && !tooltip.empty()) {
26 MakeTool(id, art, tooltip, tooltip, type);
27 return;
28 }
29
30 wxBitmap bmp = CThemeProvider::Get()->CreateBitmap(art, wxART_TOOLBAR, iconSize_);
31 wxToolBar::AddTool(XRCID(id), wxString(), bmp, wxBitmap(), type, tooltip, help);
32 }
33
MakeTools()34 void CToolBar::MakeTools()
35 {
36 #ifdef __WXMSW__
37 MakeTool("ID_TOOLBAR_SITEMANAGER", L"ART_SITEMANAGER", _("Open the Site Manager."), _("Open the Site Manager"), wxITEM_DROPDOWN);
38 #else
39 MakeTool("ID_TOOLBAR_SITEMANAGER", L"ART_SITEMANAGER", _("Open the Site Manager. Right-click for a list of sites."), _("Open the Site Manager"), wxITEM_DROPDOWN);
40 #endif
41 AddSeparator();
42
43 MakeTool("ID_TOOLBAR_LOGVIEW", L"ART_LOGVIEW", _("Toggles the display of the message log"), wxString(), wxITEM_CHECK);
44 MakeTool("ID_TOOLBAR_LOCALTREEVIEW", L"ART_LOCALTREEVIEW", _("Toggles the display of the local directory tree"), wxString(), wxITEM_CHECK);
45 MakeTool("ID_TOOLBAR_REMOTETREEVIEW", L"ART_REMOTETREEVIEW", _("Toggles the display of the remote directory tree"), wxString(), wxITEM_CHECK);
46 MakeTool("ID_TOOLBAR_QUEUEVIEW", L"ART_QUEUEVIEW", _("Toggles the display of the transfer queue"), wxString(), wxITEM_CHECK);
47 AddSeparator();
48
49 MakeTool("ID_TOOLBAR_REFRESH", L"ART_REFRESH", _("Refresh the file and folder lists"));
50 MakeTool("ID_TOOLBAR_PROCESSQUEUE", L"ART_PROCESSQUEUE", _("Toggles processing of the transfer queue"), wxString(), wxITEM_CHECK);
51 MakeTool("ID_TOOLBAR_CANCEL", L"ART_CANCEL", _("Cancels the current operation"), _("Cancel current operation"));
52 MakeTool("ID_TOOLBAR_DISCONNECT", L"ART_DISCONNECT", _("Disconnects from the currently visible server"), _("Disconnect from server"));
53 MakeTool("ID_TOOLBAR_RECONNECT", L"ART_RECONNECT", _("Reconnects to the last used server"));
54 AddSeparator();
55
56 MakeTool("ID_TOOLBAR_FILTER", L"ART_FILTER", _("Opens the directory listing filter dialog. Right-click to toggle filters.") + L"\n" + _("Files matching a filter rule are removed from directory listings."), _("Filter the directory listings"), wxITEM_CHECK);
57 MakeTool("ID_TOOLBAR_COMPARISON", L"ART_COMPARE", _("Toggle directory comparison. Right-click to change comparison mode.\n\nColors:\nYellow: File only exists on one side\nGreen: File is newer than the unmarked file on other side\nRed: File sizes different"), _("Directory comparison"), wxITEM_CHECK);
58 MakeTool("ID_TOOLBAR_SYNCHRONIZED_BROWSING", L"ART_SYNCHRONIZE", _("Toggle synchronized browsing.\nIf enabled, navigating the local directory hierarchy will also change the directory on the server accordingly and vice versa."), _("Synchronized browsing"), wxITEM_CHECK);
59 MakeTool("ID_TOOLBAR_FIND", L"ART_FIND", _("Search for files recursively."), _("File search"));
60 }
61
62 #ifdef __WXMAC__
63 void fix_toolbar_style(wxFrame& frame);
64 #endif
65
Load(CMainFrame * pMainFrame)66 CToolBar* CToolBar::Load(CMainFrame* pMainFrame)
67 {
68 if (!pMainFrame) {
69 return nullptr;
70 }
71
72 CToolBar* toolbar = new CToolBar();
73 toolbar->m_pMainFrame = pMainFrame;
74
75 toolbar->iconSize_ = CThemeProvider::GetIconSize(iconSizeSmall, true);
76 #ifdef __WXMAC__
77 fix_toolbar_style(*pMainFrame);
78
79 // OS X only knows two hardcoded toolbar sizes.
80 if (toolbar->iconSize_.x >= 32) {
81 toolbar->iconSize_ = wxSize(32, 32);
82 }
83 else {
84 toolbar->iconSize_ = wxSize(24, 24);
85 }
86 #endif
87
88 int style = wxTB_FLAT | wxTB_HORIZONTAL | wxTB_NODIVIDER;
89 #ifdef __WXMSW__
90 style |= wxTB_NOICONS;
91 #endif
92 if (!toolbar->Create(pMainFrame, XRCID("ID_TOOLBAR"), wxDefaultPosition, wxDefaultSize, style)) {
93 delete toolbar;
94 return nullptr;
95 }
96 toolbar->SetToolBitmapSize(toolbar->iconSize_);
97 toolbar->MakeTools();
98
99 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_REMOTE_IDLE, true);
100 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_SERVER, true);
101 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_SYNC_BROWSE, true);
102 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_COMPARISON, true);
103 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_APPLYFILTER, true);
104
105 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_QUEUEPROCESSING, false);
106 CContextManager::Get()->RegisterHandler(toolbar, STATECHANGE_CHANGEDCONTEXT, false);
107
108 COptions::Get()->watch(OPTION_SHOW_MESSAGELOG, toolbar);
109 COptions::Get()->watch(OPTION_SHOW_QUEUE, toolbar);
110 COptions::Get()->watch(OPTION_SHOW_TREE_LOCAL, toolbar);
111 COptions::Get()->watch(OPTION_SHOW_TREE_REMOTE, toolbar);
112 COptions::Get()->watch(OPTION_MESSAGELOG_POSITION, toolbar);
113
114 toolbar->ToggleTool(XRCID("ID_TOOLBAR_FILTER"), CFilterManager::HasActiveFilters());
115 toolbar->ToggleTool(XRCID("ID_TOOLBAR_LOGVIEW"), COptions::Get()->get_int(OPTION_SHOW_MESSAGELOG) != 0);
116 toolbar->ToggleTool(XRCID("ID_TOOLBAR_QUEUEVIEW"), COptions::Get()->get_int(OPTION_SHOW_QUEUE) != 0);
117 toolbar->ToggleTool(XRCID("ID_TOOLBAR_LOCALTREEVIEW"), COptions::Get()->get_int(OPTION_SHOW_TREE_LOCAL) != 0);
118 toolbar->ToggleTool(XRCID("ID_TOOLBAR_REMOTETREEVIEW"), COptions::Get()->get_int(OPTION_SHOW_TREE_REMOTE) != 0);
119
120 pMainFrame->SetToolBar(toolbar);
121 toolbar->Realize();
122
123 if (COptions::Get()->get_int(OPTION_MESSAGELOG_POSITION) == 2) {
124 toolbar->HideTool(XRCID("ID_TOOLBAR_LOGVIEW"));
125 }
126
127 return toolbar;
128 }
129
130 #ifdef __WXMSW__
Realize()131 bool CToolBar::Realize()
132 {
133 wxASSERT(HasFlag(wxTB_NOICONS));
134
135 bool ret = wxToolBar::Realize();
136 if (!ret) {
137 return false;
138 }
139
140 wxASSERT(iconSize_.x > 0 && iconSize_.y > 0);
141 auto toolImages = std::make_unique<wxImageList>(iconSize_.x, iconSize_.y, false, 0);
142 auto disabledToolImages = std::make_unique<wxImageList>(iconSize_.x, iconSize_.y, false, 0);
143
144 HWND hwnd = GetHandle();
145
146 auto hImgList = reinterpret_cast<HIMAGELIST>(toolImages->GetHIMAGELIST());
147 auto hDisabledImgList = reinterpret_cast<HIMAGELIST>(disabledToolImages->GetHIMAGELIST());
148 ::SendMessage(hwnd, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(hImgList));
149 ::SendMessage(hwnd, TB_SETDISABLEDIMAGELIST, 0, reinterpret_cast<LPARAM>(hDisabledImgList));
150
151 toolImages_ = std::move(toolImages);
152 disabledToolImages_ = std::move(disabledToolImages);
153
154 for (size_t i = 0; i < GetToolsCount(); ++i) {
155 auto tool = GetToolByPos(static_cast<int>(i));
156 if (!tool || tool->GetStyle() != wxTOOL_STYLE_BUTTON) {
157 continue;
158 }
159
160 auto bmp = tool->GetBitmap();
161 if (!bmp.IsOk()) {
162 continue;
163 }
164
165 int image = toolImages_->Add(bmp);
166 auto disabled = tool->GetDisabledBitmap();
167 if (!disabled.IsOk()) {
168 disabled = wxBitmap(bmp.ConvertToImage().ConvertToGreyscale());
169 }
170 disabledToolImages_->Add(disabled);
171
172 TBBUTTONINFO btn{};
173 btn.cbSize = sizeof(TBBUTTONINFO);
174 btn.dwMask = TBIF_BYINDEX;
175 int index = ::SendMessage(hwnd, TB_GETBUTTONINFO, i, reinterpret_cast<LPARAM>(&btn));
176 if (index != static_cast<int>(i)) {
177 return false;
178 }
179
180 btn.dwMask = TBIF_BYINDEX | TBIF_IMAGE;
181 btn.iImage = image;
182 if (::SendMessage(hwnd, TB_SETBUTTONINFO, i, reinterpret_cast<LPARAM>(&btn)) == 0) {
183 return false;
184 }
185 }
186
187 ::SendMessage(hwnd, TB_SETINDENT, ConvertDialogToPixels(wxPoint(1, 0)).x, 0);
188
189 return true;
190 }
191
192 #endif
193
OnStateChange(CState * pState,t_statechange_notifications notification,std::wstring const &,const void *)194 void CToolBar::OnStateChange(CState* pState, t_statechange_notifications notification, std::wstring const&, const void*)
195 {
196 switch (notification)
197 {
198 case STATECHANGE_CHANGEDCONTEXT:
199 case STATECHANGE_SERVER:
200 case STATECHANGE_REMOTE_IDLE:
201 UpdateToolbarState();
202 break;
203 case STATECHANGE_QUEUEPROCESSING:
204 {
205 const bool check = m_pMainFrame->GetQueue() && m_pMainFrame->GetQueue()->IsActive() != 0;
206 ToggleTool(XRCID("ID_TOOLBAR_PROCESSQUEUE"), check);
207 }
208 break;
209 case STATECHANGE_SYNC_BROWSE:
210 {
211 bool is_sync_browse = pState && pState->GetSyncBrowse();
212 ToggleTool(XRCID("ID_TOOLBAR_SYNCHRONIZED_BROWSING"), is_sync_browse);
213 }
214 break;
215 case STATECHANGE_COMPARISON:
216 {
217 bool is_comparing = pState && pState->GetComparisonManager()->IsComparing();
218 ToggleTool(XRCID("ID_TOOLBAR_COMPARISON"), is_comparing);
219 }
220 break;
221 case STATECHANGE_APPLYFILTER:
222 ToggleTool(XRCID("ID_TOOLBAR_FILTER"), CFilterManager::HasActiveFilters());
223 break;
224 default:
225 break;
226 }
227 }
228
UpdateToolbarState()229 void CToolBar::UpdateToolbarState()
230 {
231 CState* pState = CContextManager::Get()->GetCurrentContext();
232 if (!pState) {
233 return;
234 }
235
236 bool const hasServer = static_cast<bool>(pState->GetSite());
237 bool const idle = pState->IsRemoteIdle();
238
239 EnableTool(XRCID("ID_TOOLBAR_DISCONNECT"), hasServer && idle);
240 EnableTool(XRCID("ID_TOOLBAR_CANCEL"), hasServer && !idle);
241 EnableTool(XRCID("ID_TOOLBAR_SYNCHRONIZED_BROWSING"), hasServer);
242
243 ToggleTool(XRCID("ID_TOOLBAR_COMPARISON"), pState->GetComparisonManager()->IsComparing());
244 ToggleTool(XRCID("ID_TOOLBAR_SYNCHRONIZED_BROWSING"), pState->GetSyncBrowse());
245
246 bool canReconnect;
247 if (hasServer || !idle) {
248 canReconnect = false;
249 }
250 else {
251 canReconnect = static_cast<bool>(pState->GetLastSite());
252 }
253 EnableTool(XRCID("ID_TOOLBAR_RECONNECT"), canReconnect);
254 }
255
OnOptionsChanged(watched_options const & options)256 void CToolBar::OnOptionsChanged(watched_options const& options)
257 {
258 if (options.test(OPTION_SHOW_MESSAGELOG)) {
259 ToggleTool(XRCID("ID_TOOLBAR_LOGVIEW"), COptions::Get()->get_int(OPTION_SHOW_MESSAGELOG) != 0);
260 }
261 if (options.test(OPTION_SHOW_QUEUE)) {
262 ToggleTool(XRCID("ID_TOOLBAR_QUEUEVIEW"), COptions::Get()->get_int(OPTION_SHOW_QUEUE) != 0);
263 }
264 if (options.test(OPTION_SHOW_TREE_LOCAL)) {
265 ToggleTool(XRCID("ID_TOOLBAR_LOCALTREEVIEW"), COptions::Get()->get_int(OPTION_SHOW_TREE_LOCAL) != 0);
266 }
267 if (options.test(OPTION_SHOW_TREE_REMOTE)) {
268 ToggleTool(XRCID("ID_TOOLBAR_REMOTETREEVIEW"), COptions::Get()->get_int(OPTION_SHOW_TREE_REMOTE) != 0);
269 }
270 if (options.test(OPTION_MESSAGELOG_POSITION)) {
271 if (COptions::Get()->get_int(OPTION_MESSAGELOG_POSITION) == 2) {
272 HideTool(XRCID("ID_TOOLBAR_LOGVIEW"));
273 }
274 else {
275 ShowTool(XRCID("ID_TOOLBAR_LOGVIEW"));
276 ToggleTool(XRCID("ID_TOOLBAR_LOGVIEW"), COptions::Get()->get_int(OPTION_SHOW_MESSAGELOG) != 0);
277 }
278 }
279 }
280
ShowTool(int id)281 bool CToolBar::ShowTool(int id)
282 {
283 int offset = 0;
284
285 for (auto iter = m_hidden_tools.begin(); iter != m_hidden_tools.end(); ++iter) {
286 if (iter->second->GetId() != id) {
287 offset++;
288 continue;
289 }
290
291 InsertTool(iter->first - offset, iter->second);
292 Realize();
293 m_hidden_tools.erase(iter);
294
295 return true;
296 }
297
298 return false;
299 }
300
HideTool(int id)301 bool CToolBar::HideTool(int id)
302 {
303 int pos = GetToolPos(id);
304 if (pos == -1) {
305 return false;
306 }
307
308 wxToolBarToolBase* tool = RemoveTool(id);
309 if (!tool) {
310 return false;
311 }
312
313 for (auto const& iter : m_hidden_tools) {
314 if (iter.first > pos) {
315 break;
316 }
317
318 ++pos;
319 }
320
321 m_hidden_tools[pos] = tool;
322
323 return true;
324 }
325