diff --git a/intl/convert.bat b/intl/convert.bat index d5f608d..c2e829b 100755 --- a/intl/convert.bat +++ b/intl/convert.bat @@ -1,20 +1,19 @@ -@echo off -setlocal EnableDelayedExpansion -set SCRIPTDIR=%CD% -set PRJDIR=%SCRIPTDIR%\.. -set QTPATH=C:\Qt\5.3\mingw482_32 - -echo Converting localizations -del %PRJDIR%\rsrc\intl\* -if not exist %PRJDIR%\rsrc\intl\ mkdir %PRJDIR%\rsrc\intl\ - -REM Convert all except the en_US which is -REM the original text in the code - -%QTPATH%\bin\lrelease de_DE.ts -qm ..\rsrc\intl\de_DE.qm -%QTPATH%\bin\lrelease el_GR.ts -qm ..\rsrc\intl\el_GR.qm -%QTPATH%\bin\lrelease es_ES.ts -qm ..\rsrc\intl\es_ES.qm -%QTPATH%\bin\lrelease fr_FR.ts -qm ..\rsrc\intl\fr_FR.qm -%QTPATH%\bin\lrelease ru_RU.ts -qm ..\rsrc\intl\ru_RU.qm - -endlocal +@echo off +setlocal EnableDelayedExpansion +set SCRIPTDIR=%CD% +set PRJDIR=%SCRIPTDIR%\.. +set QTPATH=C:\Qt\Qt5.3.1\5.3\mingw482_32 + +echo Converting localizations +del /q %PRJDIR%\rsrc\intl\* +if not exist %PRJDIR%\rsrc\intl\ mkdir %PRJDIR%\rsrc\intl\ + +REM Convert all except the en_US which is the original text in the code + +%QTPATH%\bin\lrelease de_DE.ts -qm ..\rsrc\intl\de_DE.qm +%QTPATH%\bin\lrelease el_GR.ts -qm ..\rsrc\intl\el_GR.qm +%QTPATH%\bin\lrelease es_ES.ts -qm ..\rsrc\intl\es_ES.qm +%QTPATH%\bin\lrelease fr_FR.ts -qm ..\rsrc\intl\fr_FR.qm +%QTPATH%\bin\lrelease ru_RU.ts -qm ..\rsrc\intl\ru_RU.qm + +endlocal diff --git a/manifest b/manifest index 7966277..42fe1ac 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Simplified\slocalisation\sconversion\sscript -D 2014-07-15T15:10:02.206 +C Comment\sfiles\snow\sstart\swith\sa\sUTF-8\sBOM\s\nAdded\san\s"Apply"\sMessageBox\sbutton\sto\shandle\sthe\sconvert\soption\sasked\sby\sfossil\nConverted\sQ_WS_*\sto\sQ_OS_*\ssince\sthe\sfirst\sno\slonger\sexists\sin\sQT5 +D 2014-07-28T10:38:37.856 F dist/arch/PKGBUILD 1d72dad77767f94a6b1a018067188e61927fa564 F dist/win/fuel.iss ef3558dbba409eb194938b930377fc9ee27d319e F doc/Building.txt 7c0f1060d4a08ed330058d4a3a68905c05228381 F doc/Changes.txt cc626cd9352d7e630c5cd0a74f35fdc6180a8bf9 F doc/License.txt 4cc77b90af91e615a64ae04893fdffa7939db84c F fuel.pro d15cce9435cf605947ae41e53869020e90563336 -F intl/convert.bat bbe13b51e51d01b8f3bf78af4857cf5416b7d036 x +F intl/convert.bat 90152e8b17c9c9bd79d8bf99fa70b9c4258064ec x F intl/convert.sh 5694496585ff5f4363c90ff8b6f48e19e0b6b4aa x F intl/de_DE.ts 4acf6f379792a7e425ea143d440e8d5c01b391aa F intl/el_GR.ts e8f071623fe4abba239525faffb40c2668213562 @@ -187,13 +187,13 @@ F src/FileTableView.cpp 5ddf8c391c9a3ac449ec61fb1db837b577afeec2 F src/FileTableView.h 03e56d87c2d46411b9762b87f4d301619aaf18df F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261 -F src/MainWindow.cpp f5b550c638659e48dd618d99309261b828fde0e2 +F src/MainWindow.cpp 2db7b4ca002c61985432fcf71c97a6a1ab482f3f F src/MainWindow.h 3e0ed4d5f6a531401e0aed92d1cd0eb29543d62b -F src/SettingsDialog.cpp 91bf5225e85bbe5544ac10d4d1182b09b4dc4c30 +F src/SettingsDialog.cpp effff92f746a71b07f0e6a72a21caac5a9085123 F src/SettingsDialog.h 01c1f876c64f750ba8820a0d745e377acabe4921 -F src/Utils.cpp caca5268e3194abe77211040bf9511a82909d2e6 -F src/Utils.h 5af911147390879176e587fc60fb662490bb9e97 -F src/main.cpp 8f8790822f82870a12169bcf204e571138adb065 +F src/Utils.cpp 9aff456712e4276b49083426301b3b96d3819c77 +F src/Utils.h c546e478a1225a28c99cd4c30f70cf9be9804a2a +F src/main.cpp 8db6ff84fc37464645415ef74562b328d2c5abc5 F tools/pack.sh d7f38a498c4e9327fecd6a6e5ac27be270d43008 x F ui/BrowserWidget.ui 5ad98b13773afadb20a1a2c22148aaebe5dbd95d F ui/CloneDialog.ui 0fc820804df91f16506ee466a44519fdd44e468f @@ -201,7 +201,7 @@ F ui/CommitDialog.ui 6200f6cabdcf40a20812e811be28e0793f82516f F ui/FileActionDialog.ui 89bb4dc2d0b8adcd41adcb11ec65f2028a09a12d F ui/MainWindow.ui 7ede8bbb54513e0771fdf5d5a2566d88c81b73ad F ui/SettingsDialog.ui 55aefad7145c40d936c43759789d1b50e361b020 -P e57b41e07e0ab31a1b6a949211352224145a3d44 -R 06473a96180a1a67aeed741ac68aa542 -U kostas -Z 693ca7eab8d1a063fb213e373519b433 +P 05251390b4dac6dc122efb007cd84650e410a0d1 +R 8e737c57d203e492166f8d579f5e0a13 +U Kostas +Z 3b353f1973572f26eb2307e7504f1871 diff --git a/manifest.uuid b/manifest.uuid index 572db87..9c3928f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -05251390b4dac6dc122efb007cd84650e410a0d1 \ No newline at end of file +f99bd8ac7960cb1758222d2211937e99708f67f3 \ No newline at end of file diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b159dcf..997fa08 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -27,6 +27,7 @@ #define COUNTOF(array) (sizeof(array)/sizeof(array[0])) #define PATH_SEP "/" +static const unsigned char UTF8_BOM[] = { 0xEF, 0xBB, 0xBF }; //----------------------------------------------------------------------------- enum @@ -211,8 +212,8 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP ui->statusBar->insertPermanentWidget(0, progressBar); progressBar->setVisible(false); -#ifdef Q_WS_MACX - // Native applications on OSX don't use menu icons +#ifdef Q_OS_MACX + // Native applications on OSX don't have menu icons foreach(QAction *a, ui->menuBar->actions()) a->setIconVisibleInMenu(false); foreach(QAction *a, ui->menuFile->actions()) @@ -1104,11 +1105,12 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int QString ans_yes = 'y' + EOL_MARK; QString ans_no = 'n' + EOL_MARK; QString ans_always = 'a' + EOL_MARK; + QString ans_convert = 'c' + EOL_MARK; fossilAbort = false; QString buffer; -#ifdef Q_WS_WIN32 +#ifdef Q_OS_WIN QTextCodec *codec = QTextCodec::codecForName("UTF-8"); #else QTextCodec *codec = QTextCodec::codecForLocale(); @@ -1129,7 +1131,7 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int if(fossilAbort) { log("\n* "+tr("Terminated")+" *\n"); - #ifdef Q_WS_WIN + #ifdef Q_OS_WIN // Verify this is still true on Qt5 process.kill(); // QT on windows cannot terminate console processes with QProcess::terminate #else process.terminate(); @@ -1200,11 +1202,19 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int buffer = buffer.mid(last_line_start+1) ; // Now process any query - if(have_query && (have_yna_query || have_acyn_query)) // FIXME: We are not handling the "convert" part + if(have_query && (have_yna_query || have_acyn_query)) { log(last_line); QString query = ParseFossilQuery(last_line); - QMessageBox::StandardButton res = DialogQuery(this, "Fossil", query, QMessageBox::YesToAll|QMessageBox::Yes|QMessageBox::No); + QMessageBox::StandardButtons buttons = QMessageBox::YesToAll|QMessageBox::Yes|QMessageBox::No; + + // Map the Convert option to the Apply button + if(have_acyn_query) + { + buttons |= QMessageBox::Apply; + } + + QMessageBox::StandardButton res = DialogQuery(this, "Fossil", query, buttons); if(res==QMessageBox::Yes) { process.write(ans_yes.toLatin1()); @@ -1215,6 +1225,11 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int process.write(ans_always.toLatin1()); log("A\n"); } + else if(res==QMessageBox::Apply) + { + process.write(ans_convert.toLatin1()); + log("C\n"); + } else { process.write(ans_no.toLatin1()); @@ -1286,7 +1301,7 @@ QString MainWindow::getFossilPath() return QDir::toNativeSeparators(fossil_path); QString fossil_exe = "fossil"; -#ifdef Q_WS_WIN32 +#ifdef Q_OS_WIN fossil_exe += ".exe"; #endif // Use our fossil if available @@ -1638,7 +1653,7 @@ void MainWindow::stopUI() { if(uiRunning()) { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN fossilUI.kill(); // QT on windows cannot terminate console processes with QProcess::terminate #else fossilUI.terminate(); @@ -1783,6 +1798,10 @@ void MainWindow::on_actionCommit_triggered() return; } + // Write BOM + comment_file.write(reinterpret_cast(UTF8_BOM), sizeof(UTF8_BOM)); + + // Write Comment comment_file.write(msg.toUtf8()); comment_file.close(); @@ -2514,7 +2533,7 @@ void MainWindow::on_textBrowser_customContextMenuRequested(const QPoint &pos) void MainWindow::on_tableView_customContextMenuRequested(const QPoint &pos) { QPoint gpos = QCursor::pos(); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN if(qApp->keyboardModifiers() & Qt::SHIFT) { ui->tableView->selectionModel()->select(ui->tableView->indexAt(pos), QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Rows); @@ -2525,7 +2544,7 @@ void MainWindow::on_tableView_customContextMenuRequested(const QPoint &pos) { QString fname = getCurrentWorkspace() + PATH_SEP + fnames[0]; fname = QDir::toNativeSeparators(fname); - if(ShowExplorerMenu(winId(), fname, gpos)) + if(ShowExplorerMenu((HWND)winId(), fname, gpos)) refresh(); } } diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index eb3470e..17d0b73 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -15,7 +15,7 @@ QString SettingsDialog::SelectExe(QWidget *parent, const QString &description) { QString filter(tr("Applications")); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN filter += " (*.exe)"; #else filter += " (*)"; diff --git a/src/Utils.cpp b/src/Utils.cpp index 20540a0..18ccce2 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,293 +1,293 @@ -#include "Utils.h" -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons) -{ - QMessageBox mb(QMessageBox::Question, title, query, buttons, parent, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet ); - mb.setDefaultButton(QMessageBox::No); - mb.setWindowModality(Qt::WindowModal); - mb.setModal(true); - mb.exec(); - QMessageBox::StandardButton res = mb.standardButton(mb.clickedButton()); - return res; -} - -//----------------------------------------------------------------------------- -#if 0 // Unused -#include - -static bool DialogQueryText(QWidget *parent, const QString &title, const QString &query, QString &text, bool isPassword=false) -{ - QInputDialog dlg(parent, Qt::Sheet); - dlg.setWindowTitle(title); - dlg.setInputMode(QInputDialog::TextInput); - dlg.setWindowModality(Qt::WindowModal); - dlg.setModal(true); - dlg.setLabelText(query); - dlg.setTextValue(text); - if(isPassword) - dlg.setTextEchoMode(QLineEdit::Password); - - if(dlg.exec() == QDialog::Rejected) - return false; - - text = dlg.textValue(); - return true; -} -#endif - - -#ifdef Q_WS_WIN -// Explorer File Context Menu support. Based on http://www.microsoft.com/msj/0497/wicked/wicked0497.aspx -#include - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// FUNCTION: DoExplorerMenu -// -// DESCRIPTION: Given a path name to a file or folder object, displays -// the shell's context menu for that object and executes -// the menu command (if any) selected by the user. -// -// INPUT: hwnd = Handle of the window in which the menu will be -// displayed. -// -// pszPath = Pointer to an ANSI or Unicode string -// specifying the path to the object. -// -// point = x and y coordinates of the point where the -// menu's upper left corner should be located, in -// client coordinates relative to hwnd. -// -// RETURNS: TRUE if successful, FALSE if not. -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint) -{ - struct Util - { - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // FUNCTION: GetNextItem - // DESCRIPTION: Finds the next item in an item ID list. - // INPUT: pidl = Pointer to an item ID list. - // RETURNS: Pointer to the next item. - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - static LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl) - { - USHORT nLen; - - if ((nLen = pidl->mkid.cb) == 0) - return NULL; - - return (LPITEMIDLIST) (((LPBYTE) pidl) + nLen); - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // FUNCTION: GetItemCount - // DESCRIPTION: Computes the number of item IDs in an item ID list. - // INPUT: pidl = Pointer to an item ID list. - // RETURNS: Number of item IDs in the list. - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - static UINT GetItemCount (LPITEMIDLIST pidl) - { - USHORT nLen; - UINT nCount; - - nCount = 0; - while ((nLen = pidl->mkid.cb) != 0) { - pidl = GetNextItem (pidl); - nCount++; - } - return nCount; - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // FUNCTION: DuplicateItem - // DESCRIPTION: Makes a copy of the next item in an item ID list. - // INPUT: pMalloc = Pointer to an IMalloc interface. - // pidl = Pointer to an item ID list. - // RETURNS: Pointer to an ITEMIDLIST containing the copied item ID. - // NOTES: It is the caller's responsibility to free the memory - // allocated by this function when the item ID is no longer - // needed. Example: - // pidlItem = DuplicateItem (pMalloc, pidl); - // . - // . - // . - // pMalloc->lpVtbl->Free (pMalloc, pidlItem); - // Failure to free the ITEMIDLIST will result in memory - // leaks. - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - static LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl) - { - USHORT nLen; - LPITEMIDLIST pidlNew; - - nLen = pidl->mkid.cb; - if (nLen == 0) - return NULL; - - pidlNew = (LPITEMIDLIST) pMalloc->Alloc ( - nLen + sizeof (USHORT)); - if (pidlNew == NULL) - return NULL; - - CopyMemory (pidlNew, pidl, nLen); - *((USHORT*) (((LPBYTE) pidlNew) + nLen)) = 0; - - return pidlNew; - } - }; - - - LPITEMIDLIST pidlMain, pidlItem, pidlNextItem, *ppidl; - UINT nCount; - POINT point; - point.x = qpoint.x(); - point.y = qpoint.y(); - - WCHAR wchPath[MAX_PATH]; - memset(wchPath, 0, sizeof(wchPath)); - Q_ASSERT(path.length()Release(); - return bResult; - } - - // - // Convert the path name into a pointer to an item ID list (pidl). - // - ULONG ulCount, ulAttr; - if (SUCCEEDED (psfFolder->ParseDisplayName (hwnd, - NULL, wchPath, &ulCount, &pidlMain, &ulAttr)) && (pidlMain != NULL)) { - - if ( (nCount = Util::GetItemCount (pidlMain))>0) { // nCount must be > 0 - // - // Initialize psfFolder with a pointer to the IShellFolder - // interface of the folder that contains the item whose context - // menu we're after, and initialize pidlItem with a pointer to - // the item's item ID. If nCount > 1, this requires us to walk - // the list of item IDs stored in pidlMain and bind to each - // subfolder referenced in the list. - // - pidlItem = pidlMain; - - while (--nCount) { - // - // Create a 1-item item ID list for the next item in pidlMain. - // - pidlNextItem = Util::DuplicateItem (pMalloc, pidlItem); - if (pidlNextItem == NULL) { - pMalloc->Free(pidlMain); - psfFolder->Release (); - pMalloc->Release (); - return bResult; - } - - // - // Bind to the folder specified in the new item ID list. - // - LPSHELLFOLDER psfNextFolder; - if (!SUCCEEDED (psfFolder->BindToObject ( - pidlNextItem, NULL, IID_IShellFolder, (void**)&psfNextFolder))) { - pMalloc->Free (pidlNextItem); - pMalloc->Free (pidlMain); - psfFolder->Release (); - pMalloc->Release (); - return bResult; - } - - // - // Release the IShellFolder pointer to the parent folder - // and set psfFolder equal to the IShellFolder pointer for - // the current folder. - // - psfFolder->Release (); - psfFolder = psfNextFolder; - - // - // Release the storage for the 1-item item ID list we created - // just a moment ago and initialize pidlItem so that it points - // to the next item in pidlMain. - // - pMalloc->Free(pidlNextItem); - pidlItem = Util::GetNextItem (pidlItem); - } - - // - // Get a pointer to the item's IContextMenu interface and call - // IContextMenu::QueryContextMenu to initialize a context menu. - // - ppidl = &pidlItem; - LPCONTEXTMENU pContextMenu; - if (SUCCEEDED (psfFolder->GetUIObjectOf ( - hwnd, 1, (const ITEMIDLIST **)ppidl, IID_IContextMenu, NULL, (void**)&pContextMenu))) { - - HMENU hMenu = CreatePopupMenu (); - if (SUCCEEDED (pContextMenu->QueryContextMenu ( - hMenu, 0, 1, 0x7FFF, CMF_EXPLORE))) { - - - // - // Display the context menu. - // - UINT nCmd = TrackPopupMenu (hMenu, TPM_LEFTALIGN | - TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, - point.x, point.y, 0, hwnd, NULL); - - - // - // If a command was selected from the menu, execute it. - // - if (nCmd) { - CMINVOKECOMMANDINFO ici; - memset(&ici, 0, sizeof(ici) ); - ici.cbSize = sizeof (CMINVOKECOMMANDINFO); - ici.fMask = 0; - ici.hwnd = hwnd; - ici.lpVerb = MAKEINTRESOURCEA (nCmd - 1); - ici.lpParameters = NULL; - ici.lpDirectory = NULL; - ici.nShow = SW_SHOWNORMAL; - ici.dwHotKey = 0; - ici.hIcon = NULL; - - if (SUCCEEDED ( - pContextMenu->InvokeCommand ( - (CMINVOKECOMMANDINFO*)&ici))) - bResult = true; - } - } - DestroyMenu (hMenu); - pContextMenu->Release (); - } - } - pMalloc->Free (pidlMain); - } - - // - // Clean up and return. - // - psfFolder->Release (); - pMalloc->Release (); - - return bResult; -} - -#endif - +#include "Utils.h" +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons) +{ + QMessageBox mb(QMessageBox::Question, title, query, buttons, parent, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::Sheet ); + mb.setDefaultButton(QMessageBox::No); + mb.setWindowModality(Qt::WindowModal); + mb.setModal(true); + mb.exec(); + QMessageBox::StandardButton res = mb.standardButton(mb.clickedButton()); + return res; +} + +//----------------------------------------------------------------------------- +#if 0 // Unused +#include + +static bool DialogQueryText(QWidget *parent, const QString &title, const QString &query, QString &text, bool isPassword=false) +{ + QInputDialog dlg(parent, Qt::Sheet); + dlg.setWindowTitle(title); + dlg.setInputMode(QInputDialog::TextInput); + dlg.setWindowModality(Qt::WindowModal); + dlg.setModal(true); + dlg.setLabelText(query); + dlg.setTextValue(text); + if(isPassword) + dlg.setTextEchoMode(QLineEdit::Password); + + if(dlg.exec() == QDialog::Rejected) + return false; + + text = dlg.textValue(); + return true; +} +#endif + + +#ifdef Q_OS_WIN +// Explorer File Context Menu support. Based on http://www.microsoft.com/msj/0497/wicked/wicked0497.aspx +#include + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// FUNCTION: DoExplorerMenu +// +// DESCRIPTION: Given a path name to a file or folder object, displays +// the shell's context menu for that object and executes +// the menu command (if any) selected by the user. +// +// INPUT: hwnd = Handle of the window in which the menu will be +// displayed. +// +// pszPath = Pointer to an ANSI or Unicode string +// specifying the path to the object. +// +// point = x and y coordinates of the point where the +// menu's upper left corner should be located, in +// client coordinates relative to hwnd. +// +// RETURNS: TRUE if successful, FALSE if not. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint) +{ + struct Util + { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // FUNCTION: GetNextItem + // DESCRIPTION: Finds the next item in an item ID list. + // INPUT: pidl = Pointer to an item ID list. + // RETURNS: Pointer to the next item. + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + static LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl) + { + USHORT nLen; + + if ((nLen = pidl->mkid.cb) == 0) + return NULL; + + return (LPITEMIDLIST) (((LPBYTE) pidl) + nLen); + } + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // FUNCTION: GetItemCount + // DESCRIPTION: Computes the number of item IDs in an item ID list. + // INPUT: pidl = Pointer to an item ID list. + // RETURNS: Number of item IDs in the list. + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + static UINT GetItemCount (LPITEMIDLIST pidl) + { + USHORT nLen; + UINT nCount; + + nCount = 0; + while ((nLen = pidl->mkid.cb) != 0) { + pidl = GetNextItem (pidl); + nCount++; + } + return nCount; + } + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // FUNCTION: DuplicateItem + // DESCRIPTION: Makes a copy of the next item in an item ID list. + // INPUT: pMalloc = Pointer to an IMalloc interface. + // pidl = Pointer to an item ID list. + // RETURNS: Pointer to an ITEMIDLIST containing the copied item ID. + // NOTES: It is the caller's responsibility to free the memory + // allocated by this function when the item ID is no longer + // needed. Example: + // pidlItem = DuplicateItem (pMalloc, pidl); + // . + // . + // . + // pMalloc->lpVtbl->Free (pMalloc, pidlItem); + // Failure to free the ITEMIDLIST will result in memory + // leaks. + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + static LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl) + { + USHORT nLen; + LPITEMIDLIST pidlNew; + + nLen = pidl->mkid.cb; + if (nLen == 0) + return NULL; + + pidlNew = (LPITEMIDLIST) pMalloc->Alloc ( + nLen + sizeof (USHORT)); + if (pidlNew == NULL) + return NULL; + + CopyMemory (pidlNew, pidl, nLen); + *((USHORT*) (((LPBYTE) pidlNew) + nLen)) = 0; + + return pidlNew; + } + }; + + + LPITEMIDLIST pidlMain, pidlItem, pidlNextItem, *ppidl; + UINT nCount; + POINT point; + point.x = qpoint.x(); + point.y = qpoint.y(); + + WCHAR wchPath[MAX_PATH]; + memset(wchPath, 0, sizeof(wchPath)); + Q_ASSERT(path.length()Release(); + return bResult; + } + + // + // Convert the path name into a pointer to an item ID list (pidl). + // + ULONG ulCount, ulAttr; + if (SUCCEEDED (psfFolder->ParseDisplayName (hwnd, + NULL, wchPath, &ulCount, &pidlMain, &ulAttr)) && (pidlMain != NULL)) { + + if ( (nCount = Util::GetItemCount (pidlMain))>0) { // nCount must be > 0 + // + // Initialize psfFolder with a pointer to the IShellFolder + // interface of the folder that contains the item whose context + // menu we're after, and initialize pidlItem with a pointer to + // the item's item ID. If nCount > 1, this requires us to walk + // the list of item IDs stored in pidlMain and bind to each + // subfolder referenced in the list. + // + pidlItem = pidlMain; + + while (--nCount) { + // + // Create a 1-item item ID list for the next item in pidlMain. + // + pidlNextItem = Util::DuplicateItem (pMalloc, pidlItem); + if (pidlNextItem == NULL) { + pMalloc->Free(pidlMain); + psfFolder->Release (); + pMalloc->Release (); + return bResult; + } + + // + // Bind to the folder specified in the new item ID list. + // + LPSHELLFOLDER psfNextFolder; + if (!SUCCEEDED (psfFolder->BindToObject ( + pidlNextItem, NULL, IID_IShellFolder, (void**)&psfNextFolder))) { + pMalloc->Free (pidlNextItem); + pMalloc->Free (pidlMain); + psfFolder->Release (); + pMalloc->Release (); + return bResult; + } + + // + // Release the IShellFolder pointer to the parent folder + // and set psfFolder equal to the IShellFolder pointer for + // the current folder. + // + psfFolder->Release (); + psfFolder = psfNextFolder; + + // + // Release the storage for the 1-item item ID list we created + // just a moment ago and initialize pidlItem so that it points + // to the next item in pidlMain. + // + pMalloc->Free(pidlNextItem); + pidlItem = Util::GetNextItem (pidlItem); + } + + // + // Get a pointer to the item's IContextMenu interface and call + // IContextMenu::QueryContextMenu to initialize a context menu. + // + ppidl = &pidlItem; + LPCONTEXTMENU pContextMenu; + if (SUCCEEDED (psfFolder->GetUIObjectOf ( + hwnd, 1, (const ITEMIDLIST **)ppidl, IID_IContextMenu, NULL, (void**)&pContextMenu))) { + + HMENU hMenu = CreatePopupMenu (); + if (SUCCEEDED (pContextMenu->QueryContextMenu ( + hMenu, 0, 1, 0x7FFF, CMF_EXPLORE))) { + + + // + // Display the context menu. + // + UINT nCmd = TrackPopupMenu (hMenu, TPM_LEFTALIGN | + TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, + point.x, point.y, 0, hwnd, NULL); + + + // + // If a command was selected from the menu, execute it. + // + if (nCmd) { + CMINVOKECOMMANDINFO ici; + memset(&ici, 0, sizeof(ici) ); + ici.cbSize = sizeof (CMINVOKECOMMANDINFO); + ici.fMask = 0; + ici.hwnd = hwnd; + ici.lpVerb = MAKEINTRESOURCEA (nCmd - 1); + ici.lpParameters = NULL; + ici.lpDirectory = NULL; + ici.nShow = SW_SHOWNORMAL; + ici.dwHotKey = 0; + ici.hIcon = NULL; + + if (SUCCEEDED ( + pContextMenu->InvokeCommand ( + (CMINVOKECOMMANDINFO*)&ici))) + bResult = true; + } + } + DestroyMenu (hMenu); + pContextMenu->Release (); + } + } + pMalloc->Free (pidlMain); + } + + // + // Clean up and return. + // + psfFolder->Release (); + pMalloc->Release (); + + return bResult; +} + +#endif + diff --git a/src/Utils.h b/src/Utils.h index 4661d26..601065a 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,14 +1,14 @@ -#ifndef UTILS_H -#define UTILS_H - -#include -#include - -QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No); - -#ifdef Q_WS_WIN - bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint); -#endif - - -#endif // UTILS_H +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No); + +#ifdef Q_OS_WIN + bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint); +#endif + + +#endif // UTILS_H diff --git a/src/main.cpp b/src/main.cpp index 6aed5ab..2aff817 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,8 +10,8 @@ int main(int argc, char *argv[]) app.setOrganizationName("Fuel-SCM"); - #ifdef Q_WS_MACX - // Native OSX applications don't use menu icons + #ifdef Q_OS_MACX + // Native OSX applications don't have menu icons app.setAttribute(Qt::AA_DontShowIconsInMenus); #endif {