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