Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/windirstat.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Schneider <oliver@assarbad.net>2012-10-14 18:09:57 +0400
committerOliver Schneider <oliver@assarbad.net>2012-10-14 18:09:57 +0400
commit8e6bf65086ceb2e950d0f66c15a29ab1a3d43705 (patch)
tree70ef058cf7c24fde6142e81a73af625e83fafa69 /windirstat/Dialogs
parent3f2c80c4b2f8fdf2fe79f319d18a10b54403fdf9 (diff)
- Renaming various files to make more obvious where they belong logically
- Updated premake4.lua to create proper filters in VS projects
Diffstat (limited to 'windirstat/Dialogs')
-rw-r--r--windirstat/Dialogs/AboutDlg.h82
-rw-r--r--windirstat/Dialogs/DeleteWarningDlg.cpp71
-rw-r--r--windirstat/Dialogs/DeleteWarningDlg.h49
-rw-r--r--windirstat/Dialogs/SelectDrivesDlg.cpp936
-rw-r--r--windirstat/Dialogs/SelectDrivesDlg.h195
-rw-r--r--windirstat/Dialogs/aboutdlg.cpp329
6 files changed, 1662 insertions, 0 deletions
diff --git a/windirstat/Dialogs/AboutDlg.h b/windirstat/Dialogs/AboutDlg.h
new file mode 100644
index 0000000..2e0f76e
--- /dev/null
+++ b/windirstat/Dialogs/AboutDlg.h
@@ -0,0 +1,82 @@
+// aboutdlg.h - Declaration of StartAboutDialog(), CAboutThread and CAboutDlg
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#ifndef __WDS_ABOUTDLG_H__
+#define __WDS_ABOUTDLG_H__
+#pragma once
+
+#include "layout.h"
+#include <common/wds_constants.h>
+
+
+void StartAboutDialog();
+
+
+class CAboutThread: public CWinThread
+{
+ DECLARE_DYNCREATE(CAboutThread);
+protected:
+ virtual BOOL InitInstance();
+};
+
+
+class CAboutDlg : public CDialog
+{
+ enum { IDD = IDD_ABOUTBOX };
+
+ class CMyTabControl: public CTabCtrl
+ {
+ public:
+ void Initialize();
+ void SetPageText(int tab);
+
+ protected:
+ CRichEditCtrl m_text;
+
+ DECLARE_MESSAGE_MAP()
+ afx_msg void OnEnLinkText(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnEnMsgFilter(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ };
+
+public:
+ CAboutDlg();
+ static CString GetAppVersion();
+
+protected:
+ virtual BOOL OnInitDialog();
+ virtual void DoDataExchange(CDataExchange* pDX);
+
+ CStatic m_caption;
+ CMyTabControl m_tab;
+ CLayout m_layout;
+
+ DECLARE_MESSAGE_MAP()
+ afx_msg void OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+ afx_msg void OnDestroy();
+};
+
+#endif // __WDS_ABOUTDLG_H__
diff --git a/windirstat/Dialogs/DeleteWarningDlg.cpp b/windirstat/Dialogs/DeleteWarningDlg.cpp
new file mode 100644
index 0000000..d19880c
--- /dev/null
+++ b/windirstat/Dialogs/DeleteWarningDlg.cpp
@@ -0,0 +1,71 @@
+// DeleteWarningDlg.cpp - implementation of CDeleteWarningDlg
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#include "stdafx.h"
+#include "windirstat.h"
+#include "DeleteWarningDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+IMPLEMENT_DYNAMIC(CDeleteWarningDlg, CDialog)
+
+CDeleteWarningDlg::CDeleteWarningDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CDeleteWarningDlg::IDD, pParent)
+ , m_fileName(wds::strEmpty)
+ , m_dontShowAgain(false)
+{
+}
+
+CDeleteWarningDlg::~CDeleteWarningDlg()
+{
+}
+
+void CDeleteWarningDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Check(pDX, IDC_DONTSHOWAGAIN, m_dontShowAgain);
+ DDX_Text(pDX, IDC_FILENAME, m_fileName);
+}
+
+
+BEGIN_MESSAGE_MAP(CDeleteWarningDlg, CDialog)
+ ON_BN_CLICKED(IDNO, OnBnClickedNo)
+ ON_BN_CLICKED(IDYES, OnBnClickedYes)
+END_MESSAGE_MAP()
+
+
+void CDeleteWarningDlg::OnBnClickedNo()
+{
+ UpdateData();
+ EndDialog(IDNO);
+}
+
+void CDeleteWarningDlg::OnBnClickedYes()
+{
+ UpdateData();
+ EndDialog(IDYES);
+}
diff --git a/windirstat/Dialogs/DeleteWarningDlg.h b/windirstat/Dialogs/DeleteWarningDlg.h
new file mode 100644
index 0000000..0885c6b
--- /dev/null
+++ b/windirstat/Dialogs/DeleteWarningDlg.h
@@ -0,0 +1,49 @@
+// deletewarningdlg.h - Declaration of CDeleteWarningDlg
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#pragma once
+
+//
+// CDeleteWarningDlg. As WinDirStat can delete all files and folders,
+// e.g. C:\Windows, we show an additional warning, when the user
+// selects "Delete" (before the shell shows its warning).
+//
+class CDeleteWarningDlg : public CDialog
+{
+ DECLARE_DYNAMIC(CDeleteWarningDlg)
+ enum { IDD = IDD_DELETE_WARNING };
+
+public:
+ CDeleteWarningDlg(CWnd* pParent = NULL);
+ virtual ~CDeleteWarningDlg();
+
+ CString m_fileName; // [in] file name for feedback
+ BOOL m_dontShowAgain; // [out]
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX);
+ DECLARE_MESSAGE_MAP()
+ afx_msg void OnBnClickedNo();
+ afx_msg void OnBnClickedYes();
+};
diff --git a/windirstat/Dialogs/SelectDrivesDlg.cpp b/windirstat/Dialogs/SelectDrivesDlg.cpp
new file mode 100644
index 0000000..138482d
--- /dev/null
+++ b/windirstat/Dialogs/SelectDrivesDlg.cpp
@@ -0,0 +1,936 @@
+// SelectDrivesDlg.cpp - Implementation of CDriveItem, CDrivesList and CSelectDrivesDlg
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#include "stdafx.h"
+#include "windirstat.h"
+#include "SelectDrivesDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+namespace
+{
+ enum
+ {
+ COL_NAME,
+ COL_TOTAL,
+ COL_FREE,
+ COL_GRAPH,
+ COL_PERCENTUSED,
+ COLUMN_COUNT
+ };
+
+ const UINT WMU_OK = WM_USER + 100;
+
+ static UINT WMU_THREADFINISHED = ::RegisterWindowMessage(_T("{F03D3293-86E0-4c87-B559-5FD103F5AF58}"));
+
+ // Return: false, if drive not accessible
+ bool RetrieveDriveInformation(LPCTSTR path, CString& name, ULONGLONG& total, ULONGLONG& free)
+ {
+ CString volumeName;
+
+ if(!GetVolumeName(path, volumeName))
+ {
+ return false;
+ }
+
+ name = FormatVolumeName(path, volumeName);
+
+ if(!CDirstatApp::getDiskFreeSpace(path, total, free))
+ {
+ return false;
+ }
+
+ // This condition *can* become true if quotas exist!
+ //ASSERT(free <= total);
+
+ return true;
+ }
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+CDriveItem::CDriveItem(CDrivesList *list, LPCTSTR pszPath)
+ : m_list(list)
+ , m_path(pszPath)
+ , m_success(false)
+ , m_name(m_path)
+ , m_totalBytes(0)
+ , m_freeBytes(0)
+ , m_used(0)
+ , m_isRemote(DRIVE_REMOTE == ::GetDriveType(m_path))
+ , m_querying(true)
+{
+
+ /*
+ For local drives we could do this synchronously:
+ if(!m_isRemote)
+ {
+ m_querying = false;
+
+ CString name = m_name;
+ ULONGLONG total = 0;
+ ULONGLONG free = 0;
+
+ bool success = RetrieveDriveInformation(m_path, name, total, free);
+ SetDriveInformation(success, name, total, free);
+ }
+ */
+}
+
+void CDriveItem::StartQuery(HWND dialog, UINT serial)
+{
+ ASSERT(dialog != NULL);
+
+ ASSERT(m_querying); // The synchronous query in the constructor is commented out.
+
+ if(m_querying)
+ {
+ new CDriveInformationThread(m_path, (LPARAM)this, dialog, serial);
+ // (will delete itself when finished.)
+ }
+}
+
+void CDriveItem::SetDriveInformation(bool success, LPCTSTR name, ULONGLONG total, ULONGLONG free)
+{
+ m_querying = false;
+ m_success = success;
+
+ if(m_success)
+ {
+ m_name = name;
+ m_totalBytes = total;
+ m_freeBytes = free;
+
+ m_used = 0;
+ if(m_totalBytes > 0)
+ {
+ if(m_totalBytes < m_freeBytes) // can happen with quotas enabled
+ {
+ m_used = 0.0; // always return 0% in this case
+ }
+ else
+ {
+ m_used = (double)(m_totalBytes - m_freeBytes) / m_totalBytes;
+ }
+ }
+ }
+}
+
+bool CDriveItem::IsRemote() const
+{
+ return m_isRemote;
+}
+
+bool CDriveItem::IsSUBSTed() const
+{
+ return IsSUBSTedDrive(m_path);
+}
+
+int CDriveItem::Compare(const CSortingListItem *baseOther, int subitem) const
+{
+ const CDriveItem *other = (CDriveItem *)baseOther;
+
+ int r = 0;
+
+ switch (subitem)
+ {
+ case COL_NAME:
+ {
+ r = signum(GetPath().CompareNoCase(other->GetPath()));
+ }
+ break;
+ case COL_TOTAL:
+ {
+ r = signum(m_totalBytes - other->m_totalBytes);
+ }
+ break;
+ case COL_FREE:
+ {
+ r = signum(m_freeBytes - other->m_freeBytes);
+ }
+ break;
+ case COL_GRAPH:
+ case COL_PERCENTUSED:
+ {
+ r = signum(m_used - other->m_used);
+ }
+ break;
+ default:
+ {
+ ASSERT(0);
+ }
+ }
+
+ return r;
+}
+
+
+int CDriveItem::GetImage() const
+{
+ return GetMyImageList()->getFileImage(m_path);
+}
+
+bool CDriveItem::DrawSubitem(int subitem, CDC *pdc, CRect rc, UINT state, int *width, int *focusLeft) const
+{
+ if(subitem == COL_NAME)
+ {
+ DrawLabel(m_list, GetMyImageList(), pdc, rc, state, width, focusLeft);
+ return true;
+ }
+ else if(subitem == COL_GRAPH)
+ {
+ if(!m_success)
+ {
+ return false;
+ }
+
+
+ if(width != NULL)
+ {
+ *width = 100;
+ return true;
+ }
+
+ DrawSelection(m_list, pdc, rc, state);
+
+ rc.DeflateRect(3, 5);
+
+ DrawPercentage(pdc, rc, m_used, RGB(0,0,170));
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+CString CDriveItem::GetText(int subitem) const
+{
+ CString s;
+
+ switch (subitem)
+ {
+ case COL_NAME:
+ {
+ s = m_name;
+ }
+ break;
+
+ case COL_TOTAL:
+ if(m_success)
+ {
+ s = FormatBytes(m_totalBytes);
+ }
+ break;
+
+ case COL_FREE:
+ if(m_success)
+ {
+ s = FormatBytes(m_freeBytes);
+ }
+ break;
+
+ case COL_GRAPH:
+ if(m_querying)
+ {
+ s.LoadString(IDS_QUERYING);
+ }
+ else if(!m_success)
+ {
+ s.LoadString(IDS_NOTACCESSIBLE);
+ }
+ break;
+
+ case COL_PERCENTUSED:
+ if(m_success)
+ {
+ s = FormatDouble(m_used * 100) + _T("%");
+ }
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+ return s;
+}
+
+CString CDriveItem::GetPath() const
+{
+ return m_path;
+}
+
+CString CDriveItem::GetDrive() const
+{
+ return m_path.Left(2);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+CSet<CDriveInformationThread *, CDriveInformationThread *> CDriveInformationThread::_runningThreads;
+CCriticalSection CDriveInformationThread::_csRunningThreads;
+
+void CDriveInformationThread::AddRunningThread()
+{
+ CSingleLock lock(&_csRunningThreads, true);
+ _runningThreads.SetKey(this);
+}
+
+void CDriveInformationThread::RemoveRunningThread()
+{
+ CSingleLock lock(&_csRunningThreads, true);
+ _runningThreads.RemoveKey(this);
+}
+
+
+// This static method is called by the dialog when the dialog gets closed.
+// We set the m_dialog members of all running threads to null, so that
+// they don't send messages around to a no-more-existing window.
+//
+void CDriveInformationThread::InvalidateDialogHandle()
+{
+ CSingleLock lock(&_csRunningThreads, true);
+
+ POSITION pos = _runningThreads.GetStartPosition();
+ while(pos != NULL)
+ {
+ CDriveInformationThread *thread;
+ _runningThreads.GetNextAssoc(pos, thread);
+
+ CSingleLock lockObj(&thread->m_cs, true);
+ thread->m_dialog = NULL;
+ }
+}
+
+void CDriveInformationThread::OnAppExit()
+{
+ // We need not do anything here.
+}
+
+// The constructor starts the thread.
+//
+CDriveInformationThread::CDriveInformationThread(LPCTSTR path, LPARAM driveItem, HWND dialog, UINT serial)
+ : m_path(path)
+ , m_driveItem(driveItem)
+ , m_serial(serial)
+ , m_dialog(dialog)
+ , m_totalBytes(0)
+ , m_freeBytes(0)
+ , m_success(false)
+{
+ ASSERT(m_bAutoDelete);
+
+ AddRunningThread();
+
+ VERIFY(CreateThread());
+}
+
+BOOL CDriveInformationThread::InitInstance()
+{
+ m_success = RetrieveDriveInformation(m_path, m_name, m_totalBytes, m_freeBytes);
+
+#ifdef TESTTHREADS
+ srand(::GetTickCount());
+ ::Sleep((rand() & 0x07) * 1000);
+#endif
+
+ HWND dialog = NULL;
+
+ {
+ CSingleLock lock(&m_cs, true);
+ dialog = m_dialog;
+ // Of course, we must release m_cs here to avoid deadlocks.
+ }
+
+ if(dialog != NULL)
+ {
+ // Theoretically the dialog may have been closed at this point.
+ // SendMessage() to a non-existing window simply fails immediately.
+ // If in the meantime the system recycled the window handle,
+ // (it may even belong to another process now?!),
+ // we are safe, because WMU_THREADFINISHED is a unique registered message.
+ // (Well if the other process crashes because of our message, there is nothing we can do about it.)
+ // If the window handle is recycled by a new Select drives dialog,
+ // its new serial will prevent it from reacting.
+ ::SendMessage(dialog, WMU_THREADFINISHED, m_serial, (LPARAM)this);
+ }
+
+ RemoveRunningThread();
+
+ ASSERT(m_bAutoDelete); // Object will delete itself.
+ return false; // no Run(), please!
+}
+
+// This method is only called by the gui thread, while we hang
+// in SendMessage(dialog, WMU_THREADFINISHED, 0, this).
+// So we need no synchronization.
+//
+LPARAM CDriveInformationThread::GetDriveInformation(bool& success, CString& name, ULONGLONG& total, ULONGLONG& free)
+{
+ name = m_name;
+ total = m_totalBytes;
+ free = m_freeBytes;
+ success = m_success;
+
+ return m_driveItem;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC(CDrivesList, COwnerDrawnListControl)
+
+CDrivesList::CDrivesList()
+ : COwnerDrawnListControl(_T("drives"), 20)
+{
+}
+
+CDriveItem *CDrivesList::GetItem(int i)
+{
+ return (CDriveItem *)GetItemData(i);
+}
+
+bool CDrivesList::HasImages()
+{
+ return true;
+}
+
+void CDrivesList::SelectItem(CDriveItem *item)
+{
+ int i = FindListItem(item);
+ SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
+}
+
+bool CDrivesList::IsItemSelected(int i)
+{
+ return (LVIS_SELECTED == GetItemState(i, LVIS_SELECTED));
+}
+
+void CDrivesList::OnLButtonDown(UINT /*nFlags*/, CPoint /*point*/)
+{
+ if(GetFocus() == this || GetSelectedCount() == 0)
+ {
+ // We simulate Ctrl-Key-Down here, so that the dialog
+ // can be driven with one hand (mouse) only.
+ const MSG *msg = GetCurrentMessage();
+ DefWindowProc(msg->message, msg->wParam | MK_CONTROL, msg->lParam);
+ }
+ else
+ {
+ SetFocus();
+
+ // Send a LVN_ITEMCHANGED to the parent, so that it can
+ // update the radio button.
+ NMLISTVIEW lv;
+ ZeroMemory(&lv, sizeof(lv));
+ lv.hdr.hwndFrom = m_hWnd;
+ lv.hdr.idFrom = GetDlgCtrlID();
+ lv.hdr.code = LVN_ITEMCHANGED;
+ GetParent()->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&lv);
+
+ // no further action
+ }
+}
+
+void CDrivesList::OnNMDblclk(NMHDR * /*pNMHDR*/, LRESULT *pResult)
+{
+ *pResult = 0;
+
+ CPoint point = GetCurrentMessage()->pt;
+ ScreenToClient(&point);
+ int i = HitTest(point);
+ if(i == -1)
+ {
+ return;
+ }
+
+ for(int k = 0; k < GetItemCount(); k++)
+ {
+ SetItemState(k, k == i ? LVIS_SELECTED : 0, LVIS_SELECTED);
+ }
+
+ GetParent()->SendMessage(WMU_OK);
+}
+
+BEGIN_MESSAGE_MAP(CDrivesList, COwnerDrawnListControl)
+ ON_WM_LBUTTONDOWN()
+ ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnLvnDeleteitem)
+ ON_WM_MEASUREITEM_REFLECT()
+ ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)
+END_MESSAGE_MAP()
+
+void CDrivesList::OnLvnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
+ delete GetItem(pNMLV->iItem);
+ *pResult = 0;
+}
+
+void CDrivesList::MeasureItem(LPMEASUREITEMSTRUCT mis)
+{
+ mis->itemHeight = GetRowHeight();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC(CSelectDrivesDlg, CDialog)
+
+UINT CSelectDrivesDlg::_serial;
+
+CSelectDrivesDlg::CSelectDrivesDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CSelectDrivesDlg::IDD, pParent)
+ , m_layout(this, _T("sddlg"))
+{
+ _serial++;
+}
+
+CSelectDrivesDlg::~CSelectDrivesDlg()
+{
+}
+
+void CSelectDrivesDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_DRIVES, m_list);
+ DDX_Radio(pDX, IDC_ALLDRIVES, m_radio);
+ DDX_Text(pDX, IDC_FOLDERNAME, m_folderName);
+ DDX_Control(pDX, IDOK, m_okButton);
+}
+
+
+BEGIN_MESSAGE_MAP(CSelectDrivesDlg, CDialog)
+ ON_BN_CLICKED(IDC_BROWSEFOLDER, OnBnClickedBrowsefolder)
+ ON_BN_CLICKED(IDC_AFOLDER, OnBnClickedAfolder)
+ ON_BN_CLICKED(IDC_SOMEDRIVES, OnBnClickedSomedrives)
+ ON_EN_CHANGE(IDC_FOLDERNAME, OnEnChangeFoldername)
+ ON_WM_MEASUREITEM()
+ ON_NOTIFY(LVN_ITEMCHANGED, IDC_DRIVES, OnLvnItemchangedDrives)
+ ON_BN_CLICKED(IDC_ALLLOCALDRIVES, OnBnClickedAlllocaldrives)
+ ON_WM_SIZE()
+ ON_WM_GETMINMAXINFO()
+ ON_WM_DESTROY()
+ ON_MESSAGE(WMU_OK, OnWmuOk)
+ ON_REGISTERED_MESSAGE(WMU_THREADFINISHED, OnWmuThreadFinished)
+ ON_WM_SYSCOLORCHANGE()
+END_MESSAGE_MAP()
+
+
+BOOL CSelectDrivesDlg::OnInitDialog()
+{
+ CWaitCursor wc;
+
+ CDialog::OnInitDialog();
+
+ if(WMU_THREADFINISHED == 0)
+ {
+ TRACE("RegisterMessage() failed. Using WM_USER + 123\r\n");
+ WMU_THREADFINISHED = WM_USER + 123;
+ }
+
+ ModifyStyle(0, WS_CLIPCHILDREN);
+
+ m_layout.AddControl(IDOK, 1, 0, 0, 0);
+ m_layout.AddControl(IDCANCEL, 1, 0, 0, 0);
+ m_layout.AddControl(IDC_DRIVES, 0, 0, 1, 1);
+ m_layout.AddControl(IDC_AFOLDER, 0, 1, 0, 0);
+ m_layout.AddControl(IDC_FOLDERNAME, 0, 1, 1, 0);
+ m_layout.AddControl(IDC_BROWSEFOLDER, 1, 1, 0, 0);
+
+ m_layout.OnInitDialog(true);
+
+ m_list.ShowGrid(GetOptions()->IsListGrid());
+ m_list.ShowStripes(GetOptions()->IsListStripes());
+ m_list.ShowFullRowSelection(GetOptions()->IsListFullRowSelection());
+
+ m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_HEADERDRAGDROP);
+ // If we set an ImageList here, OnMeasureItem will have no effect ?!
+
+ m_list.InsertColumn(COL_NAME, LoadString(IDS_DRIVECOL_NAME), LVCFMT_LEFT, 120, COL_NAME);
+ m_list.InsertColumn(COL_TOTAL, LoadString(IDS_DRIVECOL_TOTAL), LVCFMT_RIGHT, 55, COL_TOTAL);
+ m_list.InsertColumn(COL_FREE, LoadString(IDS_DRIVECOL_FREE), LVCFMT_RIGHT, 55, COL_FREE);
+ m_list.InsertColumn(COL_GRAPH, LoadString(IDS_DRIVECOL_GRAPH), LVCFMT_LEFT, 100, COL_GRAPH);
+ m_list.InsertColumn(COL_PERCENTUSED,LoadString(IDS_DRIVECOL_PERCENTUSED),LVCFMT_RIGHT, 55, COL_PERCENTUSED);
+
+ m_list.OnColumnsInserted();
+
+ m_folderName = CPersistence::GetSelectDrivesFolder();
+ CPersistence::GetSelectDrivesDrives(m_selectedDrives);
+
+ ShowWindow(SW_SHOWNORMAL);
+ UpdateWindow();
+ BringWindowToTop();
+ SetForegroundWindow();
+
+ DWORD drives = ::GetLogicalDrives();
+ int i;
+ DWORD mask = 0x00000001;
+ for(i = 0; i < wds::iNumDriveLetters; i++, mask <<= 1)
+ {
+ if((drives & mask) == 0)
+ {
+ continue;
+ }
+
+ CString s;
+ s.Format(_T("%c:\\"), i + wds::chrCapA);
+
+ UINT type = ::GetDriveType(s);
+ if(type == DRIVE_UNKNOWN || type == DRIVE_NO_ROOT_DIR)
+ {
+ continue;
+ }
+
+ // The check of remote drives will be done in the background by the CDriveInformationThread.
+ if(type != DRIVE_REMOTE && !DriveExists(s))
+ {
+ continue;
+ }
+
+ CDriveItem *item = new CDriveItem(&m_list, s);
+ m_list.InsertListItem(m_list.GetItemCount(), item);
+ item->StartQuery(m_hWnd, _serial);
+
+ for(int k = 0; k < m_selectedDrives.GetSize(); k++)
+ {
+ if(item->GetDrive() == m_selectedDrives[k])
+ {
+ m_list.SelectItem(item);
+ break;
+ }
+ }
+ }
+
+ m_list.SortItems();
+
+ m_radio = CPersistence::GetSelectDrivesRadio();
+ UpdateData(false);
+
+ switch (m_radio)
+ {
+ case RADIO_ALLLOCALDRIVES:
+ case RADIO_AFOLDER:
+ {
+ m_okButton.SetFocus();
+ }
+ break;
+ case RADIO_SOMEDRIVES:
+ {
+ m_list.SetFocus();
+ }
+ break;
+ }
+
+ UpdateButtons();
+ return false; // we have set the focus.
+}
+
+void CSelectDrivesDlg::OnBnClickedBrowsefolder()
+{
+ // Buffer, because SHBrowseForFolder() wants a buffer
+ CString sDisplayName, sSelectedFolder = m_folderName;
+ BROWSEINFO bi;
+ ZeroMemory(&bi, sizeof(bi));
+
+ // Load a meaningful title for the browse dialog
+ CString title = LoadString(IDS_SELECTFOLDER);
+ bi.hwndOwner = m_hWnd;
+ // Use the CString as buffer (minimum is MAX_PATH as length)
+ bi.pszDisplayName = sDisplayName.GetBuffer(_MAX_PATH);
+ bi.lpszTitle = title;
+ // Set a callback function to pre-select a folder
+ bi.lpfn = BFFCALLBACK(BrowseCallbackProc);
+ bi.lParam = LPARAM(sSelectedFolder.GetBuffer());
+ // Set the required flags
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
+
+ CCoTaskMem<LPITEMIDLIST> pidl = ::SHBrowseForFolder(&bi);
+ // Release the actual buffer
+ sDisplayName.ReleaseBuffer();
+ sSelectedFolder.ReleaseBuffer();
+
+ if(pidl != NULL)
+ {
+ CString sDir;
+
+ CComPtr<IShellFolder> pshf;
+ HRESULT hr = ::SHGetDesktopFolder(&pshf);
+ ASSERT(SUCCEEDED(hr));
+
+ STRRET strret;
+ strret.uType = STRRET_CSTR;
+ hr = pshf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
+ ASSERT(SUCCEEDED(hr));
+ sDir = MyStrRetToString(pidl, &strret);
+
+ m_folderName = sDir;
+ m_radio = RADIO_AFOLDER;
+ UpdateData(false);
+ UpdateButtons();
+ }
+}
+
+void CSelectDrivesDlg::OnOK()
+{
+ UpdateData();
+
+ m_drives.RemoveAll();
+ m_selectedDrives.RemoveAll();
+ if(m_radio == RADIO_AFOLDER)
+ {
+ m_folderName = getFullPathName_(m_folderName);
+ UpdateData(false);
+ }
+
+ for(int i = 0; i < m_list.GetItemCount(); i++)
+ {
+ CDriveItem *item = m_list.GetItem(i);
+
+ if(m_radio == RADIO_ALLLOCALDRIVES && !item->IsRemote() && !item->IsSUBSTed()
+ || m_radio == RADIO_SOMEDRIVES && m_list.IsItemSelected(i))
+ {
+ m_drives.Add(item->GetDrive());
+ }
+ if(m_list.IsItemSelected(i))
+ {
+ m_selectedDrives.Add(item->GetDrive());
+ }
+ }
+
+ CPersistence::SetSelectDrivesRadio(m_radio);
+ CPersistence::SetSelectDrivesFolder(m_folderName);
+ CPersistence::SetSelectDrivesDrives(m_selectedDrives);
+
+ CDialog::OnOK();
+}
+
+void CSelectDrivesDlg::UpdateButtons()
+{
+ UpdateData();
+ bool enableOk = false;
+ switch (m_radio)
+ {
+ case RADIO_ALLLOCALDRIVES:
+ {
+ enableOk = true;
+ }
+ break;
+ case RADIO_SOMEDRIVES:
+ {
+ enableOk = (m_list.GetSelectedCount() > 0);
+ }
+ break;
+ case RADIO_AFOLDER:
+ if(!m_folderName.IsEmpty())
+ {
+ if(m_folderName.GetLength() >= 2 && m_folderName.Left(2) == _T("\\\\"))
+ {
+ enableOk = true;
+ }
+ else
+ {
+ CString pattern = m_folderName;
+ if(pattern.Right(1) != _T("\\"))
+ {
+ pattern += _T("\\");
+ }
+ pattern += _T("*.*");
+ enableOk = FALSE != CFileFind().FindFile(pattern);
+ }
+ }
+ break;
+ default:
+ {
+ ASSERT(0);
+ }
+ }
+ m_okButton.EnableWindow(enableOk);
+}
+
+void CSelectDrivesDlg::OnBnClickedAfolder()
+{
+ UpdateButtons();
+}
+
+void CSelectDrivesDlg::OnBnClickedSomedrives()
+{
+ m_list.SetFocus();
+ UpdateButtons();
+}
+
+void CSelectDrivesDlg::OnEnChangeFoldername()
+{
+ UpdateButtons();
+}
+
+void CSelectDrivesDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT mis)
+{
+ if(nIDCtl == IDC_DRIVES)
+ {
+ mis->itemHeight = 20;
+ }
+ else
+ {
+ CDialog::OnMeasureItem(nIDCtl, mis);
+ }
+}
+
+void CSelectDrivesDlg::OnLvnItemchangedDrives(NMHDR * /*pNMHDR*/, LRESULT *pResult)
+{
+ // unused: LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
+
+ m_radio = RADIO_SOMEDRIVES;
+
+ UpdateData(false);
+ UpdateButtons();
+
+ *pResult = 0;
+}
+
+void CSelectDrivesDlg::OnBnClickedAlllocaldrives()
+{
+ UpdateButtons();
+}
+
+void CSelectDrivesDlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialog::OnSize(nType, cx, cy);
+ m_layout.OnSize();
+}
+
+void CSelectDrivesDlg::OnGetMinMaxInfo(MINMAXINFO* mmi)
+{
+ m_layout.OnGetMinMaxInfo(mmi);
+ CDialog::OnGetMinMaxInfo(mmi);
+}
+
+void CSelectDrivesDlg::OnDestroy()
+{
+ CDriveInformationThread::InvalidateDialogHandle();
+
+ m_layout.OnDestroy();
+ CDialog::OnDestroy();
+}
+
+LRESULT CSelectDrivesDlg::OnWmuOk(WPARAM, LPARAM)
+{
+ OnOK();
+ return 0;
+}
+
+// This message is _sent_ by a CDriveInformationThread.
+//
+LRESULT CSelectDrivesDlg::OnWmuThreadFinished(WPARAM serial, LPARAM lparam)
+{
+ if(serial != _serial)
+ {
+ TRACE("OnWmuThreadFinished: invalid serial (window handle recycled?)\r\n");
+ return 0;
+ }
+
+ CDriveInformationThread *thread = (CDriveInformationThread *)lparam;
+
+ bool success;
+ CString name;
+ ULONGLONG total;
+ ULONGLONG free;
+
+ LPARAM driveItem = thread->GetDriveInformation(success, name, total, free);
+
+ // For paranoia's sake we check, whether driveItem is in our list.
+ // (and we so find its index.)
+ LVFINDINFO fi;
+ ZeroMemory(&fi, sizeof(fi));
+ fi.flags = LVFI_PARAM;
+ fi.lParam = driveItem;
+
+ int i = m_list.FindItem(&fi);
+ if(i == -1)
+ {
+ TRACE("OnWmuThreadFinished: item not found!\r\n");
+ return 0;
+ }
+
+ CDriveItem *item = (CDriveItem *)driveItem;
+
+ item->SetDriveInformation(success, name, total, free);
+
+ m_list.RedrawItems(i, i);
+
+ m_list.SortItems();
+
+ return 0;
+}
+
+void CSelectDrivesDlg::OnSysColorChange()
+{
+ CDialog::OnSysColorChange();
+ m_list.SysColorChanged();
+}
+
+// Callback function for the dialog shown by SHBrowseForFolder()
+int CALLBACK CSelectDrivesDlg::BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch( uMsg )
+ {
+ case BFFM_INITIALIZED:
+ ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
+ break;
+ }
+ return 0;
+}
+
+CString CSelectDrivesDlg::getFullPathName_(LPCTSTR relativePath)
+{
+ LPTSTR dummy;
+ CString buffer;
+
+ DWORD len = _MAX_PATH;
+
+ DWORD dw = ::GetFullPathName(relativePath, len, buffer.GetBuffer(len), &dummy);
+ buffer.ReleaseBuffer();
+
+ while(dw >= len)
+ {
+ len += _MAX_PATH;
+ dw = ::GetFullPathName(relativePath, len, buffer.GetBuffer(len), &dummy);
+ buffer.ReleaseBuffer();
+ }
+
+ if(0 == dw)
+ {
+ TRACE("GetFullPathName(%s) failed: GetLastError returns %u\r\n", relativePath, ::GetLastError());
+ return relativePath;
+ }
+
+ return buffer;
+}
diff --git a/windirstat/Dialogs/SelectDrivesDlg.h b/windirstat/Dialogs/SelectDrivesDlg.h
new file mode 100644
index 0000000..cff7926
--- /dev/null
+++ b/windirstat/Dialogs/SelectDrivesDlg.h
@@ -0,0 +1,195 @@
+// SelectDrivesDlg.h - Declaration of CDriveItem, CDrivesList and CSelectDrivesDlg
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#ifndef __WDS_SELECTDRIVESDLG_H__
+#define __WDS_SELECTDRIVESDLG_H__
+#pragma once
+
+#include "ownerdrawnlistcontrol.h"
+#include "layout.h"
+
+//
+// The dialog has these three radio buttons.
+//
+enum RADIO
+{
+ RADIO_ALLLOCALDRIVES,
+ RADIO_SOMEDRIVES,
+ RADIO_AFOLDER
+};
+
+
+class CDrivesList;
+
+//
+// CDriveItem. An item in the CDrivesList Control.
+// All methods are called by the gui thread.
+//
+class CDriveItem: public COwnerDrawnListItem
+{
+public:
+ CDriveItem(CDrivesList *list, LPCTSTR pszPath);
+ void StartQuery(HWND dialog, UINT serial);
+
+ void SetDriveInformation(bool success, LPCTSTR name, ULONGLONG total, ULONGLONG free);
+
+ virtual int Compare(const CSortingListItem *other, int subitem) const;
+
+ CString GetPath() const;
+ CString GetDrive() const;
+ bool IsRemote() const;
+ bool IsSUBSTed() const;
+ virtual bool DrawSubitem(int subitem, CDC *pdc, CRect rc, UINT state, int *width, int *focusLeft) const;
+ virtual CString GetText(int subitem) const;
+ int GetImage() const;
+
+private:
+ CDrivesList *m_list; // Backpointer
+ CString m_path; // e.g. "C:\"
+ bool m_isRemote; // Whether the drive type is DRIVE_REMOTE (network drive)
+
+ bool m_querying; // Information thread is running.
+ bool m_success; // Drive is accessible. false while m_querying is true.
+
+ CString m_name; // e.g. "BOOT (C:)"
+ ULONGLONG m_totalBytes; // Capacity
+ ULONGLONG m_freeBytes; // Free space
+
+ double m_used; // used space / total space
+};
+
+//
+// CDriveInformationThread. Does the GetVolumeInformation() call, which
+// may hang for ca. 30 sec, it a network drive is not accessible.
+//
+class CDriveInformationThread: public CWinThread
+{
+ // Set of all running CDriveInformationThreads.
+ // Used by InvalidateDialogHandle().
+ static CSet<CDriveInformationThread *, CDriveInformationThread *> _runningThreads;
+ static CCriticalSection _csRunningThreads;
+
+ // The objects register and unregister themselves in _runningThreads
+ void AddRunningThread();
+ void RemoveRunningThread();
+
+public:
+ static void InvalidateDialogHandle();
+ static void OnAppExit();
+
+ CDriveInformationThread(LPCTSTR path, LPARAM driveItem, HWND dialog, UINT serial);
+ virtual BOOL InitInstance();
+
+ LPARAM GetDriveInformation(bool& success, CString& name, ULONGLONG& total, ULONGLONG& free);
+
+private:
+ const CString m_path; // Path like "C:\"
+ const LPARAM m_driveItem; // The list item, we belong to
+
+ CCriticalSection m_cs; // for m_dialog
+ HWND m_dialog; // synchronized by m_cs
+ const UINT m_serial; // serial number of m_dialog
+
+ // "[out]"-parameters
+ CString m_name; // Result: name like "BOOT (C:)", valid if m_success
+ ULONGLONG m_totalBytes; // Result: capacity of the drive, valid if m_success
+ ULONGLONG m_freeBytes; // Result: free space on the drive, valid if m_success
+ bool m_success; // Result: false, iff drive is unaccessible.
+};
+
+//
+// CDrivesList.
+//
+class CDrivesList: public COwnerDrawnListControl
+{
+ DECLARE_DYNAMIC(CDrivesList)
+public:
+ CDrivesList();
+ CDriveItem *GetItem(int i);
+ void SelectItem(CDriveItem *item);
+ bool IsItemSelected(int i);
+
+ virtual bool HasImages();
+
+ DECLARE_MESSAGE_MAP()
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+ afx_msg void OnLvnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+ afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
+};
+
+
+//
+// CSelectDrivesDlg. The initial dialog, where the user can select
+// one or more drives or a folder for scanning.
+//
+class CSelectDrivesDlg : public CDialog
+{
+ DECLARE_DYNAMIC(CSelectDrivesDlg)
+ enum { IDD = IDD_SELECTDRIVES };
+ static CString getFullPathName_(LPCTSTR relativePath);
+
+public:
+ CSelectDrivesDlg(CWnd* pParent = NULL);
+ virtual ~CSelectDrivesDlg();
+
+ // Dialog Data
+ int m_radio; // out.
+ CString m_folderName; // out. Valid if m_radio = RADIO_AFOLDER
+ CStringArray m_drives; // out. Valid if m_radio != RADIO_AFOLDER
+
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX);
+ virtual BOOL OnInitDialog();
+ virtual void OnOK();
+
+ void UpdateButtons();
+
+ static UINT _serial; // Each Instance of this dialog gets a serial number
+ CDrivesList m_list;
+ CButton m_okButton;
+ CStringArray m_selectedDrives;
+ CLayout m_layout;
+ // Callback function for the dialog shown by SHBrowseForFolder()
+ // MUST be static!
+ static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+
+ DECLARE_MESSAGE_MAP()
+ afx_msg void OnBnClickedBrowsefolder();
+ afx_msg void OnLbnSelchangeDrives();
+ afx_msg void OnBnClickedAlllocaldrives();
+ afx_msg void OnBnClickedAfolder();
+ afx_msg void OnBnClickedSomedrives();
+ afx_msg void OnEnChangeFoldername();
+ afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+ afx_msg void OnLvnItemchangedDrives(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+ afx_msg void OnDestroy();
+ afx_msg LRESULT OnWmuOk(WPARAM, LPARAM);
+ afx_msg LRESULT OnWmuThreadFinished(WPARAM, LPARAM lparam);
+ afx_msg void OnSysColorChange();
+};
+
+#endif // __WDS_SELECTDRIVESDLG_H__
diff --git a/windirstat/Dialogs/aboutdlg.cpp b/windirstat/Dialogs/aboutdlg.cpp
new file mode 100644
index 0000000..debbd80
--- /dev/null
+++ b/windirstat/Dialogs/aboutdlg.cpp
@@ -0,0 +1,329 @@
+// aboutdlg.cpp - Implementation of the StartAboutDialog() function
+//
+// WinDirStat - Directory Statistics
+// Copyright (C) 2003-2005 Bernhard Seifert
+// Copyright (C) 2004-2006, 2008 Oliver Schneider (assarbad.net)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author(s): - bseifert -> http://windirstat.info/contact/bernhard/
+// - assarbad -> http://windirstat.info/contact/oliver/
+//
+
+#include "stdafx.h"
+#include "windirstat.h"
+#include <common/version.h>
+#include "aboutdlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+namespace
+{
+ enum
+ {
+ RE_CONTROL = 4711 // Id of the RichEdit Control
+ };
+
+ // Tabs
+ enum
+ {
+ TAB_ABOUT,
+ TAB_AUTHORS,
+ TAB_THANKSTO,
+ TAB_LICENSE
+ };
+
+ // Retrieve the GPL text from our resources
+ CString GetTextResource(UINT id, HMODULE dll = AfxGetResourceHandle())
+ {
+ CString s;
+
+ HGLOBAL hresource = NULL;
+ try
+ {
+ HRSRC hrsrc = ::FindResource(dll, MAKEINTRESOURCE(id), _T("TEXT"));
+ if(NULL == hrsrc)
+ {
+ MdThrowLastWinerror();
+ }
+
+ DWORD dwSize = ::SizeofResource(dll, hrsrc);
+ if(0 == dwSize)
+ {
+ MdThrowLastWinerror();
+ }
+
+ hresource = ::LoadResource(dll, hrsrc);
+ const BYTE *pData = (const BYTE *)::LockResource(hresource);
+
+ CComBSTR bstr(dwSize, (LPCSTR)pData);
+
+ s = bstr;
+ }
+ catch (CException *pe)
+ {
+ pe->ReportError();
+ pe->Delete();
+ }
+
+ if(hresource != NULL)
+ {
+ ::FreeResource(hresource);
+ }
+
+ return s;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void StartAboutDialog()
+{
+ AfxBeginThread(RUNTIME_CLASS(CAboutThread), NULL);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNCREATE(CAboutThread, CWinThread);
+
+BOOL CAboutThread::InitInstance()
+{
+ CWinThread::InitInstance();
+
+ CAboutDlg dlg;
+ dlg.DoModal();
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void CAboutDlg::CMyTabControl::Initialize()
+{
+ ModifyStyle(0, WS_CLIPCHILDREN);
+
+ InsertItem(TAB_ABOUT, LPCTSTR(LoadString(IDS_ABOUT_ABOUT)));
+ InsertItem(TAB_AUTHORS, LPCTSTR(LoadString(IDS_ABOUT_AUTHORS)));
+ InsertItem(TAB_THANKSTO, LPCTSTR(LoadString(IDS_ABOUT_THANKSTO)));
+ InsertItem(TAB_LICENSE, LPCTSTR(LoadString(IDS_ABOUT_LICENSEAGREEMENT)));
+
+ CRect rc;
+ GetClientRect(rc);
+
+ CRect rcItem;
+ GetItemRect(0, rcItem);
+
+ rc.top = rcItem.bottom;
+
+ VERIFY(m_text.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER | ES_MULTILINE | ES_READONLY, rc, this, RE_CONTROL));
+ SetPageText(TAB_ABOUT);
+}
+
+void CAboutDlg::CMyTabControl::SetPageText(int tab)
+{
+ USES_CONVERSION;
+
+ CString text, translators;
+ DWORD newStyle = ES_CENTER;
+
+ switch (tab)
+ {
+ case TAB_ABOUT:
+ {
+ text.FormatMessage(IDS_ABOUT_ABOUTTEXTss, GetAuthorEmail(), GetWinDirStatHomepage());
+ }
+ break;
+ case TAB_AUTHORS:
+ {
+ text.FormatMessage(IDS_ABOUT_AUTHORSTEXTs, GetAuthorEmail());
+ translators.LoadString(IDS_TRANSLATORS);
+ text += translators;
+ // Anti-spam: avoid e-mail addresses in source-code:
+ text.Replace(wds::chrSharp, wds::chrAt);
+ }
+ break;
+ case TAB_THANKSTO:
+ {
+ text.LoadString(IDS_ABOUT_THANKSTOTEXT);
+ }
+ break;
+ case TAB_LICENSE:
+ {
+ text = GetTextResource(IDR_LICENSE, NULL);
+ newStyle = ES_LEFT;
+ }
+ break;
+ default:
+ {
+ ASSERT(0);
+ }
+ }
+ CRect rc;
+ m_text.GetWindowRect(rc);
+ ScreenToClient(rc);
+
+ DWORD style = m_text.GetStyle();
+ style &= ~ES_CENTER;
+ style |= newStyle | WS_VSCROLL;
+
+ DWORD exstyle = m_text.GetExStyle();
+
+ m_text.DestroyWindow();
+
+ m_text.Create(style, rc, this, RE_CONTROL);
+ if(exstyle)
+ {
+ m_text.ModifyStyleEx(0, exstyle);
+ }
+
+ m_text.SetAutoURLDetect();
+ m_text.SetEventMask(ENM_LINK | ENM_KEYEVENTS);
+ m_text.SetFont(GetFont());
+
+ m_text.SetWindowText(text);
+
+ m_text.HideCaret();
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg::CMyTabControl, CTabCtrl)
+ ON_NOTIFY(EN_LINK, RE_CONTROL, OnEnLinkText)
+ ON_NOTIFY(EN_MSGFILTER, RE_CONTROL, OnEnMsgFilter)
+ ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+void CAboutDlg::CMyTabControl::OnEnLinkText(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ ENLINK *el = reinterpret_cast<ENLINK *>(pNMHDR);
+ *pResult = 0;
+
+ if(WM_LBUTTONDOWN == el->msg)
+ {
+ CString link;
+ m_text.GetTextRange(el->chrg.cpMin, el->chrg.cpMax, link);
+
+ // FIXME: should probably one of the helper variants of this function
+ ::ShellExecute(*this, NULL, link, NULL, wds::strEmpty, SW_SHOWNORMAL);
+ }
+}
+
+void CAboutDlg::CMyTabControl::OnEnMsgFilter(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ MSGFILTER *mf = reinterpret_cast<MSGFILTER *>(pNMHDR);
+ *pResult = 0;
+
+ if(WM_KEYDOWN == mf->msg && (VK_ESCAPE == mf->wParam || VK_TAB == mf->wParam))
+ {
+ // Move the focus back to the Tab control
+ SetFocus();
+
+ // If we didn't ignore VK_ESCAPE here, strange things happen:
+ // both m_text and the Tab control would disappear.
+ *pResult = 1;
+ }
+}
+
+void CAboutDlg::CMyTabControl::OnSize(UINT nType, int cx, int cy)
+{
+ CTabCtrl::OnSize(nType, cx, cy);
+
+ if(::IsWindow(m_text.m_hWnd))
+ {
+ CRect rc;
+ GetClientRect(rc);
+
+ CRect rcItem;
+ GetItemRect(0, rcItem);
+
+ rc.top = rcItem.bottom;
+
+ m_text.MoveWindow(rc);
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+CAboutDlg::CAboutDlg()
+ : CDialog(CAboutDlg::IDD)
+ , m_layout(this, _T("aboutdlg"))
+{
+}
+
+CString CAboutDlg::GetAppVersion()
+{
+ USES_CONVERSION;
+
+ CString s;
+ s.Format(_T("WinDirStat %s"), A2T(VN_STRING_EXE));
+ return s;
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_CAPTION, m_caption);
+ DDX_Control(pDX, IDC_TAB, m_tab);
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+ ON_NOTIFY(TCN_SELCHANGE, IDC_TAB, OnTcnSelchangeTab)
+ ON_WM_SIZE()
+ ON_WM_GETMINMAXINFO()
+ ON_WM_DESTROY()
+END_MESSAGE_MAP()
+
+BOOL CAboutDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ m_layout.AddControl(IDC_CAPTION, 0.5, 0, 0, 0);
+ m_layout.AddControl(IDC_TAB, 0, 0, 1, 1);
+ m_layout.AddControl(IDOK, 0.5, 1, 0, 0);
+
+ m_layout.OnInitDialog(true);
+
+ m_tab.Initialize();
+ m_caption.SetWindowText(GetAppVersion());
+
+ return true;
+}
+
+void CAboutDlg::OnTcnSelchangeTab(NMHDR * /* pNMHDR */, LRESULT *pResult)
+{
+ *pResult = 0;
+ m_tab.SetPageText(m_tab.GetCurSel());
+}
+
+void CAboutDlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialog::OnSize(nType, cx, cy);
+ m_layout.OnSize();
+}
+
+
+void CAboutDlg::OnGetMinMaxInfo(MINMAXINFO* mmi)
+{
+ m_layout.OnGetMinMaxInfo(mmi);
+ CDialog::OnGetMinMaxInfo(mmi);
+
+}
+
+void CAboutDlg::OnDestroy()
+{
+ m_layout.OnDestroy();
+ CDialog::OnDestroy();
+}