source: filezilla/trunk/fuentes/src/interface/statusbar.cpp @ 130

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

First release to xenial

File size: 15.8 KB
Line 
1#include <filezilla.h>
2#include "Options.h"
3#include "sftp_crypt_info_dlg.h"
4#include "sizeformatting.h"
5#include "speedlimits_dialog.h"
6#include "statusbar.h"
7#include "themeprovider.h"
8#include "verifycertdialog.h"
9
10#include <wx/dcclient.h>
11
12static const int statbarWidths[3] = {
13        -3, 0, 25
14};
15#define FIELD_QUEUESIZE 1
16
17BEGIN_EVENT_TABLE(wxStatusBarEx, wxStatusBar)
18EVT_SIZE(wxStatusBarEx::OnSize)
19END_EVENT_TABLE()
20
21wxStatusBarEx::wxStatusBarEx(wxTopLevelWindow* pParent)
22{
23        m_pParent = pParent;
24        m_columnWidths = 0;
25        Create(pParent, wxID_ANY);
26
27        SetBackgroundStyle(wxBG_STYLE_SYSTEM);
28
29#ifdef __WXMSW__
30        m_parentWasMaximized = false;
31
32        if (GetLayoutDirection() != wxLayout_RightToLeft)
33                SetDoubleBuffered(true);
34#endif
35}
36
37wxStatusBarEx::~wxStatusBarEx()
38{
39        delete [] m_columnWidths;
40}
41
42void wxStatusBarEx::SetFieldsCount(int number /*=1*/, const int* widths /*=NULL*/)
43{
44        wxASSERT(number > 0);
45
46        int oldCount = GetFieldsCount();
47        int* oldWidths = m_columnWidths;
48
49        m_columnWidths = new int[number];
50        if (!widths)
51        {
52                if (oldWidths)
53                {
54                        const int min = wxMin(oldCount, number);
55                        for (int i = 0; i < min; i++)
56                                m_columnWidths[i] = oldWidths[i];
57                        for (int i = min; i < number; i++)
58                                m_columnWidths[i] = -1;
59                        delete [] oldWidths;
60                }
61                else
62                {
63                        for (int i = 0; i < number; i++)
64                                m_columnWidths[i] = -1;
65                }
66        }
67        else
68        {
69                delete [] oldWidths;
70                for (int i = 0; i < number; i++)
71                        m_columnWidths[i] = widths[i];
72
73                FixupFieldWidth(number - 1);
74        }
75
76        wxStatusBar::SetFieldsCount(number, m_columnWidths);
77}
78
79void wxStatusBarEx::SetStatusWidths(int n, const int *widths)
80{
81        wxASSERT(n == GetFieldsCount());
82        wxASSERT(widths);
83        for (int i = 0; i < n; i++)
84                m_columnWidths[i] = widths[i];
85
86        FixupFieldWidth(n - 1);
87
88        wxStatusBar::SetStatusWidths(n, m_columnWidths);
89}
90
91void wxStatusBarEx::FixupFieldWidth(int field)
92{
93        if (field != GetFieldsCount() - 1)
94                return;
95
96#if __WXGTK20__
97        // Gripper overlaps last all the time
98        if (m_columnWidths[field] > 0)
99                m_columnWidths[field] += 15;
100#endif
101}
102
103void wxStatusBarEx::SetFieldWidth(int field, int width)
104{
105        field = GetFieldIndex(field);
106        if( field < 0 ) {
107                return;
108        }
109
110        m_columnWidths[field] = width;
111        FixupFieldWidth(field);
112        wxStatusBar::SetStatusWidths(GetFieldsCount(), m_columnWidths);
113}
114
115int wxStatusBarEx::GetFieldIndex(int field)
116{
117        if (field >= 0) {
118                wxCHECK(field <= GetFieldsCount(), -1);
119        }
120        else {
121                field = GetFieldsCount() + field;
122                wxCHECK(field >= 0, -1);
123        }
124
125        return field;
126}
127
128void wxStatusBarEx::OnSize(wxSizeEvent&)
129{
130#ifdef __WXMSW__
131        const int count = GetFieldsCount();
132        if (count && m_columnWidths && m_columnWidths[count - 1] > 0)
133        {
134                // No sizegrip on maximized windows
135                bool isMaximized = m_pParent->IsMaximized();
136                if (isMaximized != m_parentWasMaximized)
137                {
138                        m_parentWasMaximized = isMaximized;
139
140                        if (isMaximized)
141                                m_columnWidths[count - 1] -= 16;
142                        else
143                                m_columnWidths[count - 1] += 16;
144
145                        wxStatusBar::SetStatusWidths(count, m_columnWidths);
146                        Refresh();
147                }
148        }
149#endif
150}
151
152#ifdef __WXGTK__
153void wxStatusBarEx::SetStatusText(const wxString& text, int number /*=0*/)
154{
155        wxString oldText = GetStatusText(number);
156        if (oldText != text) {
157                wxStatusBar::SetStatusText(text, number);
158        }
159}
160#endif
161
162int wxStatusBarEx::GetGripperWidth()
163{
164#if defined(__WXMSW__)
165        return m_pParent->IsMaximized() ? 0 : 6;
166#elif defined(__WXGTK__)
167        return 15;
168#else
169        return 0;
170#endif
171}
172
173
174
175BEGIN_EVENT_TABLE(CWidgetsStatusBar, wxStatusBarEx)
176EVT_SIZE(CWidgetsStatusBar::OnSize)
177END_EVENT_TABLE()
178
179CWidgetsStatusBar::CWidgetsStatusBar(wxTopLevelWindow* parent)
180        : wxStatusBarEx(parent)
181{
182}
183
184CWidgetsStatusBar::~CWidgetsStatusBar()
185{
186}
187
188void CWidgetsStatusBar::OnSize(wxSizeEvent& event)
189{
190        wxStatusBarEx::OnSize(event);
191
192        for (int i = 0; i < GetFieldsCount(); i++)
193                PositionChildren(i);
194
195#ifdef __WXMSW__
196        if (GetLayoutDirection() != wxLayout_RightToLeft)
197                Update();
198#endif
199}
200
201bool CWidgetsStatusBar::AddField(int field, int idx, wxWindow* pChild)
202{
203        field = GetFieldIndex(field);
204        if( field < 0 ) {
205                return false;
206        }
207
208        t_statbar_child data;
209        data.field = field;
210        data.pChild = pChild;
211
212        m_children[idx] = data;
213
214        PositionChildren(field);
215
216        return true;
217}
218
219void CWidgetsStatusBar::RemoveField(int idx)
220{
221        auto iter = m_children.find(idx);
222        if (iter != m_children.end()) {
223                int field = iter->second.field;
224                m_children.erase(iter);
225                PositionChildren(field);
226        }
227}
228
229void CWidgetsStatusBar::PositionChildren(int field)
230{
231        wxRect rect;
232        GetFieldRect(field, rect);
233
234        int offset = 2;
235
236#ifndef __WXMSW__
237        if (field + 1 == GetFieldsCount())
238        {
239                rect.SetWidth(m_columnWidths[field]);
240                offset += 5 + GetGripperWidth();
241        }
242#endif
243
244        for (auto iter = m_children.begin(); iter != m_children.end(); ++iter)
245        {
246                if (iter->second.field != field)
247                        continue;
248
249                const wxSize size = iter->second.pChild->GetSize();
250                int position = rect.GetRight() - size.x - offset;
251
252                iter->second.pChild->SetSize(position, rect.GetTop() + (rect.GetHeight() - size.y + 1) / 2, -1, -1);
253
254                offset += size.x + 3;
255        }
256}
257
258void CWidgetsStatusBar::SetFieldWidth(int field, int width)
259{
260        wxStatusBarEx::SetFieldWidth(field, width);
261        for (int i = 0; i < GetFieldsCount(); i++)
262                PositionChildren(i);
263}
264
265class CIndicator : public wxStaticBitmap
266{
267public:
268        CIndicator(CStatusBar* pStatusBar, const wxBitmap& bmp)
269                : wxStaticBitmap(pStatusBar, wxID_ANY, bmp)
270        {
271                m_pStatusBar = pStatusBar;
272        }
273
274protected:
275        CStatusBar* m_pStatusBar;
276
277        DECLARE_EVENT_TABLE()
278        void OnLeftMouseUp(wxMouseEvent&)
279        {
280                m_pStatusBar->OnHandleLeftClick(this);
281        }
282        void OnRightMouseUp(wxMouseEvent&)
283        {
284                m_pStatusBar->OnHandleRightClick(this);
285        }
286};
287
288BEGIN_EVENT_TABLE(CIndicator, wxStaticBitmap)
289EVT_LEFT_UP(CIndicator::OnLeftMouseUp)
290EVT_RIGHT_UP(CIndicator::OnRightMouseUp)
291END_EVENT_TABLE()
292
293BEGIN_EVENT_TABLE(CStatusBar, CWidgetsStatusBar)
294EVT_MENU(XRCID("ID_SPEEDLIMITCONTEXT_ENABLE"), CStatusBar::OnSpeedLimitsEnable)
295EVT_MENU(XRCID("ID_SPEEDLIMITCONTEXT_CONFIGURE"), CStatusBar::OnSpeedLimitsConfigure)
296EVT_TIMER(wxID_ANY, CStatusBar::OnTimer)
297END_EVENT_TABLE()
298
299CStatusBar::CStatusBar(wxTopLevelWindow* pParent)
300        : CWidgetsStatusBar(pParent), CStateEventHandler(0)
301{
302        // Speedlimits
303        RegisterOption(OPTION_SPEEDLIMIT_ENABLE);
304        RegisterOption(OPTION_SPEEDLIMIT_INBOUND);
305        RegisterOption(OPTION_SPEEDLIMIT_OUTBOUND);
306
307        // Size format
308        RegisterOption(OPTION_SIZE_FORMAT);
309        RegisterOption(OPTION_SIZE_USETHOUSANDSEP);
310        RegisterOption(OPTION_SIZE_DECIMALPLACES);
311
312        RegisterOption(OPTION_ASCIIBINARY);
313
314        // Reload icons
315        RegisterOption(OPTION_THEME);
316
317        CContextManager::Get()->RegisterHandler(this, STATECHANGE_SERVER, true);
318        CContextManager::Get()->RegisterHandler(this, STATECHANGE_CHANGEDCONTEXT, false);
319        CContextManager::Get()->RegisterHandler(this, STATECHANGE_ENCRYPTION, true);
320
321        const int count = 3;
322        SetFieldsCount(count);
323        int array[count];
324        array[0] = wxSB_FLAT;
325        array[1] = wxSB_NORMAL;
326        array[2] = wxSB_FLAT;
327        SetStatusStyles(count, array);
328
329        SetStatusWidths(count, statbarWidths);
330
331        UpdateSizeFormat();
332
333        UpdateSpeedLimitsIcon();
334        DisplayDataType();
335        DisplayEncrypted();
336
337        m_queue_size_timer.SetOwner(this);
338}
339
340CStatusBar::~CStatusBar()
341{
342}
343
344void CStatusBar::DisplayQueueSize(int64_t totalSize, bool hasUnknown)
345{
346        m_size = totalSize;
347        m_hasUnknownFiles = hasUnknown;
348
349        if (m_queue_size_timer.IsRunning()) {
350                m_queue_size_changed = true;
351        }
352        else {
353                DoDisplayQueueSize();
354                m_queue_size_timer.Start(200, true);
355        }
356}
357
358void CStatusBar::DoDisplayQueueSize()
359{
360        m_queue_size_changed = false;
361        if (m_size == 0 && !m_hasUnknownFiles) {
362                SetStatusText(_("Queue: empty"), FIELD_QUEUESIZE);
363                return;
364        }
365
366        wxString queueSize = wxString::Format(_("Queue: %s%s"), m_hasUnknownFiles ? _T(">") : _T(""),
367                CSizeFormat::Format(m_size, true, m_sizeFormat, m_sizeFormatThousandsSep, m_sizeFormatDecimalPlaces));
368
369        SetStatusText(queueSize, FIELD_QUEUESIZE);
370}
371
372void CStatusBar::DisplayDataType()
373{
374        const CServer* pServer = 0;
375        const CState* pState = CContextManager::Get()->GetCurrentContext();
376        if (pState)
377                pServer = pState->GetServer();
378
379        if (!pServer || !CServer::ProtocolHasDataTypeConcept(pServer->GetProtocol())) {
380                if (m_pDataTypeIndicator) {
381                        RemoveField(widget_datatype);
382                        m_pDataTypeIndicator->Destroy();
383                        m_pDataTypeIndicator = 0;
384                }
385        }
386        else {
387                wxString name;
388                wxString desc;
389
390                const int type = COptions::Get()->GetOptionVal(OPTION_ASCIIBINARY);
391                if (type == 1) {
392                        name = _T("ART_ASCII");
393                        desc = _("Current transfer type is set to ASCII.");
394                }
395                else if (type == 2) {
396                        name = _T("ART_BINARY");
397                        desc = _("Current transfer type is set to binary.");
398                }
399                else {
400                        name = _T("ART_AUTO");
401                        desc = _("Current transfer type is set to automatic detection.");
402                }
403
404                wxBitmap bmp = wxArtProvider::GetBitmap(name, wxART_OTHER, CThemeProvider::GetIconSize(iconSizeSmall));
405                if (!m_pDataTypeIndicator) {
406                        m_pDataTypeIndicator = new CIndicator(this, bmp);
407                        AddField(0, widget_datatype, m_pDataTypeIndicator);
408                }
409                else
410                        m_pDataTypeIndicator->SetBitmap(bmp);
411                m_pDataTypeIndicator->SetToolTip(desc);
412        }
413}
414
415void CStatusBar::MeasureQueueSizeWidth()
416{
417        wxClientDC dc(this);
418        dc.SetFont(GetFont());
419
420        wxSize s = dc.GetTextExtent(_("Queue: empty"));
421
422        wxString tmp = _T(">8888");
423        if (m_sizeFormatDecimalPlaces)
424        {
425                tmp += _T(".");
426                for (int i = 0; i < m_sizeFormatDecimalPlaces; i++)
427                        tmp += _T("8");
428        }
429        s.IncTo(dc.GetTextExtent(wxString::Format(_("Queue: %s MiB"), tmp)));
430
431        SetFieldWidth(FIELD_QUEUESIZE, s.x + 10);
432}
433
434void CStatusBar::DisplayEncrypted()
435{
436        const CServer* pServer = 0;
437        CState* pState = CContextManager::Get()->GetCurrentContext();
438        if (pState)
439                pServer = pState->GetServer();
440
441        bool encrypted = false;
442        if (pServer) {
443                CCertificateNotification* info;
444                if (pServer->GetProtocol() == FTPS || pServer->GetProtocol() == FTPES || pServer->GetProtocol() == SFTP) {
445                        encrypted = true;
446                }
447                else if (pServer->GetProtocol() == FTP && pState->GetSecurityInfo(info)) {
448                        encrypted = true;
449                }
450        }
451
452        if (!encrypted) {
453                if (m_pEncryptionIndicator) {
454                        RemoveField(widget_encryption);
455                        m_pEncryptionIndicator->Destroy();
456                        m_pEncryptionIndicator = 0;
457                }
458        }
459        else {
460                wxBitmap bmp = wxArtProvider::GetBitmap(_T("ART_LOCK"), wxART_OTHER,  CThemeProvider::GetIconSize(iconSizeSmall));
461                if (!m_pEncryptionIndicator) {
462                        m_pEncryptionIndicator = new CIndicator(this, bmp);
463                        AddField(0, widget_encryption, m_pEncryptionIndicator);
464                        m_pEncryptionIndicator->SetToolTip(_("The connection is encrypted. Click icon for details."));
465                }
466                else
467                        m_pEncryptionIndicator->SetBitmap(bmp);
468        }
469}
470
471void CStatusBar::UpdateSizeFormat()
472{
473        // 0 equals bytes, however just use IEC binary prefixes instead,
474        // exact byte counts for queue make no sense.
475        m_sizeFormat = CSizeFormat::_format(COptions::Get()->GetOptionVal(OPTION_SIZE_FORMAT));
476        if (!m_sizeFormat)
477                m_sizeFormat = CSizeFormat::iec;
478
479        m_sizeFormatThousandsSep = COptions::Get()->GetOptionVal(OPTION_SIZE_USETHOUSANDSEP) != 0;
480        m_sizeFormatDecimalPlaces = COptions::Get()->GetOptionVal(OPTION_SIZE_DECIMALPLACES);
481
482        MeasureQueueSizeWidth();
483
484        DisplayQueueSize(m_size, m_hasUnknownFiles);
485}
486
487void CStatusBar::OnHandleLeftClick(wxWindow* pWnd)
488{
489        if (pWnd == m_pEncryptionIndicator) {
490                CState* pState = CContextManager::Get()->GetCurrentContext();
491                CCertificateNotification *pCertificateNotification = 0;
492                CSftpEncryptionNotification *pSftpEncryptionNotification = 0;
493                if (pState->GetSecurityInfo(pCertificateNotification)) {
494                        CVerifyCertDialog dlg;
495                        dlg.ShowVerificationDialog(*pCertificateNotification, true);
496                }
497                else if (pState->GetSecurityInfo(pSftpEncryptionNotification)) {
498                        CSftpEncryptioInfoDialog dlg;
499                        dlg.ShowDialog(pSftpEncryptionNotification);
500                }
501                else
502                        wxMessageBoxEx(_("Certificate and session data are not available yet."), _("Security information"));
503        }
504        else if (pWnd == m_pSpeedLimitsIndicator) {
505                CSpeedLimitsDialog dlg;
506                dlg.Run(m_pParent);
507        }
508        else if (pWnd == m_pDataTypeIndicator) {
509                ShowDataTypeMenu();
510        }
511}
512
513void CStatusBar::OnHandleRightClick(wxWindow* pWnd)
514{
515        if (pWnd == m_pDataTypeIndicator) {
516                ShowDataTypeMenu();
517        }
518        else if (pWnd == m_pSpeedLimitsIndicator) {
519                wxMenu* pMenu = wxXmlResource::Get()->LoadMenu(_T("ID_MENU_SPEEDLIMITCONTEXT"));
520                if (!pMenu)
521                        return;
522
523                int downloadlimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_INBOUND);
524                int uploadlimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_OUTBOUND);
525                bool enable = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_ENABLE) != 0;
526                if (!downloadlimit && !uploadlimit)
527                        enable = false;
528                pMenu->Check(XRCID("ID_SPEEDLIMITCONTEXT_ENABLE"), enable);
529
530                PopupMenu(pMenu);
531                delete pMenu;
532        }
533}
534
535void CStatusBar::ShowDataTypeMenu()
536{
537        wxMenu* pMenu = wxXmlResource::Get()->LoadMenu(_T("ID_MENU_TRANSFER_TYPE_CONTEXT"));
538        if (!pMenu)
539                return;
540
541        const int type = COptions::Get()->GetOptionVal(OPTION_ASCIIBINARY);
542        switch (type)
543        {
544        case 1:
545                pMenu->Check(XRCID("ID_MENU_TRANSFER_TYPE_ASCII"), true);
546                break;
547        case 2:
548                pMenu->Check(XRCID("ID_MENU_TRANSFER_TYPE_BINARY"), true);
549                break;
550        default:
551                pMenu->Check(XRCID("ID_MENU_TRANSFER_TYPE_AUTO"), true);
552                break;
553        }
554
555        PopupMenu(pMenu);
556        delete pMenu;
557}
558
559void CStatusBar::UpdateSpeedLimitsIcon()
560{
561        bool enable = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_ENABLE) != 0;
562
563        wxBitmap bmp = wxArtProvider::GetBitmap(_T("ART_SPEEDLIMITS"), wxART_OTHER, CThemeProvider::GetIconSize(iconSizeSmall));
564        if (!bmp.Ok()) {
565                return;
566        }
567        wxString tooltip;
568
569        int downloadLimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_INBOUND);
570        int uploadLimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_OUTBOUND);
571        if (!enable || (!downloadLimit && !uploadLimit)) {
572                wxImage img = bmp.ConvertToImage();
573                img = img.ConvertToGreyscale();
574                bmp = wxBitmap(img);
575                tooltip = _("Speed limits are disabled, click to change.");
576        }
577        else {
578                tooltip = _("Speed limits are enabled, click to change.");
579                tooltip += _T("\n");
580                if (downloadLimit)
581                        tooltip += wxString::Format(_("Download limit: %s/s"), CSizeFormat::FormatUnit(downloadLimit, CSizeFormat::kilo));
582                else
583                        tooltip += _("Download limit: none");
584                tooltip += _T("\n");
585                if (uploadLimit)
586                        tooltip += wxString::Format(_("Upload limit: %s/s"), CSizeFormat::FormatUnit(uploadLimit, CSizeFormat::kilo));
587                else
588                        tooltip += _("Upload limit: none");
589        }
590
591        if (!m_pSpeedLimitsIndicator) {
592                m_pSpeedLimitsIndicator = new CIndicator(this, bmp);
593                AddField(0, widget_speedlimit, m_pSpeedLimitsIndicator);
594        }
595        else
596                m_pSpeedLimitsIndicator->SetBitmap(bmp);
597        m_pSpeedLimitsIndicator->SetToolTip(tooltip);
598}
599
600void CStatusBar::OnOptionsChanged(changed_options_t const& options)
601{
602        if (options.test(OPTION_SPEEDLIMIT_ENABLE) || options.test(OPTION_SPEEDLIMIT_INBOUND) || options.test(OPTION_SPEEDLIMIT_OUTBOUND)) {
603                UpdateSpeedLimitsIcon();
604        }
605        if (options.test(OPTION_SIZE_FORMAT) || options.test(OPTION_SIZE_USETHOUSANDSEP) || options.test(OPTION_SIZE_DECIMALPLACES)) {
606                UpdateSizeFormat();
607        }
608        if (options.test(OPTION_ASCIIBINARY)) {
609                DisplayDataType();
610        }
611        if (options.test(OPTION_THEME)) {
612                DisplayDataType();
613                UpdateSpeedLimitsIcon();
614                DisplayEncrypted();
615        }
616}
617
618void CStatusBar::OnStateChange(CState*, enum t_statechange_notifications notification, const wxString&, const void*)
619{
620        if (notification == STATECHANGE_SERVER || notification == STATECHANGE_CHANGEDCONTEXT) {
621                DisplayDataType();
622                DisplayEncrypted();
623        }
624        else if (notification == STATECHANGE_ENCRYPTION) {
625                DisplayEncrypted();
626        }
627}
628
629void CStatusBar::OnSpeedLimitsEnable(wxCommandEvent&)
630{
631        int downloadlimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_INBOUND);
632        int uploadlimit = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_OUTBOUND);
633        bool enable = COptions::Get()->GetOptionVal(OPTION_SPEEDLIMIT_ENABLE) == 0;
634        if (enable)
635        {
636                if (!downloadlimit && !uploadlimit)
637                {
638                        CSpeedLimitsDialog dlg;
639                        dlg.Run(m_pParent);
640                }
641                else
642                        COptions::Get()->SetOption(OPTION_SPEEDLIMIT_ENABLE, 1);
643        }
644        else
645                COptions::Get()->SetOption(OPTION_SPEEDLIMIT_ENABLE, 0);
646}
647
648void CStatusBar::OnSpeedLimitsConfigure(wxCommandEvent&)
649{
650        CSpeedLimitsDialog dlg;
651        dlg.Run(m_pParent);
652}
653
654void CStatusBar::OnTimer(wxTimerEvent&)
655{
656        if (m_queue_size_changed && !m_queue_size_timer.IsRunning()) {
657                DoDisplayQueueSize();
658                m_queue_size_timer.Start(200, true);
659        }
660}
Note: See TracBrowser for help on using the repository browser.