diff --git a/BUILD.txt b/BUILD.txt index 7d4a6a1..8b5d2a1 100644 --- a/BUILD.txt +++ b/BUILD.txt @@ -1,7 +1,7 @@ Building on Linux: -For Debian and Ubuntu: -sudo apt-get install libqt4-dev libboost-dev g++ dh-make +For debian and ubuntu: +sudo apt-get install libqt4-dev libboost-dev g++ dh_make qmake -r Launchy.pro ; make ; sudo make install To build a deb package: @@ -11,7 +11,6 @@ cd linux ; ./build_deb.sh such as ./buid_deb.sh 2.2 Building and installing on Mac OS X: -0) Install the boost C++ library 1) Install the QT SDK 2) qmake Launchy.pro -spec macx-g++ -r CONFIG+=release 3) make ; make install @@ -23,7 +22,7 @@ Building and installing on Mac OS X: -Building on Windows: +Building on WINDOWS: Requirements: 1) Visual Studio 2005 w/ SP1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..fbe8179 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +launchy +======= + +Open-Source Keystroke Launcher + +# About +Launchy is a free cross-platform utility designed to help you forget about +your start menu, the icons on your desktop, and even your file manager. +Launchy indexes the programs in your start menu and can launch your documents, +project files, folders, and bookmarks with just a few keystrokes! + +Further information can be found in the [readmes](/readmes) directory. + +# This Release +The original author has abandoned this project. As such several bugs +critical to the use of Launchy have gone unfixed. The user community on +Github has patched several of these, but none have hit them all. This +repository hits the ones I cared about! + +* Config files being placed in your homedir (e.g., ~/launchy.ini). +* Desktop files with double-quotes not launching properly. +* Desktop files with multiple sections not indexing at all. + +# Contributors +* Josh Karlin: Creator and Author +* Simon Capewell: Developer +* Lukas Zapletal: Fedora package maintainer +* Pablo Russo: Desktop file patch +* Leonid Shevtsov: Quote launch patch diff --git a/Readme.pdf b/Readme.pdf deleted file mode 100644 index b891fd6..0000000 Binary files a/Readme.pdf and /dev/null differ diff --git a/platforms/unix/platform_unix.cpp b/platforms/unix/platform_unix.cpp index e53700d..e82d7e5 100644 --- a/platforms/unix/platform_unix.cpp +++ b/platforms/unix/platform_unix.cpp @@ -166,7 +166,7 @@ void PlatformUnix::alterItem(CatItem* item) { line = QString::fromUtf8(file.readLine()); - while(!file.atEnd() && !line.startsWith("[", Qt::CaseInsensitive)) { + while(!line.startsWith("[", Qt::CaseInsensitive)) { if (line.startsWith("Name[" + locale, Qt::CaseInsensitive)) name = line.split("=")[1].trimmed(); @@ -179,7 +179,16 @@ void PlatformUnix::alterItem(CatItem* item) { else if (line.startsWith("NoDisplay")) nodisplay = line.split("=")[1].trimmed(); - line = QString::fromUtf8(file.readLine()); + // Fix for regression where we were ignoring the + // last line line in the file (which if it was an icon + // would be fatal. + if (!file.atEnd()) { + line = QString::fromUtf8(file.readLine()); + continue; + } + + // We're done now. + break; } } diff --git a/platforms/unix/platform_unix_util.cpp b/platforms/unix/platform_unix_util.cpp index 56e9e04..47b0992 100644 --- a/platforms/unix/platform_unix_util.cpp +++ b/platforms/unix/platform_unix_util.cpp @@ -14,9 +14,9 @@ UnixIconProvider::UnixIconProvider() { QStringList spl = line.split("="); xdgDataDirs = spl[1].split(":"); } - // Fedora patch file launchy-xdg-icon-path.patch (original author unknown) - xdgDataDirs += "/usr/share/"; xdgDataDirs += "/usr/share/icons/"; + // Patch from Fedora (original author unknown) + xdgDataDirs += "/usr/share/"; } diff --git a/platforms/win/WinIconProvider.cpp b/platforms/win/WinIconProvider.cpp index 04be921..a659105 100644 --- a/platforms/win/WinIconProvider.cpp +++ b/platforms/win/WinIconProvider.cpp @@ -76,8 +76,8 @@ void WinIconProvider::setPreferredIconSize(int size) // This also exists in plugin_interface, need to remove both if I make a 64 build -QString wicon_aliasTo64(QString path) -{ +QString wicon_aliasTo64(QString path) +{ QProcessEnvironment env = QProcessEnvironment::systemEnvironment (); QString pf32 = env.value("PROGRAMFILES"); QString pf64 = env.value("PROGRAMW6432"); @@ -99,8 +99,8 @@ QString wicon_aliasTo64(QString path) path = path32.replace("system32", "sysnative"); } } - } - return path; + } + return path; } QIcon WinIconProvider::icon(const QFileInfo& info) const @@ -131,22 +131,10 @@ QIcon WinIconProvider::icon(const QFileInfo& info) const // Get the icon index using SHGetFileInfo SHFILEINFO sfi = {0}; - QRegExp re("\\\\\\\\([a-z0-9\\-]+\\\\?)?$", Qt::CaseInsensitive); - if (re.exactMatch(filePath)) - { - // To avoid network hangs, explicitly fetch the My Computer icon for UNCs - LPITEMIDLIST pidl; - if (SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidl) == S_OK) - { - SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX); - // Set the file path to the My Computer GUID for any later fetches - filePath = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"; - } - } - if (sfi.iIcon == 0) - { - SHGetFileInfo(filePath.utf16(), 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX); - } + // To avoid network hangs, explicitly fetch the My Computer icon for UNCs + QRegExp re("\\\\\\\\([a-z]+\\\\?)?$", Qt::CaseInsensitive); + SHGetFileInfo(re.exactMatch(filePath) ? L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" : filePath.utf16(), + 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX); // An icon index of 3 is the generic file icon if (sfi.iIcon > 0 && sfi.iIcon != 3) diff --git a/platforms/win/platform_win.cpp b/platforms/win/platform_win.cpp index 83efca8..f101e7c 100644 --- a/platforms/win/platform_win.cpp +++ b/platforms/win/platform_win.cpp @@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "main.h" #include "platform_win.h" #include "WinIconProvider.h" -#include "minidump.h" // Override the main widget to handle incoming system messages. We could have done this in the QApplication @@ -48,11 +47,6 @@ class LaunchyWidgetWin : public LaunchyWidget } break; - case WM_ENDSESSION: - // Ensure settings are saved - saveSettings(); - break; - // Might need to capture these two messages if Vista gives any problems with alpha borders // when restoring from standby case WM_POWERBROADCAST: @@ -85,10 +79,9 @@ LaunchyWidget* createLaunchyWidget(CommandFlags command) PlatformWin::PlatformWin(int& argc, char** argv) : - PlatformBase(argc, argv), - minidumper(_T("Launchy")) + PlatformBase(argc, argv) { - instance = new LimitSingleInstance(_T("Local\\{ASDSAD0-DCC6-49b5-9C61-ASDSADIIIJJL}")); + instance = new LimitSingleInstance(TEXT("Local\\{ASDSAD0-DCC6-49b5-9C61-ASDSADIIIJJL}")); // Create local and global application mutexes so that installer knows when // Launchy is running @@ -209,27 +202,8 @@ bool PlatformWin::supportsAlphaBorder() const return true; } - -bool PlatformWin::getComputers(QStringList& computers) const +bool PlatformWin::getComputers(QList& computers) const { - // Get a list of domains. This should return nothing or fail when we're on a workgroup - QStringList domains; - if (EnumerateNetworkServers(domains, SV_TYPE_DOMAIN_ENUM)) - { - foreach(QString domain, domains) - { - EnumerateNetworkServers(computers, SV_TYPE_WORKSTATION | SV_TYPE_SERVER, domain.utf16()); - } - - // If names have been retrieved from more than one domain, they'll need sorting - if (domains.length() > 1) - { - computers.sort(); - } - - return true; - } - return EnumerateNetworkServers(computers, SV_TYPE_WORKSTATION | SV_TYPE_SERVER); } @@ -239,3 +213,5 @@ QApplication* createApplication(int& argc, char** argv) { return new PlatformWin(argc, argv); } + + diff --git a/platforms/win/platform_win.h b/platforms/win/platform_win.h index 54b765a..bd64b01 100644 --- a/platforms/win/platform_win.h +++ b/platforms/win/platform_win.h @@ -24,7 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "platform_base.h" #include "platform_win_util.h" #include "platform_base_hotkey.h" -#include "minidump.h" class PlatformWin : public PlatformBase @@ -44,12 +43,11 @@ class PlatformWin : public PlatformBase virtual bool supportsAlphaBorder() const; virtual bool isAlreadyRunning() const; virtual void sendInstanceCommand(int command); - virtual bool getComputers(QStringList& computers) const; + virtual bool getComputers(QList& computers) const; private: HANDLE localMutex, globalMutex; LimitSingleInstance* instance; - MiniDumper minidumper; }; diff --git a/platforms/win/platform_win_util.cpp b/platforms/win/platform_win_util.cpp index 2e6211e..0ff1bfa 100644 --- a/platforms/win/platform_win_util.cpp +++ b/platforms/win/platform_win_util.cpp @@ -83,7 +83,7 @@ QString GetShellDirectory(int type) } -bool EnumerateNetworkServers(QStringList& items, DWORD serverType, const wchar_t* domain) +bool EnumerateNetworkServers(QList& items, DWORD serverType, const wchar_t* domain) { SERVER_INFO_100* serverInfo = 0; DWORD read, totalOnNetwork; diff --git a/platforms/win/platform_win_util.h b/platforms/win/platform_win_util.h index f805dae..16fc458 100644 --- a/platforms/win/platform_win_util.h +++ b/platforms/win/platform_win_util.h @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void UpdateEnvironment(); QString GetShellDirectory(int type); -bool EnumerateNetworkServers(QStringList& items, DWORD serverType, const wchar_t* domain = NULL); +bool EnumerateNetworkServers(QList& items, DWORD serverType, const wchar_t* domain = NULL); class LimitSingleInstance diff --git a/plugins/calcy/calcy.cpp b/plugins/calcy/calcy.cpp index f4f3d4b..79da8de 100644 --- a/plugins/calcy/calcy.cpp +++ b/plugins/calcy/calcy.cpp @@ -96,7 +96,9 @@ bool DoCalculation(QString str, double& result) calculator calc; double n = 0; - + QLocale locale; + str = str.replace(locale.groupSeparator(), ""); + str = str.replace(locale.decimalPoint(), "."); wchar_t* wstr = new wchar_t[str.length()+1]; str.toWCharArray(wstr); wstr[str.length()] = 0; @@ -114,7 +116,8 @@ bool DoCalculation(QString str, double& result) calcyPlugin* gPlugin; -calcyPlugin::calcyPlugin() +calcyPlugin::calcyPlugin() : + reg(".*[\\-\\+\\*\\/]+[\\d\\s\\-\\+\\*\\/\\(\\)\\.]+") { gPlugin = this; HASH_CALCY = qHash(QString("calcy")); @@ -128,11 +131,6 @@ calcyPlugin::~calcyPlugin() void calcyPlugin::init() { - QString decimal = (*settings)->value("calcy/useCommaForDecimal", false).toBool() ? "," : "."; - QString group = (*settings)->value("calcy/useCommaForDecimal", false).toBool() ? "." : ","; - - QString pattern = QString("^[\\(\\+\\-]*([\\d\\%1]?(\\%2\\d+)?)").arg(group).arg(decimal); - reg.setPattern(pattern); } @@ -153,8 +151,8 @@ void calcyPlugin::getLabels(QList* id) if (id->count() > 1) return; - QString text = id->last().getText().replace(" ", ""); - if (reg.indexIn(text) == 0) + const QString& text = id->last().getText(); + if (reg.indexIn(text) != -1) { id->last().setLabel(HASH_CALCY); } @@ -165,35 +163,25 @@ void calcyPlugin::getResults(QList* id, QList* results) { if (id->last().hasLabel(HASH_CALCY)) { - QString text = id->last().getText(); + const QString & text = id->last().getText(); double res = 0.0; - - QString decimal = (*settings)->value("calcy/useCommaForDecimal", false).toBool() ? "," : "."; - QString group = (*settings)->value("calcy/useCommaForDecimal", false).toBool() ? "." : ","; - - QLocale c = (*settings)->value("calcy/useCommaForDecimal", false).toBool() ? QLocale(QLocale::German) : QLocale(QLocale::C); - - - text = text.replace(group, ""); - text = text.replace(decimal, "."); - - - //double dbl = c.toDouble(text); - //qDebug() << text << dbl; - //text = QString::number(dbl); - if (!DoCalculation(text, res)) return; - - QString szRes = c.toString(res, 'f', (*settings)->value("calcy/outputRounding", 10).toInt()); - - // Remove any trailing fractional zeros - if (szRes.contains(decimal)) + QLocale locale; + locale.setNumberOptions( + (*settings)->value("calcy/outputGroupSeparator", true).toBool() ? QLocale::NumberOption() : QLocale::OmitGroupSeparator); + QString szRes = locale.toString(res, 'f', (*settings)->value("calcy/outputRounding", 10).toInt()); + // Remove any trailing factional zeros + if (szRes.contains(locale.decimalPoint())) { - while (szRes.endsWith("0")) - szRes.chop(1); - if (szRes.endsWith(decimal)) - szRes.chop(1); + while (szRes.endsWith(locale.zeroDigit())) + { + szRes.truncate(szRes.length()-1); + } + if (szRes.endsWith(locale.decimalPoint())) + { + szRes.truncate(szRes.length()-1); + } } results->push_front(CatItem(szRes + ".calcy", szRes, HASH_CALCY, getIcon())); } @@ -228,7 +216,6 @@ void calcyPlugin::doDialog(QWidget* parent, QWidget** newDlg) return; gui.reset(new Gui(parent)); *newDlg = gui.get(); - init(); } diff --git a/plugins/calcy/calcy.pro b/plugins/calcy/calcy.pro index f925717..8f9398f 100644 --- a/plugins/calcy/calcy.pro +++ b/plugins/calcy/calcy.pro @@ -16,9 +16,10 @@ SOURCES = plugin_interface.cpp \ TARGET = calcy win32 { CONFIG -= embed_manifest_dll - LIBS += user32.lib shell32.lib - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG + LIBS += shell32.lib + LIBS += user32.lib + % LIBS += Gdi32.lib + % LIBS += comctl32.lib } if(!debug_and_release|build_pass):CONFIG(debug, debug|release):DESTDIR = ../../debug/plugins if(!debug_and_release|build_pass):CONFIG(release, debug|release):DESTDIR = ../../release/plugins diff --git a/plugins/calcy/dlg.ui b/plugins/calcy/dlg.ui index 219312a..0ac99ce 100644 --- a/plugins/calcy/dlg.ui +++ b/plugins/calcy/dlg.ui @@ -13,56 +13,46 @@ Calcy - Simple Calculator - - - - 10 - 10 - 350 - 91 - - - - - - - Rounding - - - - - - - decimal places - - - - - - - - - - Show digit grouping symbol - - - - - - - Copy result to clipboard when pressing Enter - - - - - - - Use "," instead of "." as the decimal separator - - - - - + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Rounding + + + + + + + decimal places + + + + + + + + + + Show digit grouping symbol + + + + + + + Copy result to clipboard when pressing Enter + + + + + + diff --git a/plugins/calcy/gui.cpp b/plugins/calcy/gui.cpp index c8e1e20..0fbb3be 100644 --- a/plugins/calcy/gui.cpp +++ b/plugins/calcy/gui.cpp @@ -33,7 +33,6 @@ Gui::Gui(QWidget* parent) txtRounding->setValue(settings->value("calcy/outputRounding", 10).toInt()); chkDigitGrouping->setChecked(settings->value("calcy/outputGroupSeparator", true).toBool()); chkCopyToClipboard->setChecked(settings->value("calcy/copyToClipboard", true).toBool()); - chkComma->setChecked(settings->value("calcy/useCommaForDecimal", false).toBool()); } @@ -52,5 +51,4 @@ void Gui::writeOptions() settings->setValue("calcy/outputRounding", txtRounding->value()); settings->setValue("calcy/outputGroupSeparator", chkDigitGrouping->isChecked()); settings->setValue("calcy/copyToClipboard", chkCopyToClipboard->isChecked()); - settings->setValue("calcy/useCommaForDecimal", chkComma->isChecked()); } diff --git a/plugins/controly/controly.pro b/plugins/controly/controly.pro index dfd8d9e..b507c9c 100644 --- a/plugins/controly/controly.pro +++ b/plugins/controly/controly.pro @@ -28,18 +28,13 @@ SOURCES = plugin_interface.cpp \ TARGET = controly win32 { CONFIG -= embed_manifest_dll - LIBS += shell32.lib - LIBS += user32.lib - LIBS += Gdi32.lib - LIBS += comctl32.lib - LIBS += Advapi32.lib - LIBS += ole32.lib - LIBS += shlwapi.lib - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG -# disable optimizations to prevent crashes with certain third party control panel -# applets when Controly is built using VC++ 2005. - QMAKE_CXXFLAGS_RELEASE -= -O2 + LIBS += shell32.lib + LIBS += user32.lib + LIBS += Gdi32.lib + LIBS += comctl32.lib + LIBS += Advapi32.lib + LIBS += ole32.lib + LIBS += shlwapi.lib } # *:debug { diff --git a/plugins/gcalc/gcalc.pro b/plugins/gcalc/gcalc.pro index d6309dd..93f0e6a 100644 --- a/plugins/gcalc/gcalc.pro +++ b/plugins/gcalc/gcalc.pro @@ -11,9 +11,10 @@ SOURCES = plugin_interface.cpp gcalc.cpp TARGET = gcalc win32 { CONFIG -= embed_manifest_dll - LIBS += user32.lib shell32.lib - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG + LIBS += shell32.lib + LIBS += user32.lib + % LIBS += Gdi32.lib + % LIBS += comctl32.lib } if(!debug_and_release|build_pass):CONFIG(debug, debug|release):DESTDIR = ../../debug/plugins if(!debug_and_release|build_pass):CONFIG(release, debug|release):DESTDIR = ../../release/plugins diff --git a/plugins/runner/gui.cpp b/plugins/runner/gui.cpp index ed0f7ef..7c67666 100644 --- a/plugins/runner/gui.cpp +++ b/plugins/runner/gui.cpp @@ -25,12 +25,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ROW_PADDING 6 -Gui::Gui(QWidget* parent, QSettings* settings) - : QWidget(parent), settings(settings) +Gui::Gui(QWidget* parent) + : QWidget(parent) { setupUi(this); - if (settings == NULL) - return; + QSettings* settings = *gRunnerInstance->settings; + if (settings == NULL) return; // Stretch the centre column of the table table->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch); // column 1 @@ -59,8 +59,8 @@ Gui::Gui(QWidget* parent, QSettings* settings) void Gui::writeOptions() { - if (settings == NULL) - return; + QSettings* settings = *gRunnerInstance->settings; + if (settings == NULL) return; settings->beginWriteArray("runner/cmds"); for(int i = 0; i < table->rowCount(); ++i) { diff --git a/plugins/runner/gui.h b/plugins/runner/gui.h index 1141286..c107a3b 100644 --- a/plugins/runner/gui.h +++ b/plugins/runner/gui.h @@ -24,14 +24,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "FileBrowserDelegate.h" #include "ui_dlg.h" #include "globals.h" -#include + class Gui : public QWidget, private Ui::Dlg { Q_OBJECT public: - Gui(QWidget* parent, QSettings* settings); + Gui(QWidget* parent); ~Gui() { this->hide(); } void writeOptions(); @@ -44,7 +44,6 @@ private slots: private: void appendRow(const QString& name, const QString& file, const QString& args); - QSettings* settings; FileBrowserDelegate delegate; }; diff --git a/plugins/runner/runner.cpp b/plugins/runner/runner.cpp index fc92dd4..93fcff6 100644 --- a/plugins/runner/runner.cpp +++ b/plugins/runner/runner.cpp @@ -22,8 +22,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "gui.h" +RunnerPlugin* gRunnerInstance = NULL; + + void RunnerPlugin::init() { + if (gRunnerInstance == NULL) + gRunnerInstance = this; + QSettings* set = *settings; cmds.clear(); @@ -167,7 +173,7 @@ void RunnerPlugin::doDialog(QWidget* parent, QWidget** newDlg) { if (gui != NULL) return; - gui.reset(new Gui(parent, *settings)); + gui.reset(new Gui(parent)); *newDlg = gui.get(); } diff --git a/plugins/runner/runner.h b/plugins/runner/runner.h index 934aaca..db4cb29 100644 --- a/plugins/runner/runner.h +++ b/plugins/runner/runner.h @@ -57,8 +57,11 @@ class RunnerPlugin : public QObject, public PluginInterface uint HASH_runner; QList cmds; QString libPath; - boost::shared_ptr gui; + boost::shared_ptr gui; }; +extern RunnerPlugin* gRunnerInstance; + + #endif diff --git a/plugins/runner/runner.pro b/plugins/runner/runner.pro index 97e2801..6c89c1e 100644 --- a/plugins/runner/runner.pro +++ b/plugins/runner/runner.pro @@ -27,9 +27,10 @@ TARGET \ runner win32 { CONFIG -= embed_manifest_dll - LIBS += user32.lib shell32.lib - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG + LIBS += shell32.lib + LIBS += user32.lib + % LIBS += Gdi32.lib + % LIBS += comctl32.lib } if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { diff --git a/plugins/verby/Verby.cpp b/plugins/verby/Verby.cpp index 90d3680..5fb01c4 100644 --- a/plugins/verby/Verby.cpp +++ b/plugins/verby/Verby.cpp @@ -55,25 +55,29 @@ void VerbyPlugin::getLabels(QList* inputData) { if (inputData->count() == 1) { - // If it's not an item from Launchy's built in catalog, i.e. a file or directory or something added - // by a plugin, don't add verbs. - if (inputData->first().getTopResult().id != 0) + QString text = inputData->last().getText(); + + // Is it a file? + if (text.contains("\\") || text.contains("/")) return; - QString path = inputData->first().getTopResult().fullPath; + QDir qd; + QFile qf; + + QString path = inputData->last().getTopResult().fullPath; QFileInfo info(path); if (info.isSymLink()) { - inputData->first().setLabel(HASH_LINK); + inputData->last().setLabel(HASH_LINK); } else if (info.isDir()) { - inputData->first().setLabel(HASH_DIR); + inputData->last().setLabel(HASH_DIR); } else if (info.isFile()) { - inputData->first().setLabel(HASH_FILE); + inputData->last().setLabel(HASH_FILE); } } } @@ -110,7 +114,7 @@ void VerbyPlugin::addCatItem(QString text, QList* results, QString full { if (text.length() == 0 || isMatch(shortName, text)) { - CatItem item = CatItem(fullName, shortName, HASH_VERBY, getIconPath() + iconName); + CatItem item = CatItem(fullName, shortName, HASH_VERBY, getIconPath() + iconName); item.usage = (*settings)->value("verby/" + shortName.replace(" ", "") , 0).toInt(); results->push_back(item); } diff --git a/plugins/verby/Verby.h b/plugins/verby/Verby.h index dc50cc5..c8a4650 100644 --- a/plugins/verby/Verby.h +++ b/plugins/verby/Verby.h @@ -34,9 +34,9 @@ class VerbyPlugin : public QObject, public PluginInterface { gui = NULL; HASH_VERBY = qHash(QString("verby")); - HASH_DIR = qHash(QString("verbydirectory")); - HASH_FILE = qHash(QString("verbyfile")); - HASH_LINK = qHash(QString("verbylink")); + HASH_DIR = qHash(QString("directory")); + HASH_FILE = qHash(QString("file")); + HASH_LINK = qHash(QString("link")); } ~VerbyPlugin() diff --git a/plugins/verby/verby.pro b/plugins/verby/verby.pro index 69a242f..303fa14 100644 --- a/plugins/verby/verby.pro +++ b/plugins/verby/verby.pro @@ -16,12 +16,20 @@ SOURCES = plugin_interface.cpp \ TARGET = verby win32 { CONFIG -= embed_manifest_dll - LIBS += user32.lib shell32.lib - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG + LIBS += shell32.lib user32.lib +} +win32:debug:%QMAKE_CXXFLAGS += /ZI +*:debug:DESTDIR = ../../debug/plugins/ +*:release { + DESTDIR = ../../release/plugins/ + %QMAKE_CXXFLAGS += /Ox \ + /Ob2 \ + /Oi \ + /Oy \ + /GT \ + /GA \ + /WX } -if(!debug_and_release|build_pass):CONFIG(debug, debug|release):DESTDIR = ../../debug/plugins -if(!debug_and_release|build_pass):CONFIG(release, debug|release):DESTDIR = ../../release/plugins unix:!macx { PREFIX = /usr target.path = $$PREFIX/lib64/launchy/plugins/ diff --git a/plugins/weby/gui.cpp b/plugins/weby/gui.cpp index a0c0559..a07288a 100644 --- a/plugins/weby/gui.cpp +++ b/plugins/weby/gui.cpp @@ -24,12 +24,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ROW_PADDING 6 -Gui::Gui(QWidget* parent, QSettings* settings) - : QWidget(parent), settings(settings) +Gui::Gui(QWidget* parent) + : QWidget(parent) { setupUi(this); - if (settings == NULL) - return; + QSettings* settings = *gWebyInstance->settings; + if (settings == NULL) return; booksFirefox->setChecked(settings->value("weby/firefox", true).toBool()); booksIE->setChecked(settings->value("weby/ie", true).toBool()); @@ -67,8 +67,8 @@ Gui::Gui(QWidget* parent, QSettings* settings) void Gui::writeOptions() { - if (settings == NULL) - return; + QSettings* settings = *gWebyInstance->settings; + if (settings == NULL) return; settings->setValue("weby/firefox", booksFirefox->isChecked()); settings->setValue("weby/ie", booksIE->isChecked()); diff --git a/plugins/weby/gui.h b/plugins/weby/gui.h index 818263e..b18cbea 100644 --- a/plugins/weby/gui.h +++ b/plugins/weby/gui.h @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "ui_dlg.h" #include "globals.h" -#include + class Gui : public QWidget, private Ui::Dlg { @@ -30,7 +30,7 @@ class Gui : public QWidget, private Ui::Dlg private: QList sites; public: - Gui(QWidget* parent, QSettings* settings); + Gui(QWidget* parent); ~Gui() { this->hide(); } void writeOptions(); QString defaultName; @@ -45,8 +45,6 @@ public slots: private: void appendRow(const QString& name, const QString& path); - - QSettings* settings; }; #endif diff --git a/plugins/weby/weby.cpp b/plugins/weby/weby.cpp index 723e502..45f6208 100644 --- a/plugins/weby/weby.cpp +++ b/plugins/weby/weby.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "IconCache.h" #include "gui.h" +WebyPlugin* gWebyInstance = NULL; int Suggest::currentId = 0; @@ -83,6 +84,9 @@ void Suggest::httpGetFinished(bool error) void WebyPlugin::init() { + if (gWebyInstance == NULL) + gWebyInstance = this; + QSettings* set = *settings; // get config / settings directory (base for 'temporary' icon cache dir) @@ -481,7 +485,8 @@ void WebyPlugin::launchItem(QList* inputData, CatItem* item) for (; i < inputData->count(); i++) { QString txt = inputData->at(i).getText(); - args.push_back(QUrl::toPercentEncoding(txt)); + txt = QUrl::toPercentEncoding(txt); + args.push_back(txt); } // Is it a Firefox shortcut? @@ -515,22 +520,9 @@ void WebyPlugin::launchItem(QList* inputData, CatItem* item) } else { - // Build the new string - QString out; - int curArg = 0; - for(int i = 0; i < file.size()-1; i++) { - QChar curchar = file[i]; - QChar nextchar = file[i+1]; - if (curchar == '%' && nextchar >= '0' && nextchar <= '9') { - i += 1; - if (curArg < args.size()) { - out += args[curArg++]; - } - } else { - out += curchar; - } - } - file = out; + // Fill additional parameter placeholders + for (int i = 0; i < args.size(); i++) + file = file.arg(args[i]); } break; } @@ -548,7 +540,7 @@ void WebyPlugin::launchItem(QList* inputData, CatItem* item) } QUrl url(file); - runProgram(url.toString(), "", false); + runProgram(url.toString(), ""); } @@ -556,7 +548,7 @@ void WebyPlugin::doDialog(QWidget* parent, QWidget** newDlg) { if (gui != NULL) return; - gui.reset(new Gui(parent, *settings)); + gui.reset(new Gui(parent)); *newDlg = gui.get(); } diff --git a/plugins/weby/weby.h b/plugins/weby/weby.h index 01fb94d..5ef1c23 100644 --- a/plugins/weby/weby.h +++ b/plugins/weby/weby.h @@ -99,5 +99,8 @@ class WebyPlugin : public QObject, public PluginInterface #endif }; +extern WebyPlugin* gWebyInstance; + + #endif diff --git a/plugins/weby/weby.pro b/plugins/weby/weby.pro index 4ca34eb..72d83ca 100644 --- a/plugins/weby/weby.pro +++ b/plugins/weby/weby.pro @@ -24,7 +24,10 @@ SOURCES = plugin_interface.cpp \ TARGET = weby win32 { CONFIG -= embed_manifest_dll - LIBS += user32.lib shell32.lib + LIBS += shell32.lib + LIBS += user32.lib + % LIBS += Gdi32.lib + % LIBS += comctl32.lib } if(!debug_and_release|build_pass):CONFIG(debug, debug|release):DESTDIR = ../../debug/plugins if(!debug_and_release|build_pass):CONFIG(release, debug|release):DESTDIR = ../../release/plugins diff --git a/Readme.doc b/readmes/Readme.doc similarity index 62% rename from Readme.doc rename to readmes/Readme.doc index b11fc77..a172016 100644 Binary files a/Readme.doc and b/readmes/Readme.doc differ diff --git a/readmes/Readme.pdf b/readmes/Readme.pdf new file mode 100644 index 0000000..2a1b969 Binary files /dev/null and b/readmes/Readme.pdf differ diff --git a/readme.lyx b/readmes/readme.lyx similarity index 100% rename from readme.lyx rename to readmes/readme.lyx diff --git a/readme.txt b/readmes/readme.txt similarity index 100% rename from readme.txt rename to readmes/readme.txt diff --git a/skins/Mercury/scrollDown.png b/skins/Mercury/scrollDown.png index c32b05b..25001ae 100644 Binary files a/skins/Mercury/scrollDown.png and b/skins/Mercury/scrollDown.png differ diff --git a/skins/Mercury/scrollUp.png b/skins/Mercury/scrollUp.png index 5bae8e0..29ec50f 100644 Binary files a/skins/Mercury/scrollUp.png and b/skins/Mercury/scrollUp.png differ diff --git a/src/CommandHistory.cpp b/src/CommandHistory.cpp index 86bae2e..ef0913a 100644 --- a/src/CommandHistory.cpp +++ b/src/CommandHistory.cpp @@ -116,6 +116,7 @@ void CommandHistory::search(const QString& /*searchText*/, QList& searc foreach(InputDataList historyItem, history) { CatItem item = historyItem.first().getTopResult(); + item.shortName = historyItem.toString(); item.id = HASH_HISTORY; item.data = (void*)index++; searchResults.push_back(item); diff --git a/src/Fader.cpp b/src/Fader.cpp index 4e7dfb7..41e7f29 100644 --- a/src/Fader.cpp +++ b/src/Fader.cpp @@ -26,7 +26,6 @@ Fader::Fader(QObject* parent) : QThread(parent), keepRunning(true) { - setObjectName("Fader"); } @@ -37,7 +36,7 @@ Fader::~Fader() void Fader::fadeIn(bool quick) { - int time = gSettings->value("GenOps/fadein", 0).toInt(); + int time = gSettings->value("GenOps/fadein", 0).toInt(); mutex.lock(); targetLevel = gSettings->value("GenOps/opaqueness", 100).toInt() / 100.0; @@ -50,7 +49,7 @@ void Fader::fadeIn(bool quick) } mutex.unlock(); - if (quick || delay == 0) + if (quick) { // stop any current slow fades stop(); @@ -83,7 +82,7 @@ void Fader::fadeOut(bool quick) // qDebug() << level << " to " << targetLevel << " delay " << delay; - if (quick || delay == 0) + if (quick) { // stop any current slow fades stop(); diff --git a/src/FileSearch.cpp b/src/FileSearch.cpp index 5711a82..d68bf75 100644 --- a/src/FileSearch.cpp +++ b/src/FileSearch.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2009-2010 Simon Capewell, Josh Karlin +Copyright (C) 2009 Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,10 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void FileSearch::search(const QString& searchText, QList& searchResults, InputDataList& inputData) { - qDebug() << "Searching file system for" << searchText; - QString searchPath = QDir::fromNativeSeparators(searchText); - gSearchText = searchPath; if (searchPath.startsWith("~")) searchPath.replace("~", QDir::homePath()); @@ -39,9 +36,8 @@ void FileSearch::search(const QString& searchText, QList& searchResults { // Special case for Windows: list available drives QFileInfoList driveList = QDir::drives(); - for (int i = driveList.length()-1; i >= 0; --i) + foreach(QFileInfo info, driveList) { - QFileInfo info = driveList[i]; // Retrieve volume name QString volumeName; WCHAR volName[MAX_PATH]; @@ -59,88 +55,88 @@ void FileSearch::search(const QString& searchText, QList& searchResults searchPath += "/"; #endif - // Split the string on the last slash - QString directoryPart = searchPath.section("/", 0, -2); - if (directoryPart == "") - directoryPart = "/"; - QString filePart = searchPath.section("/", -1); - bool isDirectory = filePart.length() == 0; - bool sort = true; - bool listPopulated = false; - QStringList itemList; - QDir dir(directoryPart); - -#ifdef Q_WS_WIN - // This is a windows network search + // Network searches are too slow to run in the main thread if (searchPath.startsWith("//")) { - // Exit if the user doesn't want to browse networks if (!gSettings->value("GenOps/showNetwork", true).toBool()) return; - // Check for a search against just the network name QRegExp re("//([a-z0-9\\-]+)?$", Qt::CaseInsensitive); if (re.exactMatch(searchPath)) { - // Get a list of devices on the network. This will be filtered and sorted later. - platform->getComputers(itemList); - isDirectory = false; - listPopulated = true; - sort = false; + inputData.last().setLabel(LABEL_FILE); + + QList computers; + platform->getComputers(computers); + + // Filter computer names by search text + foreach(QString computer, computers) + { + QString computerPath = "//" + computer; + if (computerPath.indexOf(searchPath, 0, Qt::CaseInsensitive) == 0) + { + CatItem item(QDir::toNativeSeparators(computerPath), computer); + item.id = HASH_LAUNCHYFILE; + searchResults.push_back(item); + } + } } + return; } -#endif - if (!listPopulated) - { - // Exit if the path doesn't exist - if (!dir.exists()) - return; - // We have a directory, get a list of files and directories within the directory - QDir::Filters filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; + // Split the string on the last slash + QString directoryPart = searchPath.mid(0,searchPath.lastIndexOf("/")+1); + QString filePart = searchPath.mid(searchPath.lastIndexOf("/")+1); + + QFileInfo info(directoryPart); + if (!info.isDir()) + return; + + inputData.last().setLabel(LABEL_FILE); + + // Okay, we have a directory, find files that match "file" + QDir dir(directoryPart); + QStringList fileList; + QDir::Filters filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; #ifndef Q_WS_WIN - filters |= QDir::CaseSensitive; -#else - filePart = filePart.toLower(); + filters |= QDir::CaseSensitive; #endif - if (gSettings->value("GenOps/showHiddenFiles", false).toBool()) - filters |= QDir::Hidden; + if (gSettings->value("GenOps/showHiddenFiles", false).toBool()) + filters |= QDir::Hidden; - itemList = dir.entryList(filters, QDir::DirsLast | QDir::IgnoreCase | QDir::LocaleAware); + bool userWildcard = false; + QString fileSearch; + if (gSettings->value("GenOps/wildcardFileSearch", false).toBool()) + { + userWildcard = filePart.contains("*") || filePart.contains("?") || filePart.contains("["); + fileSearch = filePart; } + fileSearch += "*"; + + fileList = dir.entryList(QStringList(fileSearch), filters, QDir::DirsLast | QDir::IgnoreCase | QDir::LocaleAware); - for (int i = itemList.length()-1; i >= 0; --i) + foreach(QString fileName, fileList) { - QString fileName = itemList[i]; - QString filePath = QDir::cleanPath(dir.absolutePath() + "/" + fileName); - CatItem item(QDir::toNativeSeparators(filePath), fileName); - if (filePart.length() == 0 || Catalog::matches(&item, filePart.toLower())) + if (userWildcard || fileName.indexOf(filePart, 0, Qt::CaseInsensitive) == 0) { + QString filePath = dir.absolutePath() + "/" + fileName; + filePath = QDir::cleanPath(filePath); + CatItem item(QDir::toNativeSeparators(filePath), fileName); item.id = HASH_LAUNCHYFILE; - searchResults.push_front(item); + searchResults.push_back(item); } } - // Set the sort and underline global to just the filename - gSearchText = filePart; - - if (isDirectory) + // Showing a directory + if (filePart.count() == 0) { - // We're showing a directory, add it as the top result - if (!directoryPart.endsWith("/")) - directoryPart += "/"; QString fullPath = QDir::toNativeSeparators(directoryPart); - QString name = dir.dirName(); - CatItem item(fullPath, name.length() == 0 ? fullPath : name); + if (!fullPath.endsWith(QDir::separator())) + fullPath += QDir::separator(); + QString name = info.dir().dirName(); + CatItem item(fullPath, name.count() == 0 ? fullPath : name); item.id = HASH_LAUNCHYFILE; searchResults.push_front(item); } - else if (sort) - { - // If we're not matching exactly and there's a filename then do a priority sort - qSort(searchResults.begin(), searchResults.end(), CatLessNoPtr); - } - - inputData.last().setLabel(LABEL_FILE); } diff --git a/src/SettingsManager.cpp b/src/SettingsManager.cpp index 98bcaa1..7ca5fa9 100644 --- a/src/SettingsManager.cpp +++ b/src/SettingsManager.cpp @@ -48,16 +48,9 @@ void SettingsManager::load() // Load settings dirs = platform->getDirectories(); portable = QFile::exists(dirs["portableConfig"][0] + iniName); + gSettings = new QSettings(configDirectory(portable) + iniName, QSettings::IniFormat); qDebug("Loading settings in %s mode from %s", portable ? "portable" : "installed", qPrintable(configDirectory(portable))); - QString iniPath = configDirectory(portable) + iniName; - gSettings = new QSettings(configDirectory(portable) + iniName, QSettings::IniFormat); - if (!QFile::exists(iniPath)) - { - // Ini file doesn't exist, create some defaults and save them to disk - QList directories = platform->getDefaultCatalogDirectories(); - writeCatalogDirectories(directories); - } } @@ -165,59 +158,5 @@ void SettingsManager::removeAll() // Get the configuration directory QString SettingsManager::configDirectory(bool portable) const { - QString result = dirs[portable ? "portableConfig" : "config"][0]; - if (profileName.length() > 0) - { - result += "/profiles/" + profileName; - } - return result; -} - - -void SettingsManager::setProfileName(const QString& name) -{ - profileName = name; -} - - -QList SettingsManager::readCatalogDirectories() -{ - QList result; - int size = gSettings->beginReadArray("directories"); - for (int i = 0; i < size; ++i) - { - gSettings->setArrayIndex(i); - Directory tmp; - tmp.name = gSettings->value("name").toString(); - if (tmp.name.length() > 0) - { - tmp.types = gSettings->value("types").toStringList(); - tmp.indexDirs = gSettings->value("indexDirs", false).toBool(); - tmp.indexExe = gSettings->value("indexExes", false).toBool(); - tmp.depth = gSettings->value("depth", 100).toInt(); - result.append(tmp); - } - } - gSettings->endArray(); - - return result; -} - - -void SettingsManager::writeCatalogDirectories(QList& directories) -{ - gSettings->beginWriteArray("directories"); - for (int i = 0; i < directories.count(); ++i) - { - if (directories[i].name.length() > 0) - { - gSettings->setArrayIndex(i); - gSettings->setValue("name", directories[i].name); - gSettings->setValue("types", directories[i].types); - gSettings->setValue("indexDirs", directories[i].indexDirs); - gSettings->setValue("indexExes", directories[i].indexExe); - gSettings->setValue("depth", directories[i].depth); - } - } - gSettings->endArray(); + return dirs[portable ? "portableConfig" : "config"][0]; } diff --git a/src/SettingsManager.h b/src/SettingsManager.h index f126b21..55029c0 100644 --- a/src/SettingsManager.h +++ b/src/SettingsManager.h @@ -24,7 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include -#include "Directory.h" class SettingsManager : public QObject @@ -40,15 +39,11 @@ class SettingsManager : public QObject QString skinPath(const QString& skinName) const; void setPortable(bool makePortable); void removeAll(); - void setProfileName(const QString& name); - static QList readCatalogDirectories(); - static void writeCatalogDirectories(QList& directories); private: QString configDirectory(bool portable) const; bool portable; - QString profileName; QHash > dirs; }; diff --git a/src/catalog.h b/src/catalog.h index 575ec94..29230f7 100644 --- a/src/catalog.h +++ b/src/catalog.h @@ -1,241 +1,238 @@ -/* -Launchy: Application Launcher -Copyright (C) 2007-2009 Josh Karlin - -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. -*/ - -#ifndef CATALOG_H -#define CATALOG_H - -#include -#include -#include - - -/** -\brief CatItem (Catalog Item) stores a single item in the index -*/ -class CatItem { -public: - - /** The full path of the indexed item */ - QString fullPath; - /** The abbreviated name of the indexed item */ - QString shortName; - /** The lowercase name of the indexed item */ - QString lowName; - /** A path to an icon for the item */ - QString icon; - /** How many times this item has been called by the user */ - int usage; - /** This is unused, and meant for plugin writers and future extensions */ - void* data; - /** The plugin id of the creator of this CatItem */ - int id; - - CatItem() {} - - - - CatItem(QString full, bool isDir = false) - : fullPath(full) { - int last = fullPath.lastIndexOf("/"); - if (last == -1) { - shortName = fullPath; - - } else { - shortName = fullPath.mid(last+1); - if (!isDir) - shortName = shortName.mid(0,shortName.lastIndexOf(".")); - } - - lowName = shortName.toLower(); - data = NULL; - usage = 0; - id = 0; - } - - - CatItem(QString full, QString shortN) - : fullPath(full), shortName(shortN) - { - lowName = shortName.toLower(); - data = NULL; - usage = 0; - id = 0; - } - - CatItem(QString full, QString shortN, uint i_d) - : fullPath(full), shortName(shortN), id(i_d) - { - lowName = shortName.toLower(); - data = NULL; - usage = 0; - } - /** This is the constructor most used by plugins - \param full The full path of the file to execute - \param The abbreviated name for the entry - \param i_d Your plugin id (0 for Launchy itself) - \param iconPath The path to the icon for this entry - \warning It is usually a good idea to append ".your_plugin_name" to the end of the full parameter - so that there are not multiple items in the index with the same full path. - */ - CatItem(QString full, QString shortN, uint i_d, QString iconPath) - : fullPath(full), shortName(shortN), icon(iconPath), id(i_d) - { - lowName = shortName.toLower(); - data = NULL; - usage = 0; - } - - CatItem(const CatItem &s) { - fullPath = s.fullPath; - shortName = s.shortName; - lowName = s.lowName; - icon = s.icon; - usage = s.usage; - data = s.data; - id = s.id; - } - - CatItem& operator=( const CatItem &s ) { - fullPath = s.fullPath; - shortName = s.shortName; - lowName = s.lowName; - icon = s.icon; - usage = s.usage; - data = s.data; - id = s.id; - return *this; - } - - bool operator==(const CatItem& other) const - { - return fullPath == other.fullPath && shortName == other.shortName; - } - - bool operator!=(const CatItem& other) const - { - return !(*this == other); - } -}; - - -/** InputData shows one segment (between tabs) of a user's query - A user's query is typically represented by List - and each element of the list represents a segment of the query. - - E.g. query = "google this is my search" will have 2 InputData segments - in the list. One for "google" and one for "this is my search" -*/ -class InputData -{ -private: - /** The user's entry */ - QString text; - /** Any assigned labels to this query segment */ - QSet labels; - /** A pointer to the best catalog match for this segment of the query */ - CatItem topResult; - /** The plugin id of this query's owner */ - uint id; -public: - /** Get the labels applied to this query segment */ - QSet getLabels() { return labels; } - /** Apply a label to this query segment */ - void setLabel(uint l) { labels.insert(l); } - /** Remove a label from this query segment */ - void removeLabel(uint l) { labels.remove(l); } - /** Check if it has the given label applied to it */ - bool hasLabel(uint l) { return labels.contains(l); } - - /** Set the id of this query - - This can be used to override the owner of the selected catalog item, so that - no matter what item is chosen from the catalog, the given plugin will be the one - to execute it. - - \param i The plugin id of the plugin to execute the query's best match from the catalog - */ - void setID(uint i) { id = i; } - - /** Returns the current owner id of the query */ - uint getID() const { return id; } - - /** Get the text of the query segment */ - QString getText() const { return text; } - - /** Set the text of the query segment */ - void setText(QString t) { text = t; } - - /** Get the text of the query segment */ - bool hasText() const { return text.length() > 0; } - - /** Get a pointer to the best catalog match for this segment of the query */ - CatItem& getTopResult() { return topResult; } - - /** Change the best catalog match for this segment */ - void setTopResult(CatItem sr) { topResult = sr; } - - InputData() { id = 0; } - InputData(QString str) : text(str) { id = 0;} - - friend QDataStream &operator<<(QDataStream &out, const InputData &inputData); - friend QDataStream &operator>>(QDataStream &in, InputData &inputData); -}; - -bool CatLess(CatItem* left, CatItem* right); -bool CatLessNoPtr(CatItem& a, CatItem& b); - -inline QDataStream &operator<<(QDataStream &out, const CatItem &item) { - out << item.fullPath; - out << item.shortName; - out << item.lowName; - out << item.icon; - out << item.usage; - out << item.id; - return out; -} - -inline QDataStream &operator>>(QDataStream &in, CatItem &item) { - in >> item.fullPath; - in >> item.shortName; - in >> item.lowName; - in >> item.icon; - in >> item.usage; - in >> item.id; - return in; -} - - -inline QDataStream &operator<<(QDataStream &out, const InputData &inputData) { - out << inputData.text; - out << inputData.labels; - out << inputData.topResult; - out << inputData.id; - return out; -} - -inline QDataStream &operator>>(QDataStream &in, InputData &inputData) { - in >> inputData.text; - in >> inputData.labels; - in >> inputData.topResult; - in >> inputData.id; - return in; -} - - -#endif +/* +Launchy: Application Launcher +Copyright (C) 2007-2009 Josh Karlin + +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. +*/ + +#ifndef CATALOG_H +#define CATALOG_H + +#include +#include +#include + + +/** +\brief CatItem (Catalog Item) stores a single item in the index +*/ +class CatItem { +public: + + /** The full path of the indexed item */ + QString fullPath; + /** The abbreviated name of the indexed item */ + QString shortName; + /** The lowercase name of the indexed item */ + QString lowName; + /** A path to an icon for the item */ + QString icon; + /** How many times this item has been called by the user */ + int usage; + /** This is unused, and meant for plugin writers and future extensions */ + void* data; + /** The plugin id of the creator of this CatItem */ + int id; + + CatItem() {} + + + + CatItem(QString full, bool isDir = false) + : fullPath(full) { + int last = fullPath.lastIndexOf("/"); + if (last == -1) { + shortName = fullPath; + + } else { + shortName = fullPath.mid(last+1); + if (!isDir) + shortName = shortName.mid(0,shortName.lastIndexOf(".")); + } + + lowName = shortName.toLower(); + data = NULL; + usage = 0; + id = 0; + } + + + CatItem(QString full, QString shortN) + : fullPath(full), shortName(shortN) + { + lowName = shortName.toLower(); + data = NULL; + usage = 0; + id = 0; + } + + CatItem(QString full, QString shortN, uint i_d) + : fullPath(full), shortName(shortN), id(i_d) + { + lowName = shortName.toLower(); + data = NULL; + usage = 0; + } + /** This is the constructor most used by plugins + \param full The full path of the file to execute + \param The abbreviated name for the entry + \param i_d Your plugin id (0 for Launchy itself) + \param iconPath The path to the icon for this entry + \warning It is usually a good idea to append ".your_plugin_name" to the end of the full parameter + so that there are not multiple items in the index with the same full path. + */ + CatItem(QString full, QString shortN, uint i_d, QString iconPath) + : fullPath(full), shortName(shortN), icon(iconPath), id(i_d) + { + lowName = shortName.toLower(); + data = NULL; + usage = 0; + } + + CatItem(const CatItem &s) { + fullPath = s.fullPath; + shortName = s.shortName; + lowName = s.lowName; + icon = s.icon; + usage = s.usage; + data = s.data; + id = s.id; + } + + CatItem& operator=( const CatItem &s ) { + fullPath = s.fullPath; + shortName = s.shortName; + lowName = s.lowName; + icon = s.icon; + usage = s.usage; + data = s.data; + id = s.id; + return *this; + } + + bool operator==(const CatItem& other) const { + if (fullPath == other.fullPath) + return true; + return false; + } + +}; + + +/** InputData shows one segment (between tabs) of a user's query + A user's query is typically represented by List + and each element of the list represents a segment of the query. + + E.g. query = "google this is my search" will have 2 InputData segments + in the list. One for "google" and one for "this is my search" +*/ +class InputData +{ +private: + /** The user's entry */ + QString text; + /** Any assigned labels to this query segment */ + QSet labels; + /** A pointer to the best catalog match for this segment of the query */ + CatItem topResult; + /** The plugin id of this query's owner */ + uint id; +public: + /** Get the labels applied to this query segment */ + QSet getLabels() { return labels; } + /** Apply a label to this query segment */ + void setLabel(uint l) { labels.insert(l); } + /** Remove a label from this query segment */ + void removeLabel(uint l) { labels.remove(l); } + /** Check if it has the given label applied to it */ + bool hasLabel(uint l) { return labels.contains(l); } + + /** Set the id of this query + + This can be used to override the owner of the selected catalog item, so that + no matter what item is chosen from the catalog, the given plugin will be the one + to execute it. + + \param i The plugin id of the plugin to execute the query's best match from the catalog + */ + void setID(uint i) { id = i; } + + /** Returns the current owner id of the query */ + uint getID() const { return id; } + + /** Get the text of the query segment */ + QString getText() const { return text; } + + /** Set the text of the query segment */ + void setText(QString t) { text = t; } + + /** Get the text of the query segment */ + bool hasText() const { return text.length() > 0; } + + /** Get a pointer to the best catalog match for this segment of the query */ + CatItem& getTopResult() { return topResult; } + + /** Change the best catalog match for this segment */ + void setTopResult(CatItem sr) { topResult = sr; } + + InputData() { id = 0; } + InputData(QString str) : text(str) { id = 0;} + + friend QDataStream &operator<<(QDataStream &out, const InputData &inputData); + friend QDataStream &operator>>(QDataStream &in, InputData &inputData); +}; + +bool CatLess(CatItem* left, CatItem* right); +bool CatLessNoPtr(CatItem& a, CatItem& b); + +inline QDataStream &operator<<(QDataStream &out, const CatItem &item) { + out << item.fullPath; + out << item.shortName; + out << item.lowName; + out << item.icon; + out << item.usage; + out << item.id; + return out; +} + +inline QDataStream &operator>>(QDataStream &in, CatItem &item) { + in >> item.fullPath; + in >> item.shortName; + in >> item.lowName; + in >> item.icon; + in >> item.usage; + in >> item.id; + return in; +} + + +inline QDataStream &operator<<(QDataStream &out, const InputData &inputData) { + out << inputData.text; + out << inputData.labels; + out << inputData.topResult; + out << inputData.id; + return out; +} + +inline QDataStream &operator>>(QDataStream &in, InputData &inputData) { + in >> inputData.text; + in >> inputData.labels; + in >> inputData.topResult; + in >> inputData.id; + return in; +} + + +#endif diff --git a/src/catalog_builder.cpp b/src/catalog_builder.cpp index 7183bf2..9ff5c62 100644 --- a/src/catalog_builder.cpp +++ b/src/catalog_builder.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,44 +27,94 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. CatalogBuilder::CatalogBuilder(PluginHandler* plugs) : + plugins(plugs) +{ + catalog.reset((Catalog*)createCatalog()); +} + + +CatalogBuilder::CatalogBuilder(PluginHandler* plugs, shared_ptr currentCatalog) : plugins(plugs), - progress(CATALOG_PROGRESS_MAX) + currentCatalog(currentCatalog) +{ + catalog.reset((Catalog*)createCatalog()); +} + + +Catalog* CatalogBuilder::createCatalog() { - catalog = new SlowCatalog(); + if (gSettings->value("GenOps/fastindexer",false).toBool()) + return new FastCatalog(); + return new SlowCatalog(); +} + + +void CatalogBuilder::run() +{ + buildCatalog(); + emit catalogFinished(); } void CatalogBuilder::buildCatalog() { - progress = CATALOG_PROGRESS_MIN; - emit catalogIncrement(progress); - catalog->incrementTimestamp(); - indexed.clear(); + QList memDirs; + int size = gSettings->beginReadArray("directories"); + for (int i = 0; i < size; ++i) + { + gSettings->setArrayIndex(i); + Directory tmp; + tmp.name = gSettings->value("name").toString(); + tmp.types = gSettings->value("types").toStringList(); + tmp.indexDirs = gSettings->value("indexDirs", false).toBool(); + tmp.indexExe = gSettings->value("indexExes", false).toBool(); + tmp.depth = gSettings->value("depth", 100).toInt(); + memDirs.append(tmp); + } + gSettings->endArray(); + + if (memDirs.count() == 0) + { + memDirs = platform->getDefaultCatalogDirectories(); + } - QList memDirs = SettingsManager::readCatalogDirectories(); QHash pluginsInfo = plugins->getPlugins(); - totalItems = memDirs.count() + pluginsInfo.count(); - currentItem = 0; + int totalItems = memDirs.count() + pluginsInfo.count(); + int currentItem = 0; - while (currentItem < memDirs.count()) + for (; currentItem < memDirs.count(); ++currentItem) { + emit(catalogIncrement(100.0f * (currentItem+1) / totalItems)); QString cur = platform->expandEnvironmentVars(memDirs[currentItem].name); indexDirectory(cur, memDirs[currentItem].types, memDirs[currentItem].indexDirs, memDirs[currentItem].indexExe, memDirs[currentItem].depth); - progressStep(currentItem); } - // Don't call the pluginhandler to request catalog because we need to track progress - plugins->getCatalogs(catalog, this); + foreach(PluginInfo info, pluginsInfo) + { + emit(catalogIncrement(100.0f * (currentItem+1) / totalItems)); + if (info.loaded) + { + QList items; + info.obj->msg(MSG_GET_CATALOG, (void*)&items); + foreach(CatItem item, items) + { + if (currentCatalog != NULL) + { + item.usage = currentCatalog->getUsage(item.fullPath); + } + catalog->addItem(item); + } + } + ++currentItem; + } - catalog->purgeOldItems(); - indexed.clear(); - progress = CATALOG_PROGRESS_MAX; - emit catalogFinished(); + emit(catalogIncrement(0.0)); } void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& filters, bool fdirs, bool fbin, int depth) { + QString dir = QDir::toNativeSeparators(directory); QDir qd(dir); dir = qd.absolutePath(); @@ -83,6 +133,8 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& // Special handling of app directories if (cur.endsWith(".app", Qt::CaseInsensitive)) { CatItem item(dir + "/" + cur); + if (currentCatalog != NULL) + item.usage = currentCatalog->getUsage(item.fullPath); platform->alterItem(&item); catalog->addItem(item); } @@ -103,8 +155,10 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& bool isShortcut = dirs[i].endsWith(".lnk", Qt::CaseInsensitive); CatItem item(dir + "/" + dirs[i], !isShortcut); + if (currentCatalog != NULL) + item.usage = currentCatalog->getUsage(item.fullPath); catalog->addItem(item); - indexed.insert(dir + "/" + dirs[i]); + indexed[dir + "/" + dirs[i]] = true; } } } @@ -119,8 +173,10 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& if (!indexed.contains(dir + "/" + dirs[i])) { CatItem item(dir + "/" + dirs[i], true); + if (currentCatalog != NULL) + item.usage = currentCatalog->getUsage(item.fullPath); catalog->addItem(item); - indexed.insert(dir + "/" + dirs[i]); + indexed[dir + "/" + dirs[i]] = true; } } } @@ -134,8 +190,10 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& if (!indexed.contains(dir + "/" + bins[i])) { CatItem item(dir + "/" + bins[i]); + if (currentCatalog != NULL) + item.usage = currentCatalog->getUsage(item.fullPath); catalog->addItem(item); - indexed.insert(dir + "/" + bins[i]); + indexed[dir + "/" + bins[i]] = true; } } } @@ -149,7 +207,10 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& { if (!indexed.contains(dir + "/" + files[i])) { + CatItem item(dir + "/" + files[i]); + if (currentCatalog != NULL) + item.usage = currentCatalog->getUsage(item.fullPath); platform->alterItem(&item); #ifdef Q_WS_X11 if(item.fullPath.endsWith(".desktop") && item.icon == "") @@ -157,23 +218,7 @@ void CatalogBuilder::indexDirectory(const QString& directory, const QStringList& #endif catalog->addItem(item); - indexed.insert(dir + "/" + files[i]); + indexed[dir + "/" + files[i]] = true; } } } - - -bool CatalogBuilder::progressStep(int newStep) -{ - newStep = newStep; - - ++currentItem; - int newProgress = (int)(CATALOG_PROGRESS_MAX * (float)currentItem / totalItems); - if (newProgress != progress) - { - progress = newProgress; - emit catalogIncrement(progress); - } - - return true; -} diff --git a/src/catalog_builder.h b/src/catalog_builder.h index c680893..c77c98c 100644 --- a/src/catalog_builder.h +++ b/src/catalog_builder.h @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,41 +22,41 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include +#include #include "catalog_types.h" #include "plugin_handler.h" -#define CATALOG_PROGRESS_MIN 0 -#define CATALOG_PROGRESS_MAX 100 +using namespace boost; -class CatalogBuilder : public QObject, public INotifyProgressStep +class CatalogBuilder : public QThread { Q_OBJECT public: CatalogBuilder(PluginHandler* plugs); - Catalog* getCatalog() const { return catalog; } - int getProgress() const { return progress; } - int isRunning() const { return progress < CATALOG_PROGRESS_MAX; } - bool progressStep(int newStep); + CatalogBuilder(PluginHandler* plugs, shared_ptr catalog); + static Catalog* createCatalog(); -public slots: - void buildCatalog(); + shared_ptr getCatalog() + { + return catalog; + } + void run(); signals: - void catalogIncrement(int); void catalogFinished(); + void catalogIncrement(float); private: + void buildCatalog(); void indexDirectory(const QString& dir, const QStringList& filters, bool fdirs, bool fbin, int depth); PluginHandler* plugins; - Catalog* catalog; - QSet indexed; - int progress; - int currentItem; - int totalItems; + shared_ptr currentCatalog; + shared_ptr catalog; + QHash indexed; }; diff --git a/src/catalog_types.cpp b/src/catalog_types.cpp index 0f58e5a..7fbba59 100644 --- a/src/catalog_types.cpp +++ b/src/catalog_types.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -22,20 +22,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "globals.h" -// Load the catalog from the specified filename bool Catalog::load(const QString& filename) { QFile inFile(filename); if (!inFile.open(QIODevice::ReadOnly)) { - qWarning("Could not open catalog file for reading"); + qWarning("Could not open catalog database file for reading"); return false; } - // Remove any existing catalog contents - timestamp = 0; - clear(); - QByteArray ba = inFile.readAll(); QByteArray unzipped = qUncompress(ba); QDataStream in(&unzipped, QIODevice::ReadOnly); @@ -52,12 +47,8 @@ bool Catalog::load(const QString& filename) } -// Save the catalog to the specified filename bool Catalog::save(const QString& filename) { - // Prevent other threads accessing the catalog - QMutexLocker locker(&mutex); - QByteArray ba; QDataStream out(&ba, QIODevice::ReadWrite); out.setVersion(QDataStream::Qt_4_2); @@ -68,11 +59,11 @@ bool Catalog::save(const QString& filename) out << item; } - // Compress and write the catalog to the specified file + // Zip the archive QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { - qWarning("Could not open catalog file for writing"); + qWarning("Could not open catalog database file for writing"); return false; } file.write(qCompress(ba)); @@ -80,86 +71,139 @@ bool Catalog::save(const QString& filename) } -// Return true if the specified catalog item matches the specified string -bool Catalog::matches(CatItem* item, const QString& match) +void FastCatalog::addItem(const CatItem& item) { - int matchLength = match.count(); - int curChar = 0; + catList.push_back(item); + int index = catList.count() - 1; + CatItem* pCatItem = &catList[index]; + foreach(QChar c, item.lowName) + { + if (catIndex[c].count() == 0 || catIndex[c].last() != pCatItem) + catIndex[c].push_back(pCatItem); + } +} - foreach(QChar c, item->lowName) + +int FastCatalog::getUsage(const QString& path) +{ + for (int i = 0; i < catList.size(); ++i) { - if (c == match[curChar]) + if (path == catList[i].fullPath) { - ++curChar; - if (curChar >= matchLength) - { - return true; - } - } + return catList[i].usage; + } } - return false; + return 0; } -// Search the catalog, for items matching the text parameter and -// populate the out parameter -void Catalog::searchCatalogs(const QString& text, QList& out) +void FastCatalog::incrementUsage(const CatItem& item) { - // Prevent other threads accessing the catalog - QMutexLocker locker(&mutex); + for (int i = 0; i < catList.size(); ++i) + { + if (item == catList[i]) + { + // If an item is demoted, return it to a usage count of 1 + if (catList[i].usage < 0) + catList[i].usage = 1; + else + ++catList[i].usage; + break; + } + } +} - QList catMatches = search(text); - // Now prioritize the catalog items - qSort(catMatches.begin(), catMatches.end(), CatLess); +void FastCatalog::demoteItem(const CatItem& item) +{ + for (int i = 0; i < catList.size(); ++i) + { + if (item == catList[i]) + { + // If an item is not demoted, demote it + if (catList[i].usage > 0) + catList[i].usage = -1; + else // otherwise demote it further + --catList[i].usage; + break; + } + } +} - // Check for history matches - QString location = "History/" + text; - QStringList hist; - hist = gSettings->value(location, hist).toStringList(); - if (hist.count() == 2) + +int SlowCatalog::getUsage(const QString& path) +{ + for (int i = 0; i < catList.size(); ++i) { - for (int i = 0; i < catMatches.count(); i++) + if (path == catList[i].fullPath) { - if (catMatches[i]->lowName == hist[0] && - catMatches[i]->fullPath == hist[1]) - { - CatItem* tmp = catMatches[i]; - catMatches.removeAt(i); - catMatches.push_front(tmp); - } + return catList[i].usage; } } - // Load up the results - int max = gSettings->value("GenOps/numresults", 10).toInt(); - for (int i = 0; i < max && i < catMatches.count(); i++) + return 0; +} + + +void SlowCatalog::incrementUsage(const CatItem& item) +{ + for (int i = 0; i < catList.size(); ++i) { - out.push_back(*catMatches[i]); + if (item == catList[i]) + { + // If an item is demoted, return it to a usage count of 1 + if (catList[i].usage < 0) + catList[i].usage = 1; + else + ++catList[i].usage; + break; + } } } -void Catalog::promoteRecentlyUsedItems(const QString& text, QList & list) +void SlowCatalog::demoteItem(const CatItem& item) { - // Check for history matches - QString location = "History/" + text; - QStringList hist; - hist = gSettings->value(location, hist).toStringList(); - if (hist.count() == 2) + for (int i = 0; i < catList.size(); ++i) { - for (int i = 0; i < list.count(); i++) + if (item == catList[i]) { - if (list[i].lowName == hist[0] && - list[i].fullPath == hist[1]) + // If an item is not demoted, demote it + if (catList[i].usage > 0) + catList[i].usage = -1; + else // otherwise demote it further + --catList[i].usage; + break; + } + } +} + + +void SlowCatalog::addItem(const CatItem& item) +{ + catList.push_back(item); +} + + +bool Catalog::matches(CatItem* item, const QString& match) +{ + int matchLength = match.count(); + int curChar = 0; + + foreach(QChar c, item->lowName) + { + if (c == match[curChar]) + { + ++curChar; + if (curChar >= matchLength) { - CatItem tmp = list[i]; - list.removeAt(i); - list.push_front(tmp); + return true; } - } + } } + + return false; } @@ -219,97 +263,94 @@ QString Catalog::decorateText(const QString& text, const QString& match, bool ou } -void SlowCatalog::addItem(const CatItem& item) +void Catalog::searchCatalogs(const QString& text, QList & out) { - // Prevent other threads accessing the catalog - QMutexLocker locker(&mutex); - - bool replaced = false; + gSearchText = text.toLower(); + QList catMatches = search(gSearchText); + + // Now prioritize the catalog items + qSort(catMatches.begin(), catMatches.end(), CatLess); - if (timestamp > 0) + // Check for history matches + QString location = "History/" + gSearchText; + QStringList hist; + hist = gSettings->value(location, hist).toStringList(); + if (hist.count() == 2) { - // If we're not loading the catalog, search for an existing matching catalog item - // and replace it if it exists - for (int i = 0; i < catalogItems.size(); ++i) + for (int i = 0; i < catMatches.count(); i++) { - if (item == catalogItems[i]) + if (catMatches[i]->lowName == hist[0] && + catMatches[i]->fullPath == hist[1]) { - int usage = catalogItems[i].usage; - catalogItems[i] = CatalogItem(item, timestamp); - catalogItems[i].usage = usage; - replaced = true; - break; + CatItem* tmp = catMatches[i]; + catMatches.removeAt(i); + catMatches.push_front(tmp); } } } - if (!replaced) + // Load up the results + int max = gSettings->value("GenOps/numresults", 10).toInt(); + for (int i = 0; i < max && i < catMatches.count(); i++) { - // If no match found, append the item to the catalog - qDebug() << "Adding" << item.fullPath; - catalogItems.push_back(CatalogItem(item, timestamp)); + out.push_back(*catMatches[i]); } } -void SlowCatalog::purgeOldItems() +void Catalog::promoteRecentlyUsedItems(const QString& text, QList & list) { - // Prevent other threads accessing the catalog - QMutexLocker locker(&mutex); - - for (int i = catalogItems.size() - 1; i >= 0; --i) + // Check for history matches + QString location = "History/" + text; + QStringList hist; + hist = gSettings->value(location, hist).toStringList(); + if (hist.count() == 2) { - if (catalogItems.at(i).timestamp < timestamp) + for (int i = 0; i < list.count(); i++) { - qDebug() << "Removing" << catalogItems.at(i).fullPath; - catalogItems.remove(i); + if (list[i].lowName == hist[0] && + list[i].fullPath == hist[1]) + { + CatItem tmp = list[i]; + list.removeAt(i); + list.push_front(tmp); + } } } } -void SlowCatalog::incrementUsage(const CatItem& item) +QList FastCatalog::search(const QString& searchText) { - // Prevent other threads accessing the catalog - QMutexLocker locker(&mutex); + QList result; - for (int i = 0; i < catalogItems.size(); ++i) + if (searchText.count() > 0) { - if (item == catalogItems[i]) + // Find the smallest char list + QChar leastCommon = -1; + foreach(QChar c, searchText) { - // If an item is currently demoted, return it to a usage count of 1 - if (catalogItems[i].usage < 0) - catalogItems[i].usage = 1; - else - ++catalogItems[i].usage; - break; + if (leastCommon == -1 || catIndex[c].count() < leastCommon) + leastCommon = c; } - } -} - - -void SlowCatalog::demoteItem(const CatItem& item) -{ - // Prevent catalog refreshes whilst searching - QMutexLocker locker(&mutex); - - for (int i = 0; i < catalogItems.size(); ++i) - { - if (item == catalogItems[i]) + + if (catIndex[leastCommon].count() > 0) { - // If an item is not demoted, demote it - if (catalogItems[i].usage > 0) - catalogItems[i].usage = -1; - else // otherwise demote it further - --catalogItems[i].usage; - break; + // Search the list + for (int i = 0; i < catIndex[leastCommon].count(); ++i) + { + if (matches(catIndex[leastCommon][i], searchText)) + { + result.push_back(catIndex[leastCommon][i]); + } + } } } + + return result; } -// Return a list of catalog items that match searchText -// this method should only be called from within a QMutexLocker protected section QList SlowCatalog::search(const QString& searchText) { QList result; @@ -318,11 +359,11 @@ QList SlowCatalog::search(const QString& searchText) { QString lowSearch = searchText.toLower(); - for (int i = 0; i < catalogItems.count(); ++i) + for (int i = 0; i < catList.count(); ++i) { - if (matches(&catalogItems[i], lowSearch)) + if (matches(&catList[i], lowSearch)) { - result.push_back(&catalogItems[i]); + result.push_back(&catList[i]); } } } diff --git a/src/catalog_types.h b/src/catalog_types.h index 53961fb..917c35b 100644 --- a/src/catalog_types.h +++ b/src/catalog_types.h @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,64 +21,50 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "catalog.h" #include -#include // os x -// These classes do not pertain to plugins - -// Catalog provides methods to search and manage the indexed items +/** This class does not pertain to plugins */ class Catalog { public: - Catalog() : timestamp(0) {} + Catalog() {} virtual ~Catalog() {} bool load(const QString& filename); bool save(const QString& filename); - void incrementTimestamp() { ++timestamp; } - void searchCatalogs(const QString&, QList&); - void promoteRecentlyUsedItems(const QString& text, QList & list); - - virtual int count() = 0; - virtual void clear() = 0; virtual void addItem(const CatItem& item) = 0; - virtual void purgeOldItems() = 0; + virtual int count() = 0; + virtual const CatItem& getItem(int) = 0; + static bool matches(CatItem* item, const QString& match); + static QString decorateText(const QString& text, const QString& match, bool outputRichText = false); + void searchCatalogs(const QString&, QList&); virtual void incrementUsage(const CatItem& item) = 0; virtual void demoteItem(const CatItem& item) = 0; + virtual int getUsage(const QString& path) = 0; + void promoteRecentlyUsedItems(const QString& text, QList & list); - static bool matches(CatItem* item, const QString& match); - static QString decorateText(const QString& text, const QString& match, bool outputRichText = false); - -protected: - virtual const CatItem& getItem(int) = 0; +private: virtual QList search(const QString&) = 0; - - int timestamp; - QMutex mutex; }; -// CatalogItem is used internally to store additional -class CatalogItem : public CatItem +/** This class does not pertain to plugins */ +// The fast catalog searches quickly but +// addition of items is slow and uses a lot of memory +class FastCatalog : public Catalog { public: - CatalogItem() : - timestamp(0) - { - } - - CatalogItem(const CatItem& item, int time) : - timestamp(time) - { - fullPath = item.fullPath; - shortName = item.shortName; - lowName = item.lowName; - icon = item.icon; - usage = item.usage; - data = item.data; - id = item.id; - } + FastCatalog() : Catalog() {} + void addItem(const CatItem& item); + QList search(const QString&); + int count() { return catList.count(); } + const CatItem& getItem(int i) { return catList[i]; } + void incrementUsage(const CatItem& item); + void demoteItem(const CatItem& item); + int getUsage(const QString& path); - int timestamp; +private: + QVector catList; + QHash > catIndex; }; @@ -90,18 +76,14 @@ class SlowCatalog : public Catalog { public: SlowCatalog() : Catalog() {} - virtual int count() { return catalogItems.count(); } - virtual void clear() { catalogItems.clear(); } - virtual void addItem(const CatItem& item); - virtual void purgeOldItems(); - - virtual void incrementUsage(const CatItem& item); - virtual void demoteItem(const CatItem& item); - -protected: - virtual const CatItem& getItem(int i) { return catalogItems[i]; } - virtual QList search(const QString&); + void addItem(const CatItem& item); + QList search(const QString&); + int count() { return catList.count(); } + const CatItem& getItem(int i) { return catList[i]; } + void incrementUsage(const CatItem& item); + void demoteItem(const CatItem& item); + int getUsage(const QString& path); private: - QVector catalogItems; + QVector catList; }; diff --git a/src/globals.cpp b/src/globals.cpp index b762bf5..1f76b5b 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,4 +27,4 @@ PlatformBase* platform; LaunchyWidget* gMainWidget; QSettings* gSettings; QString gSearchText; -CatalogBuilder* gBuilder; +shared_ptr gBuilder; diff --git a/src/globals.h b/src/globals.h index 41cb840..cb7a643 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,10 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define GLOBALS_H +#include "catalog_builder.h" #include "SettingsManager.h" -#include // need this for os x + #define LAUNCHY_VERSION 260 -#define LAUNCHY_VERSION_STRING "2.6 Beta 2" +#define LAUNCHY_VERSION_STRING "2.6.0" #define HASH_LAUNCHY 0 #define HASH_HISTORY 1 @@ -35,13 +36,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. class LaunchyWidget; class PlatformBase; -class CatalogBuilder; extern PlatformBase* platform; extern LaunchyWidget* gMainWidget; extern QSettings* gSettings; extern SettingsManager settings; -extern CatalogBuilder* gBuilder; +extern shared_ptr gBuilder; extern QString gSearchText; diff --git a/src/icon_delegate.cpp b/src/icon_delegate.cpp index 040bc67..9dd3b01 100644 --- a/src/icon_delegate.cpp +++ b/src/icon_delegate.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "precompiled.h" #include "icon_delegate.h" #include "globals.h" -#include "catalog_types.h" extern QLabel* alternativesPath; diff --git a/src/icon_extractor.cpp b/src/icon_extractor.cpp index c0404b6..31d2f36 100644 --- a/src/icon_extractor.cpp +++ b/src/icon_extractor.cpp @@ -29,34 +29,22 @@ IconExtractor::IconExtractor() } -void IconExtractor::processIcon(const CatItem& item, bool highPriority) +void IconExtractor::processIcon(CatItem item, bool highPriority) { mutex.lock(); + item.id = -1; if (highPriority) - { - // use an id of -1 to indicate high priority - if (items.count() > 0 && items[0].id == -1) - { - items.replace(0, item); - } - else - { - items.push_front(item); - } - items[0].id = -1; - } + items.push_front(item); else - { items.push_back(item); - } mutex.unlock(); #ifdef Q_WS_MAC run(); #else if (!isRunning()) - start(LowPriority); + start(LowestPriority); #endif } @@ -68,7 +56,7 @@ void IconExtractor::processIcons(const QList& newItems, bool reset) int itemCount = items.size(); if (reset && itemCount > 0 && isRunning()) { - // reset the queue, but keep the most recent high priority item + // keep the most recent high priority item in the queue CatItem item = items.dequeue(); items.clear(); if (item.id == -1) @@ -117,10 +105,7 @@ void IconExtractor::run() item = items.dequeue(); mutex.unlock(); if (itemsRemaining) - { - QIcon icon = getIcon(item); - emit iconExtracted(item.id, item.fullPath, icon); - } + emit iconExtracted(item.id, getIcon(item)); } while (itemsRemaining); @@ -132,8 +117,6 @@ void IconExtractor::run() QIcon IconExtractor::getIcon(const CatItem& item) { - qDebug() << "Fetching icon for" << item.fullPath; - #ifdef Q_WS_MAC if (item.icon.endsWith(".png") || item.icon.endsWith(".ico")) return QIcon(item.icon); diff --git a/src/icon_extractor.h b/src/icon_extractor.h index b84f174..8fd8bf1 100644 --- a/src/icon_extractor.h +++ b/src/icon_extractor.h @@ -30,13 +30,13 @@ class IconExtractor : public QThread public: IconExtractor(); - void processIcon(const CatItem& item, bool highPriority = true); + void processIcon(CatItem item, bool highPriority = true); void processIcons(const QList& newItems, bool reset = true); void stop(); void run(); signals: - void iconExtracted(int itemIndex, QString path, QIcon icon); + void iconExtracted(int itemIndex, QIcon icon); private: QIcon getIcon(const CatItem& item); diff --git a/src/main.cpp b/src/main.cpp index e908151..f9240fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef Q_WS_WIN void SetForegroundWindowEx(HWND hWnd) { - // Attach foreground window thread to our thread + // Attach foreground window thread to our thread const DWORD foreGroundID = GetWindowThreadProcessId(GetForegroundWindow(), NULL); const DWORD currentID = GetCurrentThreadId(); @@ -54,10 +54,10 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : QWidget(NULL, Qt::FramelessWindowHint | Qt::Tool), #endif #ifdef Q_WS_X11 - QWidget(NULL, Qt::FramelessWindowHint | Qt::Tool), + QWidget(NULL, Qt::FramelessWindowHint | Qt::Tool), #endif #ifdef Q_WS_MAC - QWidget(NULL, Qt::FramelessWindowHint), + QWidget(NULL, Qt::FramelessWindowHint), #endif frameGraphic(NULL), @@ -73,8 +73,8 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : setWindowIcon(QIcon(":/resources/launchy128.png")); #endif #ifdef Q_WS_MAC - setWindowIcon(QIcon("../Resources/launchy_icon_mac.icns")); - //setAttribute(Qt::WA_MacAlwaysShowToolWindow); + setWindowIcon(QIcon("../Resources/launchy_icon_mac.icns")); + //setAttribute(Qt::WA_MacAlwaysShowToolWindow); #endif setAttribute(Qt::WA_AlwaysShowToolTips); @@ -95,7 +95,7 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : alwaysShowLaunchy = false; - connect(&iconExtractor, SIGNAL(iconExtracted(int, QString, QIcon)), this, SLOT(iconExtracted(int, QString, QIcon))); + connect(&iconExtractor, SIGNAL(iconExtracted(int, QIcon)), this, SLOT(iconExtracted(int, QIcon))); fader = new Fader(this); connect(fader, SIGNAL(fadeLevel(double)), this, SLOT(setFadeLevel(double))); @@ -118,7 +118,7 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : input = new CharLineEdit(this); #ifdef Q_WS_MAC - QMacStyle::setFocusRectPolicy(input, QMacStyle::FocusDisabled); + QMacStyle::setFocusRectPolicy(input, QMacStyle::FocusDisabled); #endif input->setObjectName("input"); connect(input, SIGNAL(keyPressed(QKeyEvent*)), this, SLOT(inputKeyPressEvent(QKeyEvent*))); @@ -151,7 +151,7 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : alternatives->setUniformItemSizes(true); listDelegate = new IconDelegate(this); defaultListDelegate = alternatives->itemDelegate(); - setSuggestionListMode(gSettings->value("GenOps/condensedView", 2).toInt()); + setSuggestionListMode(gSettings->value("GenOps/condensedView", 0).toInt()); altScroll = alternatives->verticalScrollBar(); altScroll->setObjectName("altScroll"); connect(alternatives, SIGNAL(currentRowChanged(int)), this, SLOT(alternativesRowChanged(int))); @@ -186,28 +186,18 @@ LaunchyWidget::LaunchyWidget(CommandFlags command) : } // Set the timers + updateTimer = new QTimer(this); dropTimer = new QTimer(this); dropTimer->setSingleShot(true); + connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateTimeout())); connect(dropTimer, SIGNAL(timeout()), this, SLOT(dropTimeout())); - - updateTimer = new QTimer(this); - connect(updateTimer, SIGNAL(timeout()), this, SLOT(buildCatalog())); - updateTimer->setSingleShot(true); - startUpdateTimer(); + int time = gSettings->value("GenOps/updatetimer", 10).toInt(); + if (time > 0) + updateTimer->start(time * 60000); // Load the catalog - gBuilder = new CatalogBuilder(&plugins); - gBuilder->moveToThread(&builderThread); - connect(gBuilder, SIGNAL(catalogIncrement(int)), this, SLOT(catalogProgressUpdated(int))); - connect(gBuilder, SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); - builderThread.start(QThread::IdlePriority); - builderThread.setObjectName("CatalogBuilder"); - - catalog = gBuilder->getCatalog(); - if (!catalog->load(settings.catalogFilename())) - { - command |= Rescan; - } + catalog.reset(CatalogBuilder::createCatalog()); + catalog->load(settings.catalogFilename()); // Load the history history.load(settings.historyFilename()); @@ -271,7 +261,7 @@ void LaunchyWidget::paintEvent(QPaintEvent* event) styleOption.init(this); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); - style()->drawPrimitive(QStyle::PE_Widget, &styleOption, &painter, this); + style()->drawPrimitive(QStyle::PE_Widget, &styleOption, &painter, this); // Now draw the standard frame.png graphic if there is one if (frameGraphic) @@ -344,105 +334,96 @@ void LaunchyWidget::showTrayIcon() } -// Repopulate the alternatives list with the current search results -// and set its size and position accordingly. -void LaunchyWidget::updateAlternatives(bool resetSelection) +void LaunchyWidget::showAlternatives(bool show, bool resetSelection) { - int mode = gSettings->value("GenOps/condensedView", 2).toInt(); - int i = 0; - for (; i < searchResults.size(); ++i) - { - qDebug() << "Alternative" << i << ":" << searchResults[i].fullPath; - QString fullPath = QDir::toNativeSeparators(searchResults[i].fullPath); -#ifdef _DEBUG - fullPath += QString(" (%1 launches)").arg(searchResults[i].usage); -#endif - QListWidgetItem* item; - if (i < alternatives->count()) - { - item = alternatives->item(i); - } - else - { - item = new QListWidgetItem(fullPath, alternatives); - } - if (item->data(mode == 1 ? ROLE_SHORT : ROLE_FULL) != fullPath) - { - // condensedTempIcon is a blank icon or null - item->setData(ROLE_ICON, *condensedTempIcon); - } - item->setData(mode == 1 ? ROLE_FULL : ROLE_SHORT, searchResults[i].shortName); - item->setData(mode == 1 ? ROLE_SHORT : ROLE_FULL, fullPath); - if (i >= alternatives->count()) - alternatives->addItem(item); - } + dropTimer->stop(); - while (alternatives->count() > i) - { - delete alternatives->takeItem(i); - } + // If main launchy window is not visible, do nothing + if (!isVisible()) + return; - if (resetSelection) + if (show) { - alternatives->setCurrentRow(0); - } - iconExtractor.processIcons(searchResults); - - // Now resize and reposition the list - int numViewable = gSettings->value("GenOps/numviewable", "4").toInt(); - int min = alternatives->count() < numViewable ? alternatives->count() : numViewable; - - // The stylesheet doesn't load immediately, so we cache the placement rectangle here - if (alternativesRect.isNull()) - alternativesRect = alternatives->geometry(); - QRect rect = alternativesRect; - rect.setHeight(min * alternatives->sizeHintForRow(0)); - rect.translate(pos()); + if (searchResults.size() < 1) + return; - // Is there room for the dropdown box? - if (rect.y() + rect.height() > qApp->desktop()->height()) - { - // Only move it if there's more space above - // In both cases, ensure it doesn't spill off the screen - if (pos().y() + input->pos().y() > qApp->desktop()->height() / 2) + int mode = gSettings->value("GenOps/condensedView", 0).toInt(); + int i = 0; + for (; i < searchResults.size(); ++i) { - rect.moveTop(pos().y() + input->pos().y() - rect.height()); - if (rect.top() < 0) - rect.setTop(0); + qDebug() << "Alternative" << i << ":" << searchResults[i].fullPath; + QString fullPath = QDir::toNativeSeparators(searchResults[i].fullPath); + + QListWidgetItem* item; + if (i < alternatives->count()) + { + item = alternatives->item(i); + } + else + { + item = new QListWidgetItem(fullPath, alternatives); + } + if (item->data(mode == 1 ? ROLE_SHORT : ROLE_FULL) != fullPath) + { + // condensedTempIcon is a blank icon or null + item->setData(ROLE_ICON, *condensedTempIcon); + } + item->setData(mode == 1 ? ROLE_FULL : ROLE_SHORT, searchResults[i].shortName); + item->setData(mode == 1 ? ROLE_SHORT : ROLE_FULL, fullPath); + if (i >= alternatives->count()) + alternatives->addItem(item); } - else + while (alternatives->count() > i) { - rect.setBottom(qApp->desktop()->height()); + delete alternatives->takeItem(i); } - } - - alternatives->setGeometry(rect); -} - -void LaunchyWidget::showAlternatives() -{ - // Ensure that any pending shows of the alternatives list are cancelled - // so that we only update the list once. - dropTimer->stop(); + if (resetSelection) + { + alternatives->setCurrentRow(0); + } + iconExtractor.processIcons(searchResults); - alternatives->show(); - alternatives->setFocus(); - qApp->syncX(); -} + int numViewable = gSettings->value("GenOps/numviewable", "4").toInt(); + int min = alternatives->count() < numViewable ? alternatives->count() : numViewable; + // The stylesheet doesn't load immediately, so we cache the rect here + if (alternativesRect.isNull()) + alternativesRect = alternatives->geometry(); + QRect rect = alternativesRect; + rect.setHeight(min * alternatives->sizeHintForRow(0)); + rect.translate(pos()); -void LaunchyWidget::hideAlternatives() -{ - // Ensure that any pending shows of the alternatives list are cancelled - // so that the list isn't erroneously shown shortly after being dismissed. - dropTimer->stop(); + // Is there room for the dropdown box? + if (rect.y() + rect.height() > qApp->desktop()->height()) + { + // Only move it if there's more space above + // In both cases, ensure it doesn't spill off the screen + if (pos().y() + input->pos().y() > qApp->desktop()->height() / 2) + { + rect.moveTop(pos().y() + input->pos().y() - rect.height()); + if (rect.top() < 0) + rect.setTop(0); + } + else + { + rect.setBottom(qApp->desktop()->height()); + } + } - // clear the selection before hiding to prevent flicker - alternatives->setCurrentRow(-1); - alternatives->repaint(); - alternatives->hide(); - iconExtractor.stop(); + alternatives->setGeometry(rect); + alternatives->show(); + alternatives->setFocus(); + qApp->syncX(); + } + else + { + // clear the selection before hiding to prevent flicker + alternatives->setCurrentRow(-1); + alternatives->repaint(); + alternatives->hide(); + iconExtractor.stop(); + } } @@ -499,9 +480,8 @@ void LaunchyWidget::launchItem(CatItem& item) void LaunchyWidget::focusInEvent(QFocusEvent* event) { - if (event->gotFocus() && fader->isFading()) - fader->fadeIn(false); - + if (event->gotFocus() && fader->isFading()) + fader->fadeIn(false); QWidget::focusInEvent(event); } @@ -509,10 +489,10 @@ void LaunchyWidget::focusInEvent(QFocusEvent* event) void LaunchyWidget::focusOutEvent(QFocusEvent* event) { - if (event->reason() == Qt::ActiveWindowFocusReason) + if (event->reason() == Qt::ActiveWindowFocusReason) { if (gSettings->value("GenOps/hideiflostfocus", false).toBool() && - !isActiveWindow() && !alternatives->isActiveWindow() && !optionsOpen && !fader->isFading()) + !isActiveWindow() && !alternatives->isActiveWindow() && !optionsOpen) { hideLaunchy(); } @@ -537,34 +517,30 @@ void LaunchyWidget::alternativesRowChanged(int index) if (item.id == HASH_HISTORY && historyIndex < searchResults.count()) { inputData = history.getItem(historyIndex); + gSearchText = inputData.last().getText(); input->selectAll(); input->insert(inputData.toString()); input->selectAll(); - output->setText(inputData[0].getTopResult().shortName); - // No need to fetch the icon again, just grab it from the alternatives row - outputIcon->setPixmap(alternatives->item(index)->icon().pixmap(outputIcon->size())); - outputItem = item; - gSearchText = inputData.toString(); + output->setText(Catalog::decorateText(item.shortName, gSearchText, true)); + iconExtractor.processIcon(item); } } else if (inputData.count() > 0 && (inputData.last().hasLabel(LABEL_AUTOSUGGEST) || inputData.last().hasText() == 0)) { qDebug() << "Autosuggest" << item.shortName; + gSearchText = item.shortName; inputData.last().setText(item.shortName); inputData.last().setLabel(LABEL_AUTOSUGGEST); QString root = inputData.toString(true); input->selectAll(); - input->insert(root + item.shortName); - input->setSelection(root.length(), item.shortName.length()); - - output->setText(item.shortName); - // No need to fetch the icon again, just grab it from the alternatives row - outputIcon->setPixmap(alternatives->item(index)->icon().pixmap(outputIcon->size())); - outputItem = item; - gSearchText = ""; + input->insert(root + gSearchText); + input->setSelection(root.length(), gSearchText.length()); + + output->setText(Catalog::decorateText(gSearchText, gSearchText, true)); + iconExtractor.processIcon(item); } } } @@ -580,6 +556,9 @@ void LaunchyWidget::inputKeyPressEvent(QKeyEvent* event) { event->ignore(); } + + if (input->text().length() == 0) + showAlternatives(false); } @@ -587,9 +566,9 @@ void LaunchyWidget::alternativesKeyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Escape) { - hideAlternatives(); - input->setFocus(); + showAlternatives(false); event->ignore(); + this->input->setFocus(); } else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter || event->key() == Qt::Key_Tab) { @@ -636,8 +615,7 @@ void LaunchyWidget::alternativesKeyPressEvent(QKeyEvent* event) // Delete selected history entry from the alternatives list history.removeAt(row); input->clear(); - searchOnInput(); - updateAlternatives(false); + processKey(); alternativesRowChanged(alternatives->currentRow()); } else @@ -647,6 +625,7 @@ void LaunchyWidget::alternativesKeyPressEvent(QKeyEvent* event) searchOnInput(); updateOutputWidgets(false); } + showAlternatives(true, false); } } else if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right || @@ -659,7 +638,7 @@ void LaunchyWidget::alternativesKeyPressEvent(QKeyEvent* event) input->keyPressEvent(event); keyPressEvent(event); } - alternatives->setFocus(); + alternatives->setFocus(); } @@ -668,7 +647,7 @@ void LaunchyWidget::keyPressEvent(QKeyEvent* event) if (event->key() == Qt::Key_Escape) { if (alternatives->isVisible()) - hideAlternatives(); + showAlternatives(false); else hideLaunchy(); } @@ -704,11 +683,14 @@ void LaunchyWidget::keyPressEvent(QKeyEvent* event) searchOnInput(); if (searchResults.count() > 0) { - updateAlternatives(); showAlternatives(); + alternatives->activateWindow(); + if (alternatives->count() > 0) + alternatives->setCurrentRow(0); } } } + else if ((event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backspace) && event->modifiers() == Qt::ShiftModifier) { doBackTab(); @@ -719,19 +701,14 @@ void LaunchyWidget::keyPressEvent(QKeyEvent* event) doTab(); processKey(); } + /* else if (event->key() == Qt::Key_Slash || event->key() == Qt::Key_Backslash) { - if (inputData.count() > 0 && inputData.last().hasLabel(LABEL_FILE) && - searchResults.count() > 0 && searchResults[0].id == HASH_LAUNCHYFILE) + if (inputData.count() > 0 && inputData.last().hasLabel(LABEL_FILE)) doTab(); processKey(); } - else if (event->key()== Qt::Key_Insert && event->modifiers() == Qt::ShiftModifier) - { - // ensure pasting text with Shift+Insert also parses input - // longer term parsing should be done using the TextChanged event - processKey(); - } + */ else if (event->text().length() > 0) { // process any other key with character output @@ -748,35 +725,13 @@ void LaunchyWidget::doBackTab() int index = text.lastIndexOf(input->separatorText()); if (index >= 0) { - text.truncate(index+3); - input->selectAll(); - input->insert(text); - } - - else if (text.lastIndexOf(QDir::separator()) >= 0) { - text.truncate(text.lastIndexOf(QDir::separator())+1); - input->selectAll(); - input->insert(text); - } - else if (text.lastIndexOf(QChar(' ')) >= 0) { - text.truncate(text.lastIndexOf(QChar(' '))+1); - input->selectAll(); - input->insert(text); - } - - else if (text.lastIndexOf(QDir::separator()) >= 0) { - text.truncate(text.lastIndexOf(QDir::separator())+1); - input->selectAll(); - input->insert(text); - } - else if (text.lastIndexOf(QChar(' ')) >= 0) { - text.truncate(text.lastIndexOf(QChar(' '))+1); + text.truncate(index); input->selectAll(); input->insert(text); } else { - input->clear(); + input->clear(); } } @@ -788,8 +743,54 @@ void LaunchyWidget::doTab() // If it's an incomplete file or directory, complete it QFileInfo info(searchResults[0].fullPath); - if (inputData.last().hasLabel(LABEL_FILE) || info.isDir()) + if ((inputData.last().hasLabel(LABEL_FILE) || info.isDir()) + )// && input->text().compare(QDir::toNativeSeparators(searchResults[0].fullPath), Qt::CaseInsensitive) != 0) { + + // If multiple paths exist, select the longest intersection (like the bash shell) + if (!alternatives->isActiveWindow()) + { + QStringList paths; + int minLength = -1; + foreach(const CatItem& item, searchResults) { + if (item.id == HASH_LAUNCHYFILE) { + QString p = item.fullPath; + paths += p; + if (minLength == -1 || p.length() < minLength) + minLength = p.length(); + qDebug() << p; + } + } + qDebug() << ""; + + if (paths.size() > 1) { + // Find the longest prefix common to all of the paths + QChar curChar; + QString longestPrefix = ""; + for(int i = 0; i < minLength; i++) { + curChar = paths[0][i]; + bool stop = false; + foreach(QString path, paths) { +#ifdef Q_WS_WIN + if (path[i].toLower() != curChar.toLower()) { +#else + if (path[i] != curChar) { +#endif + stop = true; + break; + } + } + if (stop) break; + longestPrefix += curChar; + } + + input->selectAll(); + input->insert(inputData.toString(true) + longestPrefix); + return; + } + } + + QString path; if (info.isSymLink()) path = info.symLinkTarget(); @@ -808,6 +809,9 @@ void LaunchyWidget::doTab() inputData.last().setText(searchResults[0].shortName); input->selectAll(); input->insert(inputData.toString() + input->separatorText()); + + QRect rect = input->rect(); + repaint(rect); } } } @@ -815,25 +819,25 @@ void LaunchyWidget::doTab() void LaunchyWidget::doEnter() { - hideAlternatives(); + showAlternatives(false); if ((inputData.count() > 0 && searchResults.count() > 0) || inputData.count() > 1) { CatItem& item = inputData[0].getTopResult(); qDebug() << "Launching" << item.shortName << ":" << item.fullPath; launchItem(item); - hideLaunchy(); } else { qDebug("Nothing to launch"); } + hideLaunchy(); } void LaunchyWidget::inputMethodEvent(QInputMethodEvent* event) { - event = event; // Warning removal + event = event; // Warning removal processKey(); } @@ -843,17 +847,6 @@ void LaunchyWidget::processKey() inputData.parse(input->text()); searchOnInput(); updateOutputWidgets(); - - // If there is no input text, ensure that the alternatives list is hidden - // otherwise, show it after the user defined delay if it's not currently visible - if (input->text().length() == 0) - { - hideAlternatives(); - } - else if (!alternatives->isVisible()) - { - startDropTimer(); - } } @@ -863,44 +856,36 @@ void LaunchyWidget::searchOnInput() return; QString searchText = inputData.count() > 0 ? inputData.last().getText() : ""; - QString searchTextLower = searchText.toLower(); - gSearchText = searchTextLower; + gSearchText = searchText; searchResults.clear(); + // Add history items on their own and don't sort them so they remain in most recently used order if ((inputData.count() > 0 && inputData.first().hasLabel(LABEL_HISTORY)) || input->text().length() == 0) { - // Add history items exclusively and unsorted so they remain in most recently used order qDebug() << "Searching history for" << searchText; - history.search(searchTextLower, searchResults); + history.search(searchText, searchResults); } else { - // Search the catalog for matching items if (inputData.count() == 1) { qDebug() << "Searching catalog for" << searchText; - catalog->searchCatalogs(searchTextLower, searchResults); + catalog->searchCatalogs(gSearchText, searchResults); } if (searchResults.count() != 0) inputData.last().setTopResult(searchResults[0]); - // Give plugins a chance to add their own dynamic matches plugins.getLabels(&inputData); plugins.getResults(&inputData, &searchResults); - - // Sort the results by match and usage, then promote any that match previously - // executed commands qSort(searchResults.begin(), searchResults.end(), CatLessNoPtr); - catalog->promoteRecentlyUsedItems(searchTextLower, searchResults); - // Finally, if the search text looks like a file or directory name, - // add any file or directory matches + // Is it a file? if (searchText.contains(QDir::separator()) || searchText.startsWith("~") || (searchText.size() == 2 && searchText[0].isLetter() && searchText[1] == ':')) - { FileSearch::search(searchText, searchResults, inputData); - } + + catalog->promoteRecentlyUsedItems(gSearchText, searchResults); } } @@ -908,43 +893,33 @@ void LaunchyWidget::searchOnInput() // If there are current results, update the output text and icon void LaunchyWidget::updateOutputWidgets(bool resetAlternativesSelection) { - if (searchResults.count() > 0 && (inputData.count() > 1 || input->text().length() > 0)) + if (searchResults.count() > 0 && (inputData.count() > 1 || gSearchText.length() > 0)) { qDebug() << "Setting output text to" << searchResults[0].shortName; + output->setText(Catalog::decorateText(searchResults[0].shortName, gSearchText, true)); + iconExtractor.processIcon(searchResults[0]); - QString outputText = Catalog::decorateText(searchResults[0].shortName, gSearchText, true); -#ifdef _DEBUG - outputText += QString(" (%1 launches)").arg(searchResults[0].usage); -#endif - output->setText(outputText); - if (outputItem != searchResults[0]) - { - outputItem = searchResults[0]; - outputIcon->clear(); - iconExtractor.processIcon(searchResults[0]); - } - - if (outputItem.id != HASH_HISTORY) +//outputIcon->setPixmap(platform->icon(searchResults[0].fullPath).pixmap((outputIcon->size()))); + if (searchResults[0].id != HASH_HISTORY) { // Did the plugin take control of the input? if (inputData.last().getID() != 0) - outputItem.id = inputData.last().getID(); + searchResults[0].id = inputData.last().getID(); inputData.last().setTopResult(searchResults[0]); } - // Only update the alternatives list if it is visible - if (alternatives->isVisible()) - { - updateAlternatives(resetAlternativesSelection); - } + // If the alternatives are already showing, update them + if (alternatives->isVisible()) + showAlternatives(true, resetAlternativesSelection); + // Don't schedule a drop down if there's no input text + else if (input->text().length() > 0) + startDropTimer(); } else { - // No results to show, clear the output UI and hide the alternatives list output->clear(); outputIcon->clear(); - outputItem = CatItem(); - hideAlternatives(); + showAlternatives(false); } } @@ -955,66 +930,47 @@ void LaunchyWidget::startDropTimer() if (delay > 0) dropTimer->start(delay); else - dropTimeout(); + showAlternatives(false); } -void LaunchyWidget::dropTimeout() -{ - // Don't do anything if Launchy has been hidden since the timer was started - if (isVisible() && searchResults.count() > 0) - { - updateAlternatives(); - showAlternatives(); - } -} - - -void LaunchyWidget::iconExtracted(int itemIndex, QString path, QIcon icon) +void LaunchyWidget::iconExtracted(int itemIndex, QIcon icon) { if (itemIndex == -1) { - // An index of -1 means update the output icon, check that it is also - // the same item as was originally requested - if (path == outputItem.fullPath) - { - outputIcon->setPixmap(icon.pixmap(outputIcon->size())); - } + // An index of -1 means update the output icon + outputIcon->setPixmap(icon.pixmap(outputIcon->size())); } else if (itemIndex < alternatives->count()) { - // >=0 is an item in the alternatives list - if (itemIndex < searchResults.count() && path == searchResults[itemIndex].fullPath) - { - QListWidgetItem* listItem = alternatives->item(itemIndex); - listItem->setIcon(icon); - listItem->setData(ROLE_ICON, icon); + // >=0 is an item in the list + QListWidgetItem* listItem = alternatives->item(itemIndex); + listItem->setIcon(icon); + listItem->setData(ROLE_ICON, icon); - QRect rect = alternatives->visualItemRect(listItem); - repaint(rect); - } + QRect rect = alternatives->visualItemRect(listItem); + repaint(rect); } } -void LaunchyWidget::catalogProgressUpdated(int value) +void LaunchyWidget::catalogProgressUpdated(float /*val*/) { - if (value == 0) - { - workingAnimation->Start(); - } } void LaunchyWidget::catalogBuilt() { - // Save settings and updated catalog, stop the "working" animation - saveSettings(); + catalog = gBuilder->getCatalog(); + + gBuilder->wait(); + gBuilder.reset(); + workingAnimation->Stop(); + // Do a search here of the current input text + processKey(); - // Now do a search using the updated catalog - searchOnInput(); - updateOutputWidgets(); + catalog->save(settings.catalogFilename()); } @@ -1115,23 +1071,25 @@ void LaunchyWidget::loadPosition(QPoint pt) } -void LaunchyWidget::saveSettings() +void LaunchyWidget::updateTimeout() { - qDebug() << "Save settings"; + // Save the settings periodically savePosition(); gSettings->sync(); - catalog->save(settings.catalogFilename()); - history.save(settings.historyFilename()); -} - -void LaunchyWidget::startUpdateTimer() -{ + buildCatalog(); + int time = gSettings->value("GenOps/updatetimer", 10).toInt(); + updateTimer->stop(); if (time != 0) updateTimer->start(time * 60000); - else - updateTimer->stop(); +} + + +void LaunchyWidget::dropTimeout() +{ + if (searchResults.count() > 0) + showAlternatives(); } @@ -1155,9 +1113,12 @@ void LaunchyWidget::onHotkey() void LaunchyWidget::closeEvent(QCloseEvent* event) { - builderThread.exit(); fader->stop(); - saveSettings(); + savePosition(); + gSettings->sync(); + + catalog->save(settings.catalogFilename()); + history.save(settings.historyFilename()); event->accept(); qApp->quit(); @@ -1206,7 +1167,7 @@ void LaunchyWidget::reloadSkin() void LaunchyWidget::applySkin(const QString& name) { - currentSkin = name; + currentSkin = name; if (listDelegate == NULL) return; @@ -1249,11 +1210,6 @@ void LaunchyWidget::applySkin(const QString& name) QString styleSheet = QLatin1String(file.readAll()); file.close(); - // Remove incorrect selectors from the stylesheet - styleSheet.replace("QLineEdit#", "#"); - styleSheet.replace("QPushButton#", "#"); - styleSheet.replace("QListWidget#", "#"); - // This is causing the ::destroyed connect errors qApp->setStyleSheet(styleSheet); @@ -1378,7 +1334,7 @@ void LaunchyWidget::applySkin(const QString& name) if (frameGraphic) { resize(frameGraphic->size()); - } + } } int maxIconSize = outputIcon->width(); @@ -1397,7 +1353,7 @@ void LaunchyWidget::mousePressEvent(QMouseEvent *e) dragStartPoint = e->pos(); } } - hideAlternatives(); + showAlternatives(false); activateWindow(); input->setFocus(); } @@ -1409,7 +1365,7 @@ void LaunchyWidget::mouseMoveEvent(QMouseEvent *e) { QPoint p = e->globalPos() - dragStartPoint; move(p); - hideAlternatives(); + showAlternatives(false); input->setFocus(); } } @@ -1417,9 +1373,9 @@ void LaunchyWidget::mouseMoveEvent(QMouseEvent *e) void LaunchyWidget::mouseReleaseEvent(QMouseEvent* event) { - event = event; // Warning removal + event = event; // Warning removal dragging = false; - hideAlternatives(); + showAlternatives(false); input->setFocus(); } @@ -1428,8 +1384,8 @@ void LaunchyWidget::contextMenuEvent(QContextMenuEvent* event) { QMenu menu(this); menu.addAction(actRebuild); - menu.addAction(actReloadSkin); - menu.addAction(actOptions); + menu.addAction(actReloadSkin); + menu.addAction(actOptions); menu.addSeparator(); menu.addAction(actExit); menuOpen = true; @@ -1442,27 +1398,30 @@ void LaunchyWidget::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason) { - case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::Trigger: showLaunchy(); - break; - case QSystemTrayIcon::Unknown: - case QSystemTrayIcon::Context: - case QSystemTrayIcon::DoubleClick: - case QSystemTrayIcon::MiddleClick: - break; + break; + case QSystemTrayIcon::Unknown: + case QSystemTrayIcon::Context: + case QSystemTrayIcon::DoubleClick: + case QSystemTrayIcon::MiddleClick: + break; } } void LaunchyWidget::buildCatalog() { - updateTimer->stop(); - saveSettings(); - - // Use the catalog builder to refresh the catalog in a worker thread - QMetaObject::invokeMethod(gBuilder, "buildCatalog", Qt::AutoConnection); - - startUpdateTimer(); + // Perform the database update + if (gBuilder == NULL) + { + gBuilder.reset(new CatalogBuilder(&plugins, catalog)); + connect(gBuilder.get(), SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); + connect(gBuilder.get(), SIGNAL(catalogIncrement(float)), this, SLOT(catalogProgressUpdated(float))); + workingAnimation->Start(); + gBuilder->start(QThread::IdlePriority); + //gBuilder->run(); + } } @@ -1470,7 +1429,8 @@ void LaunchyWidget::showOptionsDialog() { if (!optionsOpen) { - hideAlternatives(); + dropTimer->stop(); + showAlternatives(false); optionsOpen = true; OptionsDialog options(this); options.setObjectName("options"); @@ -1518,37 +1478,37 @@ void LaunchyWidget::setFadeLevel(double level) } else { - if (!isVisible()) { - show(); - activateWindow(); - raise(); - } + if (!isVisible()) + show(); } + // Make sure we grab focus once we've faded in + if (level >= 1.0) { + activateWindow(); + raise(); + } } void LaunchyWidget::showLaunchy(bool noFade) { shouldDonate(); - hideAlternatives(); + showAlternatives(false); +#ifdef Q_WS_WIN + // There's a problem with alpha layered windows under Vista after resuming + // from sleep. The alpha image may need to be reapplied. +#endif loadPosition(pos()); fader->fadeIn(noFade || alwaysShowLaunchy); + + //qApp->syncX(); #ifdef Q_WS_WIN // need to use this method in Windows to ensure that keyboard focus is set when // being activated via a hook or message from another instance of Launchy SetForegroundWindowEx(winId()); -#elif defined(Q_WS_X11) - /* Fix for bug 2994680: Not sure why this is necessary, perhaps someone with more - Qt experience can tell, but doing these two calls will force the window to actually - get keyboard focus when it is activated. It seems from the bug reports that this - only affects Linux (and I could only test it on my Linux system - running KDE), so - it leads me to believe that it is due to an issue in the Qt implementation on Linux. */ - grabKeyboard(); - releaseKeyboard(); #endif input->raise(); input->activateWindow(); @@ -1568,14 +1528,15 @@ void LaunchyWidget::showLaunchy() void LaunchyWidget::hideLaunchy(bool noFade) { - if (!isVisible() || isHidden()) - return; + if (!isVisible()) + return; savePosition(); - hideAlternatives(); + showAlternatives(false); if (alwaysShowLaunchy) return; + if (isVisible()) { fader->fadeOut(noFade); @@ -1615,7 +1576,7 @@ int LaunchyWidget::getHotkey() const int meta = Qt::ControlModifier; #endif #ifdef Q_WS_MAC - int meta = Qt::MetaModifier; + int meta = Qt::MetaModifier; #endif hotkey = gSettings->value("GenOps/hotkeyModifier", meta).toInt() | gSettings->value("GenOps/hotkeyAction", Qt::Key_Space).toInt(); @@ -1634,9 +1595,9 @@ void LaunchyWidget::createActions() connect(actRebuild, SIGNAL(triggered()), this, SLOT(buildCatalog())); addAction(actRebuild); - actReloadSkin = new QAction(tr("Reload skin"), this); + actReloadSkin = new QAction(tr("Reload skin"), this); actReloadSkin->setShortcut(QKeySequence(Qt::Key_F5 | Qt::SHIFT)); - connect(actReloadSkin, SIGNAL(triggered()), this, SLOT(reloadSkin())); + connect(actReloadSkin, SIGNAL(triggered()), this, SLOT(reloadSkin())); addAction(actReloadSkin); actOptions = new QAction(tr("Options"), this); @@ -1727,13 +1688,6 @@ int main(int argc, char *argv[]) { qInstallMsgHandler(fileLogMsgHandler); } - else if (arg.compare("profile", Qt::CaseInsensitive) == 0) - { - if (++i < args.length()) - { - settings.setProfileName(args[i]); - } - } } } @@ -1754,13 +1708,18 @@ int main(int argc, char *argv[]) qApp->setStyleSheet("file:///:/resources/basicskin.qss"); #ifdef Q_WS_WIN - LaunchyWidget* widget = createLaunchyWidget(command); + LaunchyWidget* widget = createLaunchyWidget(command); #else - LaunchyWidget* widget = new LaunchyWidget(command); + LaunchyWidget* widget = new LaunchyWidget(command); #endif qApp->exec(); + if (gBuilder != NULL) + { + gBuilder->wait(); + } + delete widget; widget = NULL; diff --git a/src/main.h b/src/main.h index dec115f..acb3fb1 100644 --- a/src/main.h +++ b/src/main.h @@ -37,6 +37,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "Fader.h" +using namespace boost; + + enum CommandFlag { None = 0, @@ -62,7 +65,7 @@ class LaunchyWidget : public QWidget void executeStartupCommand(int command); - Catalog* catalog; + shared_ptr catalog; PluginHandler plugins; void showLaunchy(bool noFade); @@ -75,7 +78,6 @@ class LaunchyWidget : public QWidget void setSkin(const QString& name); void loadOptions(); int getHotkey() const; - void startUpdateTimer(); protected: void paintEvent(QPaintEvent* event); @@ -89,12 +91,12 @@ public slots: void contextMenuEvent(QContextMenuEvent* event); void showOptionsDialog(); void onHotkey(); + void updateTimeout(); void dropTimeout(); void setOpaqueness(int level); void httpGetFinished(bool result); - void catalogProgressUpdated(int); + void catalogProgressUpdated(float); void catalogBuilt(); - void buildCatalog(); void inputMethodEvent(QInputMethodEvent* event); void keyPressEvent(QKeyEvent* event); void inputKeyPressEvent(QKeyEvent* event); @@ -102,13 +104,10 @@ public slots: void alternativesKeyPressEvent(QKeyEvent* event); void setFadeLevel(double level); void showLaunchy(); - void iconExtracted(int index, QString path, QIcon icon); + void buildCatalog(); + void iconExtracted(int itemIndex, QIcon icon); void trayIconActivated(QSystemTrayIcon::ActivationReason reason); - void reloadSkin(); - -protected: - void saveSettings(); - + void reloadSkin(); private: void createActions(); void applySkin(const QString& name); @@ -117,9 +116,7 @@ public slots: void updateVersion(int oldVersion); void checkForUpdate(); void shouldDonate(); - void updateAlternatives(bool resetSelection = true); - void showAlternatives(); - void hideAlternatives(); + void showAlternatives(bool show = true, bool resetSelection = true); void parseInput(const QString& text); void updateOutputWidgets(bool resetAlternativesSelection = true); void searchOnInput(); @@ -133,7 +130,7 @@ public slots: void addToHistory(QList& item); void startDropTimer(); - QString currentSkin; + QString currentSkin; Fader* fader; QPixmap* frameGraphic; @@ -157,10 +154,9 @@ public slots: QTimer* updateTimer; QTimer* dropTimer; - QThread builderThread; + shared_ptr catalogBuilder; IconExtractor iconExtractor; QIcon* condensedTempIcon; - CatItem outputItem; QList searchResults; InputDataList inputData; CommandHistory history; diff --git a/src/options.cpp b/src/options.cpp index 5893bcc..fde5f97 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -42,10 +42,6 @@ OptionsDialog::OptionsDialog(QWidget * parent) : restoreGeometry(windowGeometry); tabWidget->setCurrentIndex(currentTab); -#ifdef Q_WS_WIN - about_homepage->setText(about_homepage->text() + \ - "


If you would like to uninstall Launchy, please close Launchy and run \"Uninstall Launchy\" from the start menu.

"); -#endif // Load General Options if (QSystemTrayIcon::isSystemTrayAvailable()) genShowTrayIcon->setChecked(gSettings->value("GenOps/showtrayicon", true).toBool()); @@ -63,7 +59,8 @@ OptionsDialog::OptionsDialog(QWidget * parent) : genUpdateCheck->setChecked(gSettings->value("GenOps/updatecheck", true).toBool()); genShowHidden->setChecked(gSettings->value("GenOps/showHiddenFiles", false).toBool()); genShowNetwork->setChecked(gSettings->value("GenOps/showNetwork", true).toBool()); - genCondensed->setCurrentIndex(gSettings->value("GenOps/condensedView", 2).toInt()); + genUseWildcards->setChecked(gSettings->value("GenOps/wildcardFileSearch", false).toBool()); + genCondensed->setCurrentIndex(gSettings->value("GenOps/condensedView", 0).toInt()); genAutoSuggestDelay->setValue(gSettings->value("GenOps/autoSuggestDelay", 1000).toInt()); int updateInterval = gSettings->value("GenOps/updatetimer", 10).toInt(); connect(genUpdateCatalog, SIGNAL(stateChanged(int)), this, SLOT(autoUpdateCheckChanged(int))); @@ -78,8 +75,8 @@ OptionsDialog::OptionsDialog(QWidget * parent) : connect(genOpaqueness, SIGNAL(sliderMoved(int)), gMainWidget, SLOT(setOpaqueness(int))); #ifdef Q_WS_MAC - metaKeys << tr("") << tr("Alt") << tr("Command") << tr("Shift") << tr("Control") << - tr("Command+Alt") << tr("Command+Shift") << tr("Command+Control"); + metaKeys << tr("") << tr("Alt") << tr("Command") << tr("Shift") << tr("Control") << + tr("Command+Alt") << tr("Command+Shift") << tr("Command+Control"); #else metaKeys << tr("") << tr("Alt") << tr("Control") << tr("Shift") << tr("Win") << tr("Ctrl+Alt") << tr("Ctrl+Shift") << tr("Ctrl+Win"); @@ -148,7 +145,7 @@ OptionsDialog::OptionsDialog(QWidget * parent) : QHash knownSkins; foreach(QString szDir, settings.directory("skins")) { - QDir dir(szDir); + QDir dir(szDir); QStringList dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); foreach(QString d, dirs) @@ -188,10 +185,26 @@ OptionsDialog::OptionsDialog(QWidget * parent) : connect(catCheckDirs, SIGNAL(stateChanged(int)), this, SLOT(catTypesDirChanged(int))); connect(catCheckBinaries, SIGNAL(stateChanged(int)), this, SLOT(catTypesExeChanged(int))); connect(catDepth, SIGNAL(valueChanged(int)),this, SLOT(catDepthChanged(int))); + catRescan->setEnabled(gBuilder == NULL); connect(catRescan, SIGNAL(clicked(bool)), this, SLOT(catRescanClicked(bool))); - catProgress->setVisible(false); + int size = gSettings->beginReadArray("directories"); + for (int i = 0; i < size; ++i) + { + gSettings->setArrayIndex(i); + Directory tmp; + tmp.name = gSettings->value("name").toString(); + tmp.types = gSettings->value("types").toStringList(); + tmp.indexDirs = gSettings->value("indexDirs", false).toBool(); + tmp.indexExe = gSettings->value("indexExes", false).toBool(); + tmp.depth = gSettings->value("depth", 100).toInt(); + memDirs.append(tmp); + } + gSettings->endArray(); + if (memDirs.count() == 0) + { + memDirs = platform->getDefaultCatalogDirectories(); + } - memDirs = SettingsManager::readCatalogDirectories(); for (int i = 0; i < memDirs.count(); ++i) { catDirectories->addItem(memDirs[i].name); @@ -207,14 +220,11 @@ OptionsDialog::OptionsDialog(QWidget * parent) : { catSize->setText(tr("Index has %n item(s)", "", gMainWidget->catalog->count())); } - - connect(gBuilder, SIGNAL(catalogIncrement(int)), this, SLOT(catalogProgressUpdated(int))); - connect(gBuilder, SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); - if (gBuilder->isRunning()) + if (gBuilder != NULL) { - catalogProgressUpdated(gBuilder->getProgress()); + connect(gBuilder.get(), SIGNAL(catalogIncrement(float)), this, SLOT(catProgressUpdated(float))); + connect(gBuilder.get(), SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); } - // Load up the plugins connect(plugList, SIGNAL(currentRowChanged(int)), this, SLOT(pluginChanged(int))); connect(plugList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(pluginItemChanged(QListWidgetItem*))); @@ -246,8 +256,8 @@ OptionsDialog::~OptionsDialog() { if (gBuilder != NULL) { - disconnect(gBuilder, SIGNAL(catalogIncrement(int)), this, SLOT(catalogProgressUpdated(int))); - disconnect(gBuilder, SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); + disconnect(gBuilder.get(), SIGNAL(catalogIncrement(float)), this, SLOT(catProgressUpdated(float))); + disconnect(gBuilder.get(), SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); } currentTab = tabWidget->currentIndex(); @@ -262,7 +272,7 @@ void OptionsDialog::setVisible(bool visible) if (visible) { connect(skinList, SIGNAL(currentTextChanged(const QString)), this, SLOT(skinChanged(const QString))); - skinChanged(skinList->currentItem()->text()); + skinChanged(skinList->currentItem()->text()); } } @@ -293,6 +303,7 @@ void OptionsDialog::accept() gSettings->setValue("GenOps/dragmode", genShiftDrag->isChecked() ? 1 : 0); gSettings->setValue("GenOps/showHiddenFiles", genShowHidden->isChecked()); gSettings->setValue("GenOps/showNetwork", genShowNetwork->isChecked()); + gSettings->setValue("GenOps/wildcardFileSearch", genUseWildcards->isChecked()); gSettings->setValue("GenOps/condensedView", genCondensed->currentIndex()); gSettings->setValue("GenOps/autoSuggestDelay", genAutoSuggestDelay->value()); gSettings->setValue("GenOps/updatetimer", genUpdateCatalog->isChecked() ? genUpdateMinutes->value() : 0); @@ -308,12 +319,11 @@ void OptionsDialog::accept() // Apply General Options settings.setPortable(genPortable->isChecked()); - gMainWidget->startUpdateTimer(); gMainWidget->setSuggestionListMode(genCondensed->currentIndex()); gMainWidget->loadOptions(); // Apply Directory Options - SettingsManager::writeCatalogDirectories(memDirs); + saveCatalogOptions(); if (curPlugin >= 0) { @@ -371,8 +381,8 @@ void OptionsDialog::tabChanged(int tab) } else if (tabWidget->currentWidget()->objectName() == "Plugins") { - // We've currently no way of checking if a plugin requires a catalog rescan - // so assume that we need one if the user has viewed the plugins tab + // We've currently no way of checking is a plugin requires a catalog rescan + // assume that needRescan = true; } } @@ -391,8 +401,8 @@ void OptionsDialog::skinChanged(const QString& newSkin) if (newSkin.count() == 0) return; - // Find the skin with this name - QString directory = settings.skinPath(newSkin); + // Find the skin with this name + QString directory = settings.skinPath(newSkin); // Load up the author file if (directory.length() == 0) @@ -481,16 +491,11 @@ void OptionsDialog::pluginChanged(int row) // Open the new plugin dialog curPlugin = row; currentPlugin = row; - if (row >= 0) - { - loadPluginDialog(plugList->item(row)); - } -} - - -void OptionsDialog::loadPluginDialog(QListWidgetItem* item) -{ + if (row < 0) + return; + QListWidgetItem* item = plugList->item(row); QWidget* win = gMainWidget->plugins.doDialog(plugBox, item->data(Qt::UserRole).toUInt()); + if (win != NULL) { if (plugBox->layout() != NULL) @@ -539,29 +544,22 @@ void OptionsDialog::pluginItemChanged(QListWidgetItem* iz) // If enabled, reload the dialog if (iz->checkState() == Qt::Checked) { - loadPluginDialog(iz); + gMainWidget->plugins.doDialog(plugBox, iz->data(Qt::UserRole).toUInt()); } } -void OptionsDialog::catalogProgressUpdated(int value) +void OptionsDialog::catProgressUpdated(float val) { - catSize->setVisible(false); - catProgress->setValue(value); - catProgress->setVisible(true); - catRescan->setEnabled(false); + catProgress->setValue((int) val); } void OptionsDialog::catalogBuilt() { - catProgress->setVisible(false); catRescan->setEnabled(true); if (gMainWidget->catalog != NULL) - { catSize->setText(tr("Index has %n items", "", gMainWidget->catalog->count())); - catSize->setVisible(true); - } } @@ -570,11 +568,16 @@ void OptionsDialog::catRescanClicked(bool val) val = val; // Compiler warning // Apply Directory Options - SettingsManager::writeCatalogDirectories(memDirs); + saveCatalogOptions(); - needRescan = false; - catRescan->setEnabled(false); - gMainWidget->buildCatalog(); + if (gBuilder == NULL) + { + needRescan = false; + catRescan->setEnabled(false); + gMainWidget->buildCatalog(); + connect(gBuilder.get(), SIGNAL(catalogFinished()), this, SLOT(catalogBuilt())); + connect(gBuilder.get(), SIGNAL(catalogIncrement(float)), this, SLOT(catProgressUpdated(float))); + } } @@ -681,11 +684,18 @@ void OptionsDialog::catDirMinusClicked(bool c) void OptionsDialog::catDirPlusClicked(bool c) { c = c; // Compiler warning - addDirectory("", true); + QString dir = QFileDialog::getExistingDirectory(this, tr("Select a directory"), + lastDir, + QFileDialog::ShowDirsOnly); + if (dir != "") + { + lastDir = dir; + addDirectory(dir); + } } -void OptionsDialog::addDirectory(const QString& directory, bool edit) +void OptionsDialog::addDirectory(const QString& directory) { QString nativeDir = QDir::toNativeSeparators(directory); Directory dir(nativeDir); @@ -695,10 +705,6 @@ void OptionsDialog::addDirectory(const QString& directory, bool edit) QListWidgetItem* item = new QListWidgetItem(nativeDir, catDirectories); item->setFlags(item->flags() | Qt::ItemIsEditable); catDirectories->setCurrentItem(item); - if (edit) - { - catDirectories->editItem(item); - } needRescan = true; } @@ -767,3 +773,20 @@ void OptionsDialog::catDepthChanged(int d) needRescan = true; } + + +void OptionsDialog::saveCatalogOptions() +{ + gSettings->beginWriteArray("directories"); + for (int i = 0; i < memDirs.count(); ++i) + { + gSettings->setArrayIndex(i); + gSettings->setValue("name", memDirs[i].name); + gSettings->setValue("types", memDirs[i].types); + gSettings->setValue("indexDirs", memDirs[i].indexDirs); + gSettings->setValue("indexExes", memDirs[i].indexExe); + gSettings->setValue("depth", memDirs[i].depth); + } + + gSettings->endArray(); +} diff --git a/src/options.h b/src/options.h index c9fe24b..8a9ebf0 100644 --- a/src/options.h +++ b/src/options.h @@ -1,6 +1,6 @@ /* Launchy: Application Launcher -Copyright (C) 2007-2010 Josh Karlin, Simon Capewell +Copyright (C) 2007-2009 Josh Karlin, Simon Capewell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -53,16 +53,15 @@ public slots: void catTypesDirChanged(int); void catTypesExeChanged(int); void catDepthChanged(int); - void catalogProgressUpdated(int); + void catProgressUpdated(float); void catalogBuilt(); void catRescanClicked(bool); void pluginChanged(int row); void pluginItemChanged(QListWidgetItem* state); private: - void addDirectory(const QString& directory, bool edit = false); - void loadPluginDialog(QListWidgetItem* item); - void connectCatalogBuilderEvents(); + void addDirectory(const QString& directory); + void saveCatalogOptions(); private: FileBrowserDelegate directoryItemDelegate; diff --git a/src/options.ui b/src/options.ui index c591b21..e497ff4 100644 --- a/src/options.ui +++ b/src/options.ui @@ -21,7 +21,7 @@ - 4 + 0 @@ -569,6 +569,13 @@ + + + + Allow wildcards in browse mode + + + @@ -895,16 +902,56 @@ + + + - + - - - Rescan Catalog - - + + + + + Rescan Catalog + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Indexing 0 items + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -925,22 +972,6 @@ - - - - - 0 - 0 - - - - Indexing 0 items - - - Qt::AlignCenter - - - @@ -1087,7 +1118,7 @@ p, li { white-space: pre-wrap; } - + 321 @@ -1112,7 +1143,7 @@ p, li { white-space: pre-wrap; } Qt::AlignCenter - true + false true @@ -1139,14 +1170,7 @@ p, li { white-space: pre-wrap; } - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Credits</span></p> -<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Creator and Developer: Josh Karlin</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Developer: Simon Capewell</span></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"><html> <head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; }</style> </head> <body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"><p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Credits</span></p><p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Creator and Developer: Josh Karlin</span></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Developer: Simon Capewell</span></p><p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This build maintained by: Grant Cohoe</span></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"><a href="https://github.com/cohoe/launchy">https://github.com/cohoe/launchy</a></span></p></body></html> Qt::AlignCenter diff --git a/src/platform_base.h b/src/platform_base.h index 07f4d0e..deeef09 100644 --- a/src/platform_base.h +++ b/src/platform_base.h @@ -62,7 +62,7 @@ class PlatformBase : public QApplication virtual QString expandEnvironmentVars(QString txt) = 0; virtual bool supportsAlphaBorder() const { return false; } - virtual bool getComputers(QStringList& computers) const { Q_UNUSED(computers); return false; } + virtual bool getComputers(QList& computers) const { Q_UNUSED(computers); return false; } protected: diff --git a/src/plugin_handler.cpp b/src/plugin_handler.cpp index f8e5bda..61a13b8 100644 --- a/src/plugin_handler.cpp +++ b/src/plugin_handler.cpp @@ -20,17 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "precompiled.h" #include "plugin_handler.h" #include "main.h" -#include "globals.h" - - -int PluginInfo::sendMessage(int msgId, void* wParam, void* lParam) -{ - // This should have some kind of exception guard to prevent - // Launchy from crashing when a plugin is misbehaving. - // This would consist of a try/catch block to handle C++ exceptions - // and on Windows would also include a structured exception handler - return obj->msg(msgId, wParam, lParam); -} PluginHandler::PluginHandler() @@ -48,7 +37,7 @@ void PluginHandler::showLaunchy() foreach(PluginInfo info, plugins) { if (info.loaded) - info.sendMessage(MSG_LAUNCHY_SHOW); + info.obj->msg(MSG_LAUNCHY_SHOW); } } @@ -58,7 +47,7 @@ void PluginHandler::hideLaunchy() foreach(PluginInfo info, plugins) { if (info.loaded) - info.sendMessage(MSG_LAUNCHY_HIDE); + info.obj->msg(MSG_LAUNCHY_HIDE); } } @@ -70,7 +59,7 @@ void PluginHandler::getLabels(QList* inputData) foreach(PluginInfo info, plugins) { if (info.loaded) - info.sendMessage(MSG_GET_LABELS, (void*) inputData); + info.obj->msg(MSG_GET_LABELS, (void*) inputData); } } } @@ -83,32 +72,18 @@ void PluginHandler::getResults(QList* inputData, QList* resu foreach(PluginInfo info, plugins) { if (info.loaded) - info.sendMessage(MSG_GET_RESULTS, (void*) inputData, (void*) results); + info.obj->msg(MSG_GET_RESULTS, (void*) inputData, (void*) results); } } } -void PluginHandler::getCatalogs(Catalog* catalog, INotifyProgressStep* progressStep) +void PluginHandler::getCatalogs(QList* items) { - int index = 0; - foreach(PluginInfo info, plugins) { if (info.loaded) - { - QList items; - info.sendMessage(MSG_GET_CATALOG, (void*)&items); - foreach(CatItem item, items) - { - catalog->addItem(item); - } - if (progressStep) - { - progressStep->progressStep(index); - } - ++index; - } + info.obj->msg(MSG_GET_CATALOG, (void*) items); } } @@ -117,7 +92,7 @@ int PluginHandler::execute(QList* inputData, CatItem* result) { if (!plugins.contains(result->id) || !plugins[result->id].loaded) return 0; - return plugins[result->id].sendMessage(MSG_LAUNCH_ITEM, (void*) inputData, (void*) result); + return plugins[result->id].obj->msg(MSG_LAUNCH_ITEM, (void*) inputData, (void*) result); } @@ -126,7 +101,7 @@ QWidget* PluginHandler::doDialog(QWidget* parent, uint id) if (!plugins.contains(id) || !plugins[id].loaded) return NULL; QWidget* newBox = NULL; - plugins[id].sendMessage(MSG_DO_DIALOG, (void*) parent, (void*) &newBox); + plugins[id].obj->msg(MSG_DO_DIALOG, (void*) parent, (void*) &newBox); return newBox; } @@ -135,7 +110,7 @@ void PluginHandler::endDialog(uint id, bool accept) { if (!plugins.contains(id) || !plugins[id].loaded) return; - plugins[id].sendMessage(MSG_END_DIALOG, (void*) accept); + plugins[id].obj->msg(MSG_END_DIALOG, (void*) accept); } @@ -154,77 +129,79 @@ void PluginHandler::loadPlugins() } gSettings->endArray(); - foreach(QString directory, settings.directory("plugins")) + foreach(QString szDir, settings.directory("plugins")) { // Load up the plugins in the plugins/ directory - QDir pluginsDir(directory); + QDir pluginsDir(szDir); + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { - if (!QLibrary::isLibrary(fileName)) - continue; + if (!QLibrary::isLibrary(fileName)) continue; QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); - qDebug() << "Loading plugin" << fileName; QObject *plugin = loader.instance(); if (!plugin) - { - qWarning() << fileName << "is not a plugin"; continue; - } + PluginInterface *plug = qobject_cast(plugin); if (!plug) - { - qWarning() << fileName << "is not a Launchy plugin"; continue; - } - - qDebug() << "Plugin loaded"; - + plug->settings = &gSettings; PluginInfo info; + uint id; + bool handled = plug->msg(MSG_GET_ID, (void*) &id) != 0; + info.id = id; + QString name; + plug->msg(MSG_GET_NAME, (void*) &name); + info.name = name; info.obj = plug; info.path = pluginsDir.absoluteFilePath(fileName); - bool handled = info.sendMessage(MSG_GET_ID, (void*) &info.id) != 0; - info.sendMessage(MSG_GET_NAME, (void*) &info.name); - if (handled && (!loadable.contains(info.id) || loadable[info.id])) + if (handled && (!loadable.contains(id) || loadable[id])) { info.loaded = true; - info.sendMessage(MSG_INIT); - info.sendMessage(MSG_PATH, &directory); + plug->msg(MSG_INIT); + plug->msg(MSG_PATH, &szDir); // Load any of the plugin's plugins of its own QList additionalPlugins; - info.sendMessage(MSG_LOAD_PLUGINS, &additionalPlugins); + plug->msg(MSG_LOAD_PLUGINS, &additionalPlugins); foreach(PluginInfo pluginInfo, additionalPlugins) { - if (!pluginInfo.isValid()) + const bool isValidPlugin = + pluginInfo.obj && + !pluginInfo.name.isNull() && + pluginInfo.id > 0; + if (!isValidPlugin) { continue; } - bool isPluginLoadable = + const bool isPluginLoadable = !loadable.contains(pluginInfo.id) || loadable[pluginInfo.id]; if (isPluginLoadable) { - pluginInfo.sendMessage(MSG_INIT); + pluginInfo.obj->msg(MSG_INIT); pluginInfo.loaded = true; } else { - pluginInfo.sendMessage(MSG_UNLOAD_PLUGIN, (void*) pluginInfo.id); + pluginInfo.obj->msg(MSG_UNLOAD_PLUGIN, (void*) pluginInfo.id); pluginInfo.loaded = false; } plugins[pluginInfo.id] = pluginInfo; } + + } else { info.loaded = false; loader.unload(); } - plugins[info.id] = info; + plugins[id] = info; } } } diff --git a/src/plugin_handler.h b/src/plugin_handler.h index 584ee18..c7e25e3 100644 --- a/src/plugin_handler.h +++ b/src/plugin_handler.h @@ -1,94 +1,68 @@ -/* -Launchy: Application Launcher -Copyright (C) 2007-2009 Josh Karlin - -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. -*/ - -#ifndef PLUGIN_HANDLER -#define PLUGIN_HANDLER - - -#include -#include -#include "plugin_interface.h" -#include "catalog.h" - - -class Catalog; - - -// This structure is used by plugins such as PyLaunchy, so it must not be extended -// with virtual methods or additional data members -struct PluginInfo -{ - uint id; - QString name; - QString path; - PluginInterface* obj; - bool loaded; - - PluginInfo() - { - id = 0; - obj = NULL; - loaded = false; - } - ~PluginInfo() - { - QPluginLoader loader(path); - loader.unload(); - } - - bool isValid() const - { - return obj && !name.isNull() && id > 0; - } - - int sendMessage(int msgId, void* wParam = NULL, void* lParam = NULL); -}; - - -// This interface is used to notify clients when a step in a long running process occurs -class INotifyProgressStep -{ -public: - virtual bool progressStep(int newStep) = 0; -}; - - -class PluginHandler -{ -public: - PluginHandler(); - ~PluginHandler(); - - void loadPlugins(); - void showLaunchy(); - void hideLaunchy(); - void getLabels(QList* inputData); - void getResults(QList* inputData, QList* results); - void getCatalogs(Catalog* catalog, INotifyProgressStep* progressStep); - int execute(QList*, CatItem*); - QWidget* doDialog(QWidget* parent, uint id); - void endDialog(uint id, bool accept); - QHash & getPlugins() { return plugins; } - -private: - QHash plugins; -}; - - -#endif +/* +Launchy: Application Launcher +Copyright (C) 2007-2009 Josh Karlin + +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. +*/ + +#ifndef PLUGIN_HANDLER +#define PLUGIN_HANDLER + + +#include +#include +#include "plugin_interface.h" +#include "catalog.h" + + +struct PluginInfo +{ + uint id; + QString name; + QString path; + PluginInterface* obj; + bool loaded; + + ~PluginInfo() + { + QPluginLoader loader(path); + loader.unload(); + } +}; + + +class PluginHandler +{ +public: + PluginHandler(); + ~PluginHandler(); + + void loadPlugins(); + void showLaunchy(); + void hideLaunchy(); + void getLabels(QList* inputData); + void getResults(QList* inputData, QList* results); + void getCatalogs(QList* items); + int execute(QList*, CatItem*); + QWidget* doDialog(QWidget* parent, uint id); + void endDialog(uint id, bool accept); + QHash & getPlugins() { return plugins; } + +private: + QHash plugins; +}; + + +#endif diff --git a/src/plugin_interface.cpp b/src/plugin_interface.cpp index a45f670..902eae2 100644 --- a/src/plugin_interface.cpp +++ b/src/plugin_interface.cpp @@ -106,10 +106,10 @@ void runProgram(QString path, QString args) { ShellExecuteEx(&ShExecInfo); } */ -void runProgram(QString path, QString args, bool translateSeparators) { +void runProgram(QString path, QString args) { // This 64 bit aliasing needs to be gotten rid of if we have a 64 bit build - path = aliasTo64(path); + path = aliasTo64(QDir::toNativeSeparators(path)); SHELLEXECUTEINFO ShExecInfo; @@ -120,7 +120,7 @@ void runProgram(QString path, QString args, bool translateSeparators) { ShExecInfo.fMask = NULL; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = elevated ? L"runas" : NULL; - QString filePath = translateSeparators ? QDir::toNativeSeparators(path) : path; + QString filePath = QDir::toNativeSeparators(path); ShExecInfo.lpFile = (LPCTSTR)filePath.utf16(); if (args != "") { @@ -148,9 +148,8 @@ void runProgram(QString path, QString args, bool translateSeparators) { int getDesktop() { return DESKTOP_MAC; } -void runProgram(QString path, QString args, bool translateSeparators) +void runProgram(QString path, QString args) { - translateSeparators = translateSeparators; // kill warning QString cmd; cmd = "open \"" + QDir::toNativeSeparators(path) + "\" --args " + args.trimmed(); QProcess::startDetached(cmd.trimmed()); @@ -179,7 +178,7 @@ int getDesktop() -void runProgram(QString path, QString args, bool translateSeparators) { +void runProgram(QString path, QString args) { QString fullname = path.split(" ")[0]; QFileInfo info(fullname); @@ -206,17 +205,193 @@ void runProgram(QString path, QString args, bool translateSeparators) { /* special case for KDE since some apps start behind other windows */ cmd = "kstart --activate " + path.trimmed() + " " + args.trimmed(); } else /* gnome, xfce, etc */ { + /* Fix from leonid-shevtsov path.replace("\"", "\\\""); - args.replace("\"", "\\\""); + #args.replace("\"", "\\\""); cmd = "sh -c \"" + path.trimmed() + " " + args.trimmed() + "\""; + */ + cmd = path.trimmed() + " " + args.trimmed(); } QProcess::startDetached(cmd); + + return; } + +/* + +void runProgram(QString path, QString args) { + QProcess proc; + QStringList largs; + QFileInfo info(path); + + + if (path.contains("%")) { + path.replace("%u", args); + path.replace("%U", args); + path.replace("%f", args); + path.replace("%F", args); + path.replace("%c", path.split(" ")[0]); + path.replace("%k", path.split(" ")[0]); + args = ""; + } + + QString toRun = path + " " + args; + toRun = toRun.simplified(); + + + + + + + + QString r; + + // r = "xdg-open \"" + path + "\" " + args + " 2>/dev/null || sh -c \"" + path + "\" " + args; + + r = "xdg-open \"" + path.trimmed() + "\" " + args.trimmed() + " 2>/dev/null || sh -c \"" + path.trimmed() + " " + args + "\""; + + + // qDebug() << r.simplified(); + QStringList ra; + + ra += "-c"; + ra += r.trimmed().simplified(); + // qDebug() << ra; + + // Firefox needs special treatment in KDE + // else it falls behind a window + if ((path.contains("http://",Qt::CaseInsensitive) || + path.contains("firefox",Qt::CaseInsensitive)) && + getDesktop() == DESKTOP_KDE) { + proc.execute("sh",ra); + } else { + proc.startDetached("sh",ra); + } + + //proc.execute("sh", ra); + + return; +} +*/ + + + + + + + + + + +/* +void runProgram(QString path, QString args) { + // My own launcher.. + QString mimetype; + QString locale = QLocale::system().name(); + if (path.startsWith("http", Qt::CaseInsensitive)) + mimetype = "text/html"; + if (mimetype == "") { + + QProcess proc; + + QStringList args; + args += "query"; + args += "filetype"; + args += path; + proc.setReadChannel(QProcess::StandardOutput); + proc.start(QString("xdg-mime"),args); + proc.waitForFinished(10000); + mimetype = proc.readAll().trimmed(); + proc.close(); + } + + // Get the default app for the mime-type + QString defapp; + if (mimetype.startsWith("application", Qt::CaseInsensitive)) + defapp = path; + + if (mimetype == "") + defapp = path; + + if (defapp == "") { + QProcess proc; + QStringList args; + args += "query"; + args += "default"; + args += mimetype; + proc.start(QString("xdg-mime"),args); + proc.waitForFinished(10000); + QString desk = proc.readAll().trimmed(); + if (desk == "") + defapp = path; + else { + QString icon; + QString name; + // Read the .desktop file + const char *dirs[] = { "/usr/share/applications/", + "/usr/local/share/applications/", + "/usr/share/gdm/applications/", + "/usr/share/applications/kde/", + "~/.local/share/applications/"}; + for(int i = 0; i < 5; i++) { + QString dir = dirs[i]; + QString path = dir + "/" + desk; + + if (QFile::exists(path)) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + break; + while(!file.atEnd()) { + QString line = file.readLine(); + if (line.startsWith("Exec", Qt::CaseInsensitive)) { + defapp = line.split("=")[1].trimmed(); + } + else if (line.startsWith("Icon",Qt::CaseInsensitive)) + icon = line.split("=")[1].trimmed(); + else if (line.startsWith("Name",Qt::CaseInsensitive)) { + if (line.startsWith("Name[" + locale, Qt::CaseInsensitive)) + name = line.split("=")[1].trimmed(); + else if (!line.contains("[")) + name = line.split("=")[1].trimmed(); + + } + } + defapp.replace("%k", path); + break; + } + } + defapp.replace("%u", "\"" + path + "\""); + defapp.replace("%U", "\"" + path + "\""); + defapp.replace("%f", "\"" + path + "\""); + defapp.replace("%F", "\"" + path + "\""); + defapp.replace("%i", "--icon " + icon); + defapp.replace("%c", name); + } + } + + + + // qDebug() << mimetype << defapp; + QString toRun = defapp + " " + args; + QStringList largs = toRun.simplified().split(" ", QString::SkipEmptyParts); + + qDebug() << largs; + QProcess proc; + + QString exec = largs[0]; + largs.removeFirst(); + qDebug() << exec << largs.join(" "); + proc.startDetached(exec, QStringList(largs.join(" "))); + + //proc.startDetached(exec, largs); + return; +} +*/ #endif diff --git a/src/plugin_interface.h b/src/plugin_interface.h index 137a0ed..578400f 100644 --- a/src/plugin_interface.h +++ b/src/plugin_interface.h @@ -579,9 +579,8 @@ class PluginInterface This function will run the program along with arguments and is platform independent. \param file The location of the file to run \param args The arguments to the command - \param translateSeparators Whether to translate / into native separators */ -void runProgram(QString file, QString args, bool translateSeparators = true); +void runProgram(QString file, QString args); int getDesktop(); diff --git a/src/precompiled.h b/src/precompiled.h index 04e2647..6f6bc02 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef _MSC_VER #pragma warning(push,3) -#define _CRT_SECURE_NO_WARNINGS #endif #include diff --git a/src/src.pro b/src/src.pro index 48fd28f..f007246 100644 --- a/src/src.pro +++ b/src/src.pro @@ -28,9 +28,10 @@ SOURCES = main.cpp \ CommandHistory.cpp \ InputDataList.cpp \ FileSearch.cpp \ - AnimationLabel.cpp \ + AnimationLabel.cpp \ SettingsManager.cpp HEADERS = platform_base.h \ + globals.h \ globals.h \ main.h \ catalog.h \ @@ -51,21 +52,26 @@ HEADERS = platform_base.h \ CommandHistory.h \ InputDataList.h \ FileSearch.h \ - AnimationLabel.h \ + AnimationLabel.h \ SettingsManager.h FORMS = options.ui -unix:!macx { + + + + +unix:!macx { ICON = Launchy.ico + SOURCES += ../platforms/unix/platform_unix.cpp \ - ../platforms/unix/platform_unix_util.cpp \ - ../platforms/unix/platform_x11_hotkey.cpp + ../platforms/unix/platform_unix_util.cpp \ + ../platforms/unix/platform_x11_hotkey.cpp HEADERS += ../platforms/unix/platform_unix.h \ - ../platforms/unix/platform_unix_util.h \ - ../platforms/unix/platform_x11_hotkey.h \ - platform_base_hotkey.h \ - platform_base_hottrigger.h + ../platforms/unix/platform_unix_util.h \ + ../platforms/unix/platform_x11_hotkey.h \ + platform_base_hotkey.h \ + platform_base_hottrigger.h - # Fedora patch file launchy-x11-lib.patch (original author unknown) + # Patch from Fedora (original author unknown) LIBS = -lX11 PREFIX = /usr @@ -76,7 +82,7 @@ unix:!macx { CONFIG(debug, debug|release):DESTDIR = ../debug/ CONFIG(release, debug|release):DESTDIR = ../release/ } - SOURCES += + SOURCES += target.path = $$PREFIX/bin/ skins.path = $$PREFIX/share/launchy/skins/ skins.files = ../skins/* @@ -91,29 +97,28 @@ unix:!macx { } win32 { ICON = Launchy.ico + if(!debug_and_release|build_pass):CONFIG(debug, debug|release):CONFIG += console SOURCES += ../platforms/win/platform_win.cpp \ ../platforms/win/platform_win_hotkey.cpp \ ../platforms/win/platform_win_util.cpp \ - ../platforms/win/WinIconProvider.cpp \ - ../platforms/win/minidump.cpp + ../platforms/win/WinIconProvider.cpp HEADERS += ../platforms/win/WinIconProvider.h \ platform_base_hotkey.h \ platform_base_hottrigger.h \ ../platforms/win/platform_win.h \ - ../platforms/win/platform_win_util.h \ - ../platforms/win/minidump.h + ../platforms/win/platform_win_util.h CONFIG += embed_manifest_exe INCLUDEPATH += c:/boost/ RC_FILE = ../win/launchy.rc - LIBS += shell32.lib \ - user32.lib \ - gdi32.lib \ - ole32.lib \ - comctl32.lib \ - advapi32.lib \ + LIBS += shell32.lib \ + user32.lib \ + gdi32.lib \ + ole32.lib \ + comctl32.lib \ + advapi32.lib \ userenv.lib \ - netapi32.lib + netapi32.lib DEFINES = VC_EXTRALEAN \ WIN32 \ _UNICODE \ @@ -126,57 +131,52 @@ win32 { CONFIG(debug, debug|release):DESTDIR = ../debug/ CONFIG(release, debug|release):DESTDIR = ../release/ } - QMAKE_CXXFLAGS_RELEASE += /Zi - QMAKE_LFLAGS_RELEASE += /DEBUG } -macx { + +macx { ICON = ../misc/Launchy_Icon/launchy_icon_mac.icns SOURCES += ../platforms/mac/platform_mac.cpp \ - ../platforms/mac/platform_mac_hotkey.cpp + ../platforms/mac/platform_mac_hotkey.cpp HEADERS += ../platforms/mac/platform_mac.h \ - ../platforms/mac/platform_mac_hotkey.h \ - platform_base_hotkey.h \ - platform_base_hottrigger.h - if(!debug_and_release|build_pass) { + ../platforms/mac/platform_mac_hotkey.h \ + platform_base_hotkey.h \ + platform_base_hottrigger.h + if(!debug_and_release|build_pass) { CONFIG(debug, debug|release):DESTDIR = ../debug/ CONFIG(release, debug|release):DESTDIR = ../release/ } INCLUDEPATH += /opt/local/include/ - LIBS += -framework \ - Carbon + LIBS += -framework Carbon + CONFIG(debug, debug|release):skins.path = ../debug/Launchy.app/Contents/Resources/skins/ CONFIG(release, debug|release):skins.path = ../release/Launchy.app/Contents/Resources/skins/ skins.files = - skins.extra = rsync -arvz ../skins/ ../release/Launchy.app/Contents/Resources/skins/ --exclude=\".svn\" + skins.extra = rsync -arvz ../skins/ ../release/Launchy.app/Contents/Resources/skins/ --exclude=\".svn\" + + + CONFIG(debug, debug|release):translations.path = ../debug/Launchy.app/Contents/MacOS/tr/ CONFIG(release, debug|release):translations.path = ../release/Launchy.app/Contents/MacOS/tr/ translations.files = ../translations/*.qm - translations.extra = lupdate \ - src.pro \ - ; \ - lrelease \ - src.pro + translations.extra = lupdate src.pro ; lrelease src.pro + dmg.path = ../release/ dmg.files = - dmg.extra = cd \ - ../mac \ - ; \ - bash \ - deploy; \ - cd \ - ../src - INSTALLS += skins \ - translations \ - dmg + dmg.extra = cd ../mac ; bash deploy; cd ../src + + INSTALLS += skins \ + translations \ + dmg } + TRANSLATIONS = ../translations/launchy_fr.ts \ ../translations/launchy_nl.ts \ ../translations/launchy_zh.ts \ ../translations/launchy_es.ts \ ../translations/launchy_de.ts \ ../translations/launchy_ja.ts \ - ../translations/launchy_zh_TW.ts \ - ../translations/launchy_rus.ts + ../translations/launchy_zh_TW.ts + OBJECTS_DIR = build MOC_DIR = build RESOURCES += launchy.qrc diff --git a/translations/launchy_de.ts b/translations/launchy_de.ts index 2692375..8f7a8b1 100644 --- a/translations/launchy_de.ts +++ b/translations/launchy_de.ts @@ -38,29 +38,29 @@ - + Launchy (press %1 to activate) - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - + Show Launchy - + Rebuild catalog - + Reload skin @@ -75,7 +75,7 @@ You can download it at <qt><a href="http://www.launchy.ne Die Tastenkombination wird bereits verwendet. Bitte wählen Sie ein Launchy's Einstellungen eine andere aus. - + A new version of Launchy is available Es ist eine neue Version von Launchy verfügbar @@ -93,12 +93,12 @@ herunterladen Katalog neu erstellen - + Options Einstellungen - + Exit Beenden @@ -150,240 +150,240 @@ herunterladen OptionsDialog + - Alt Alt - + Win Win + - Shift Umschaltung + - Control Steuerung - + Command - + Command+Alt - + Command+Shift - + Command+Control - + Ctrl+Alt - + Ctrl+Shift - + Ctrl+Win - + Space Leertaste - + Tab Tab - + Backspace Zurück - + Enter Enter - + Esc Esc - + Home Pos 1 - + End Ende - + Insert - + Delete - + Page Up - + Page Down - + Pause Pause - + Print Druck - + Scroll Lock - + Num Lock - + Up Auf - + Down Ab - + Left Links - + Right Rechts - + F1 F1 - + F2 F2 - + F3 F3 - + F4 F4 - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + F11 F11 - + F12 F12 - + F13 F13 - + F14 F14 - + F15 F15 - + Caps Lock - + Index has %n item(s) @@ -391,17 +391,17 @@ herunterladen - + This is Launchy version %1 - + The hotkey %1 is already in use, please select another. - + Plugin options Plugin Einstellungen @@ -426,7 +426,7 @@ herunterladen Dies ist Launchy Version - + Launchy Launchy @@ -435,8 +435,9 @@ herunterladen Die Tastenkombination wird bereits verwendet. Bitte wählen Sie eine andere Einstellung. + Select a directory - Ordner auswählen + Ordner auswählen @@ -695,7 +696,7 @@ herunterladen Versteckte Dateien im Browser Modus anzeigen - + Portable mode (USB stick) Portabler Modus (USB Stick) @@ -727,37 +728,37 @@ herunterladen - + Skins Skins - + Select a skin Skin auswählen - + Author information Autor Information - + Skin preview Skin Vorschau - + Catalog Katalog - + File Types Dateitypen - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -766,7 +767,7 @@ p, li { white-space: pre-wrap; } - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -778,34 +779,34 @@ p, li { white-space: pre-wrap; } - - + + + + - - + + - - - + Include executables Anwendungsdateien einschliessen - + Include directories Ordner einschliessen - + Depth: Tiefe: - + Directories Ordner @@ -886,11 +887,16 @@ p, li { white-space: pre-wrap; } + Allow wildcards in browse mode + + + + Check for new versions of Launchy on startup - + Rescan Catalog Katalog aktualisieren @@ -900,22 +906,22 @@ p, li { white-space: pre-wrap; } 0 Elemente indexieren - + Plugins Plugins - + Available plugins Verfügbare Plugins - + Plugin options Plugin Einstellungen - + About Launchy Über Launchy @@ -927,7 +933,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Bitte helfen Sein einem armen Studenten etwas vernünftiges auf den Tisch zu bekommen. Ich habe viel Spaß bei der Entwicklung von Launchy, und ich hoffe dass es Ihnen ebenfalls viel Freude macht damit zu arbeiten. Sie können Launchy kostenlos nutzen. Wenn Sie der Meinung sind, Launchy ist eine wertvolle Anwendung, würde ich mich über Ihre <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">Spende</span></a> freuen.</p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -938,12 +944,12 @@ p, li { white-space: pre-wrap; } SettingsManager - + Launchy Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. diff --git a/translations/launchy_es.ts b/translations/launchy_es.ts index 28564af..45734a0 100644 --- a/translations/launchy_es.ts +++ b/translations/launchy_es.ts @@ -38,29 +38,29 @@ - + Launchy (press %1 to activate) - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - + Show Launchy - + Rebuild catalog - + Reload skin @@ -75,7 +75,7 @@ You can download it at <qt><a href="http://www.launchy.ne Esa combinación de teclas ya se está utilizando. Por favor, escoje otra en las preferencias de Launchy. - + A new version of Launchy is available Hay una nueva versión de Launchy disponible @@ -92,12 +92,12 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu Reconstruir catálogo - + Options Opciones - + Exit Salir @@ -148,240 +148,240 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu OptionsDialog + - Alt Alt - + Win Win + - Shift Mayús + - Control Control - + Command - + Command+Alt - + Command+Shift - + Command+Control - + Ctrl+Alt - + Ctrl+Shift - + Ctrl+Win - + Space Espacio - + Tab Tab - + Backspace Retroceso - + Enter Intro - + Esc Esc - + Home Inicio - + End Fin - + Insert - + Delete - + Page Up - + Page Down - + Pause Pausa - + Print Imprimir - + Scroll Lock - + Num Lock - + Up Arriba - + Down Abajo - + Left Izquierda - + Right Derecha - + F1 F1 - + F2 F2 - + F3 F3 - + F4 F4 - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + F11 F11 - + F12 F12 - + F13 F13 - + F14 F14 - + F15 F15 - + Caps Lock - + Index has %n item(s) @@ -389,17 +389,17 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu - + This is Launchy version %1 - + The hotkey %1 is already in use, please select another. - + Plugin options Opciones del complemento @@ -424,7 +424,7 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu Esta versión de la Launchy es la - + Launchy Launchy @@ -433,8 +433,9 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu Esa combinación de teclas ya se está utilizando. Por favor, escoje otra. + Select a directory - Escoje un direcotorio + Escoje un direcotorio @@ -693,7 +694,7 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu Mostrar archivos ocultos en el modo de exploración - + Portable mode (USB stick) Modo portátil (lápiz USB) @@ -725,37 +726,37 @@ Puedes obtenerla en <qt><a href="http://www.launchy.net/&qu - + Skins Temas - + Select a skin Escoja un tema - + Author information Datos del autor - + Skin preview Vista previa del tema - + Catalog Catálogo - + File Types Tipos de archivo - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -764,7 +765,7 @@ p, li { white-space: pre-wrap; } - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -776,34 +777,34 @@ p, li { white-space: pre-wrap; } - - + + + + - - + + - - - + Include executables Incluir ejecutables - + Include directories Incluir directorios - + Depth: Profundidad: - + Directories Directorios @@ -884,11 +885,16 @@ p, li { white-space: pre-wrap; } + Allow wildcards in browse mode + + + + Check for new versions of Launchy on startup - + Rescan Catalog Reconstruir catálogo @@ -898,22 +904,22 @@ p, li { white-space: pre-wrap; } Indexando 0 elementos - + Plugins Complementos - + Available plugins Complementos disponibles - + Plugin options Opciones del complemento - + About Launchy Acerca de Launchy @@ -928,7 +934,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Por favor, ayuda a poner un plato de ramen en la mesa de este pobre estudiante de doctorado. Disfruto muchísimo desarrollando Launchy y espero que tú disfrutes utilizándolo. Aunque es gratis, si te resulta útil agredecería tu <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">donación.</span></a></p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -942,12 +948,12 @@ p, li { white-space: pre-wrap; } SettingsManager - + Launchy Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. diff --git a/translations/launchy_fr.ts b/translations/launchy_fr.ts index 36129a4..a05e62e 100644 --- a/translations/launchy_fr.ts +++ b/translations/launchy_fr.ts @@ -1,348 +1,345 @@ - + LaunchyWidget Launchy Options - Options de Launchy + Close Launchy - Quitter Launchy + The hotkey %1 is already in use, please select another. - Le raccourcis clavier %1 est déjà utilisé, veuillez en choisir un autre. + - + Launchy (press %1 to activate) - Launchy (appuyer sur %1 pour activer) + - + Show Launchy - Afficher Launchy + - + Rebuild catalog - Reconstruire le catalogue + Launchy - Launchy + - + A new version of Launchy is available - Une nouvelle version de Launchy est disponible + - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - Une nouvelle version de Launchy est disponible. - -Vous pouvez la charger depuis <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> + - + Reload skin - Recharger le skin + - + Options - Options + - + Exit - Quitter + OptionsDialog + - Alt - Alt + - + Win - Win + + - Shift - Shift + + - Control - Control + - + Command - Command + - + Command+Alt - Command+Alt + - + Command+Shift - Command+Shift + - + Command+Control - Command+Control + - + Ctrl+Alt - Ctrl+Alt + - + Ctrl+Shift - Ctrl+Shift + - + Ctrl+Win - Ctrl+Win + - + Space - Espace + - + Tab - Tab + - + Backspace - Backspace + - + Enter - Entrée + - + Esc - Echap + - + Home - Début + - + End - Fin + - + Insert - Insère + - + Delete - Efface + - + Page Up - Page haut + - + Page Down - Page bas + - + Pause - Pause + - + Print - Imprimer + - + Scroll Lock - Srcoll lock + - + Num Lock - Num Lock + - + Up - Haut + - + Down - Bas + - + Left - Gauche + - + Right - Droite + - + F1 - F1 + - + F2 - F2 + - + F3 - F3 + - + F4 - F4 + - + F5 - F5 + - + F6 - F6 + - + F7 - F7 + - + F8 - F8 + - + F9 - F9 + - + F10 - F10 + - + F11 - F11 + - + F12 - F12 + - + F13 - F13 + - + F14 - F14 + - + F15 - F15 + - + Caps Lock - Caps Lock + - + Index has %n item(s) - - L'index comprends %n élément(s) - L'index comprends %n élément(s) + + - + This is Launchy version %1 - Launchy version %1 + - + The hotkey %1 is already in use, please select another. - Le raccourcis clavier %1 est déjà utilisé, veuillez en choisir un autre. + - + Plugin options - Options des plugins + Index has %n items - - L'index comprends %n élément(s) - L'index comprends %n élément(s) + + - + Launchy - Launchy + + Select a directory - Choisissez un répertoire + @@ -350,147 +347,144 @@ Vous pouvez la charger depuis <qt><a href="http://www.lau Launchy options - Options de Launchy + General - Général + User Interface - Interface utilisateur + Always display Launchy window - Toujours &afficher la fenêtre Launchy + Hide Launchy when it loses focus - &Cacher Launchy quand il perd le focus + Always on top - Toujours &visible + Suggestion List - Liste de suggestion + Opaqueness - Opacité + Fade in time - Durée d'apparition + Fade out time - Durée de disparition + Show tray icon - Montrer l'&icone + Simultaneously visible suggestions - Nombre de suggestions &visibles + Maximum number of suggestions - Nombre &maximum de suggestions + Visual Effects - Effets visuels + System Options - Options système + Show hidden files in browse mode - Montrer les fichiers &cachés lors du parcours + - + Portable mode (USB stick) - Mode portable (Clef &USB) + Internet Proxy - Proxy &Internet + Hostname - Nom du serveur + Port - Port du proxy + - + Skins - St&yles + - + Select a skin - C&hoisissez un style + - + Author information - Information sur l'auteur + - + Skin preview - Prévisualisation + - + Catalog - Catalogue + - + File Types - Types de fichiers + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">I greatly enjoy developing Launchy, and I hope that you enjoy using it. It's free to use, but if you think Launchy is a worthwhile application, I would appreciate your </span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html>" - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">J'ai apprécié le développement de Launchy, et j'espère que vous aimerez l'utiliser. Il est libre d'usage, mais si vous pensez que Launchy est une application utile, j'apprecierai votre donation <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">I greatly enjoy developing Launchy, and I hope that you enjoy using it. It's free to use, but if you think Launchy is a worthwhile application, I would appreciate your </span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html> + - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -499,198 +493,180 @@ p, li { white-space: pre-wrap; } <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Creator and Developer: Josh Karlin</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Developer: Simon Capewell</span></p></body></html> - <!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;> -<html><head><meta name=&quot;qrichtext&quot; content=&quot;1&quot; /><style type=&quot;text/css&quot;> -p, li { white-space: pre-wrap; } -</style></head><body style=&quot; font-family:&apos;Verdana&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;> -<p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;><span style=&quot; font-size:8pt;&quot;>Credits :</span></p> -<p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;></p> -<p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;><span style=&quot; font-size:8pt;&quot;>Createur et Developeur: Josh Karlin</span></p> -<p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;><span style=&quot; font-size:8pt;&quot;>Developeur: Simon Capewell</span></p></body></html> + - - + + + - &Ajouter + - - + + - - &Enlever + - + Include executables - Inclure &exécutables + - + Include directories - Inclure &répertoires + - + Depth: - &Profondeur: + - + Directories - Répertoires + Underline matched text - &Souligner le texte trouvé + Always center Launchy - Toujours centrer Launchy + horizontally - &horizontalement + vertically - &verticalement + Only allow dragging whilst Shift is pressed - N'autoriser le &dragging que lorsque Maj est pressé + &Hotkey: - &Raccourcis: + ms - ms + Auto open delay - &Délais d'ouverture + Maximum number of history items - Nombre maximum d'élements dans l'&historique + Name and path - &Nom et répertoire + Path only - &Répertoire seul + Name only - No&m seul + Suggestions display - &Affichage des suggestions + Auto update catalog every - Mettre à &jour le catalogue toutes les + minutes - minutes + Show network in browse mode - Montrer le &réseau lors du parcours + + Allow wildcards in browse mode - &Autoriser les jokers lors du parcours + - + Check for new versions of Launchy on startup - Vérifier les nouvelles &versions de Launchy au démarrage + - + Rescan Catalog - Reconstruire le &catalogue + Indexing 0 items - L'index comprends %n élément(s) + - + Plugins - Plugins + - + Available plugins - Liste des plugins + - + Plugin options - Options du plugin + - + About Launchy - A propos de Launchy - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">I greatly enjoy developing Launchy, and I hope that you enjoy using it. It's free to use, but if you think Launchy is a worthwhile application, I would appreciate your </span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Launchy's official homepage is <a href="http://www.launchy.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.launchy.net/</span></a></p></body></html> - <html><head><meta name=&quot;qrichtext&quot; content=&quot;1&quot; /><style type=&quot;text/css&quot;> -p, li { white-space: pre-wrap; } -</style></head><body style=&quot; font-family:&apos;Verdana&apos;; font-size:8.25pt; font-weight:400; font-style:normal;&quot;> -<p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;>Page officielle de Launchy <a href=&quot;http://www.launchy.net/&quot;><span style=&quot; text-decoration: underline; color:#0000ff;&quot;>http://www.launchy.net/</span></a></p></body></html> + SettingsManager - + Launchy - Launchy + - + Could not convert to portable mode. Please check you have write access to the %1 directory. - Impossible de convertir en mode portable. Veuillez vérifier que vous avez les droits d'écriture dans le répertoire %1. + diff --git a/translations/launchy_ja.ts b/translations/launchy_ja.ts index a2477ff..e678ada 100644 --- a/translations/launchy_ja.ts +++ b/translations/launchy_ja.ts @@ -38,29 +38,29 @@ - + Launchy (press %1 to activate) - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - + Show Launchy - + Rebuild catalog - + Reload skin @@ -75,7 +75,7 @@ You can download it at <qt><a href="http://www.launchy.ne 選択されたホットキーは既に使われています。Launchy のオプションで他のキーを指定して下さい。 - + A new version of Launchy is available 新しいバージョンのLaunchyが使用可能です。 @@ -92,12 +92,12 @@ You can download it at <qt><a href="http://www.launchy.net/ カタログを再構築 - + Options オプション - + Exit 終了 @@ -148,257 +148,257 @@ You can download it at <qt><a href="http://www.launchy.net/ OptionsDialog + - Alt Alt - + Win Win + - Shift Shift + - Control Control - + Command - + Command+Alt - + Command+Shift - + Command+Control - + Ctrl+Alt - + Ctrl+Shift - + Ctrl+Win - + Space Space - + Tab Tab - + Backspace Backspace - + Enter Enter - + Esc Esc - + Home Home - + End End - + Insert - + Delete - + Page Up - + Page Down - + Pause Pause - + Print Print - + Scroll Lock - + Num Lock - + Up Up - + Down Down - + Left Left - + Right Right - + F1 F1 - + F2 F2 - + F3 F3 - + F4 F4 - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + F11 F11 - + F12 F12 - + F13 F13 - + F14 F14 - + F15 F15 - + Caps Lock - + Index has %n item(s) - + This is Launchy version %1 - + The hotkey %1 is already in use, please select another. - + Plugin options プラグイン・オプション @@ -422,7 +422,7 @@ You can download it at <qt><a href="http://www.launchy.net/ Launchy のバージョン: - + Launchy Launchy @@ -431,8 +431,9 @@ You can download it at <qt><a href="http://www.launchy.net/ 選択されたホットキーは既に使われています。他のキーを選択して下さい。 + Select a directory - ディレクトリを選択してください + ディレクトリを選択してください @@ -691,7 +692,7 @@ You can download it at <qt><a href="http://www.launchy.net/ ブラウズ・モードで隠しファイルも表示する - + Portable mode (USB stick) ポータブル・モード(USBメモリ) @@ -723,37 +724,37 @@ You can download it at <qt><a href="http://www.launchy.net/ - + Skins スキン - + Select a skin スキンを選んで下さい - + Author information 作者の情報 - + Skin preview プレビュー - + Catalog カタログ - + File Types ファイルの種類 - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -762,7 +763,7 @@ p, li { white-space: pre-wrap; } - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -774,34 +775,34 @@ p, li { white-space: pre-wrap; } - - + + + + - - + + - - - + Include executables 実行可能ファイルも含む - + Include directories ディレクトリも含む - + Depth: 階層指定: - + Directories ディレクトリ @@ -882,11 +883,16 @@ p, li { white-space: pre-wrap; } + Allow wildcards in browse mode + + + + Check for new versions of Launchy on startup - + Rescan Catalog カタログを再スキャン @@ -896,22 +902,22 @@ p, li { white-space: pre-wrap; } 0 項目をインデックス化しています - + Plugins プラグイン - + Available plugins 利用可能なプラグイン - + Plugin options プラグイン・オプション - + About Launchy Launchy について @@ -923,7 +929,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Please help this poor grad student to put ramen on the table. I greatly enjoy developing Launchy, and I hope that you enjoy using it. It's free to use, but if you think Launchy is a worthwhile application, I would appreciate your <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -934,12 +940,12 @@ p, li { white-space: pre-wrap; } SettingsManager - + Launchy Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. diff --git a/translations/launchy_nl.ts b/translations/launchy_nl.ts index 47f4c5a..a05e62e 100644 --- a/translations/launchy_nl.ts +++ b/translations/launchy_nl.ts @@ -19,17 +19,17 @@ - + Launchy (press %1 to activate) - + Show Launchy - + Rebuild catalog @@ -40,29 +40,29 @@ - + A new version of Launchy is available - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - + Reload skin - + Options - + Exit @@ -70,257 +70,257 @@ You can download it at <qt><a href="http://www.launchy.ne OptionsDialog + - Alt - + Win + - Shift + - Control - + Command - + Command+Alt - + Command+Shift - + Command+Control - + Ctrl+Alt - + Ctrl+Shift - + Ctrl+Win - + Space - + Tab - + Backspace - + Enter - + Esc - + Home - + End - + Insert - + Delete - + Page Up - + Page Down - + Pause - + Print - + Scroll Lock - + Num Lock - + Up - + Down - + Left - + Right - + F1 - + F2 - + F3 - + F4 - + F5 - + F6 - + F7 - + F8 - + F9 - + F10 - + F11 - + F12 - + F13 - + F14 - + F15 - + Caps Lock - + Index has %n item(s) - + This is Launchy version %1 - + The hotkey %1 is already in use, please select another. - + Plugin options @@ -332,10 +332,15 @@ You can download it at <qt><a href="http://www.launchy.ne - + Launchy + + + Select a directory + + OptionsDlg @@ -420,7 +425,7 @@ You can download it at <qt><a href="http://www.launchy.ne - + Portable mode (USB stick) @@ -440,37 +445,37 @@ You can download it at <qt><a href="http://www.launchy.ne - + Skins - + Select a skin - + Author information - + Skin preview - + Catalog - + File Types - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -479,7 +484,7 @@ p, li { white-space: pre-wrap; } - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -491,34 +496,34 @@ p, li { white-space: pre-wrap; } - - + + + - - + + - - + Include executables - + Include directories - + Depth: - + Directories @@ -604,11 +609,16 @@ p, li { white-space: pre-wrap; } + Allow wildcards in browse mode + + + + Check for new versions of Launchy on startup - + Rescan Catalog @@ -618,27 +628,27 @@ p, li { white-space: pre-wrap; } - + Plugins - + Available plugins - + Plugin options - + About Launchy - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -649,12 +659,12 @@ p, li { white-space: pre-wrap; } SettingsManager - + Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. diff --git a/translations/launchy_zh.ts b/translations/launchy_zh.ts index acbb567..8f95ee0 100644 --- a/translations/launchy_zh.ts +++ b/translations/launchy_zh.ts @@ -1,6 +1,6 @@ - + @@ -25,61 +25,59 @@ Launchy Options - Launchy 选项 + Launchy 选项 Close Launchy - 关闭 Launchy + 关闭 Launchy The hotkey %1 is already in use, please select another. - 热键 %1 已经被占用了,请选择另外一个热键. + - + Launchy (press %1 to activate) - Launchy (按 %1 激活) + - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - Launchy 有新版本了! - -请到这里下载: <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> + - + Show Launchy - 显示Launchy + - + Rebuild catalog - 重建索引数据 + - + Reload skin - 重新载入皮肤 + Launchy - + Launchy The hotkey you have chosen is already in use. Please select another from Launchy's preferences. 你选择的快捷键已经被占用, 请选择其他的快捷键. - + A new version of Launchy is available - Launchy 有新版本了! + Launchy 有新版本了! A new version of Launchy is available. @@ -91,17 +89,17 @@ You can download it at <qt><a href="http://www.launchy.net/ Rebuild Catalog - 重建索引数据 + 重新建立索引 - + Options - 选项 + 选项 - + Exit - 退出 + 退出 @@ -114,6 +112,10 @@ You can download it at <qt><a href="http://www.launchy.net/ Close Launchy 关闭 Launchy + + Launchy + Launchy + The hotkey you have chosen is already in use. Please select another from Launchy's preferences. 你选择的快捷键已经被占用, 请选择其他的快捷键. @@ -146,264 +148,264 @@ You can download it at <qt><a href="http://www.launchy.net/ OptionsDialog + - Alt - + Win + - Shift + - Control - + Command - + Command+Alt - + Command+Shift - + Command+Control - + Ctrl+Alt - + Ctrl+Shift - + Ctrl+Win - + Space - + Tab - + Backspace - + Enter - + Esc - + Home - + End - + Insert - + Delete - + Page Up - + Page Down - + Pause - + Print - + Scroll Lock - + Num Lock - + Up - + Down - + Left - + Right - + F1 - + F2 - + F3 - + F4 - + F5 - + F6 - + F7 - + F8 - + F9 - + F10 - + F11 - + F12 - + F13 - + F14 - + F15 - + Caps Lock - + Index has %n item(s) - + - + This is Launchy version %1 - Launchy 版本 + - + The hotkey %1 is already in use, please select another. - 你选择的%1已经被占用, 请选择其他的快捷键. + - + Plugin options - 插件选项 + 插件选项 Index has %n items - + @@ -412,17 +414,18 @@ You can download it at <qt><a href="http://www.launchy.net/ 索引有 - + Launchy - + Launchy The hotkey you have chosen is already in use, please select another. 你选择的快捷键已经被占用, 请选择其他的快捷键. + Select a directory - 选择一个目录 + 选择一个目录 @@ -472,17 +475,17 @@ You can download it at <qt><a href="http://www.launchy.net/ Show tray icon - 显示系统托盘图标 + Suggestion List - 备选列表 + Always center Launchy - 总是居中显示 + 总是居中显示 Hotkey: @@ -509,26 +512,26 @@ You can download it at <qt><a href="http://www.launchy.net/ Simultaneously visible alternate suggestions - 一次显示备选列表数 + 一次显示建议列表的数目 Max. number of alternate suggestions - 备选列表最大显示数 + 最多显示建议列表的数目 Simultaneously visible suggestions - 同时可见备选列表数 + Maximum number of suggestions - 最多备选列表数 + Visual Effects - 视觉效果 + @@ -537,7 +540,7 @@ You can download it at <qt><a href="http://www.launchy.net/ Check for updates on startup - 启动的检查是否有新版本 + 启动的时候检测是否有新版本 @@ -545,13 +548,13 @@ You can download it at <qt><a href="http://www.launchy.net/ 显示隐藏的文件 - + Portable mode (USB stick) - 绿色软件模式 + 移动模式(貌似可放到U盘中方便使用) Use testing indexer? - 使用测试版的索引功能? + 使用测试版的索引? Minutes between catalog updates @@ -564,63 +567,59 @@ You can download it at <qt><a href="http://www.launchy.net/ Internet Proxy - 代理服务器 + Hostname - 主机名 + Port - 端口 + - + Skins 皮肤 - + Select a skin 选择皮肤 - + Author information 作者信息 - + Skin preview 预览皮肤 - + Catalog 目录 - + File Types 文件类型 - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">I greatly enjoy developing Launchy, and I hope that you enjoy using it. It's free to use, but if you think Launchy is a worthwhile application, I would appreciate your </span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">donation.</span></a></p></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">我很高兴能开发Launchy, 也希望你能喜欢它. Launchy是完全免费的, 如果你觉得这个程序真不错,请给予我们一定的</span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">捐助.</span></a></p></body></html> + - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -629,133 +628,127 @@ p, li { white-space: pre-wrap; } <p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Creator and Developer: Josh Karlin</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Developer: Simon Capewell</span></p></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Credits</span></p> -<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">作者: Josh Karlin</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">后续作者: Simon Capewell</span></p></body></html> + - - + + + - + - - + + - - + - + Include executables 包含可执行文件 - + Include directories 包含目录 - + Depth: 深度: - + Directories 目录 Underline matched text - 匹配文字时下划线 + horizontally - 水平 + vertically - 垂直 + Only allow dragging whilst Shift is pressed - 只允许按下Shift键时进行拖放 + &Hotkey: - 呼出热键 + ms - 毫秒 + Auto open delay - 自动打开延迟 + Maximum number of history items - 历史记录最大显示数 + Name and path - 名字和路径 + Path only - 只有路径 + Name only - 只有名字 + Suggestions display - 显示备选项目 + Auto update catalog every - 索引自动更新时间 + minutes - 分钟 + Show network in browse mode - 浏览模式里显示网络 + + Allow wildcards in browse mode - 浏览模式里允许使用通配符 + - + Check for new versions of Launchy on startup - 启动时检查是否有新版本 + - + Rescan Catalog 扫描目录 @@ -765,22 +758,22 @@ p, li { white-space: pre-wrap; } 已找到 0 项 - + Plugins 插件 - + Available plugins 有效的插件 - + Plugin options 插件选项 - + About Launchy 关于 @@ -792,25 +785,25 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:11pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">原作者语:我很高兴开发Launchy,希望你能喜欢它。你可以免费使用,如果你觉得Launchy不错,我期待你的 <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">赞助.</span></a></p>拼音处理方案采用李先静的 <a href="http://sourceforge.net/projects/pinyin-kit/"><span style=" text-decoration: underline; color:#0000ff;">pinyin-kit</span></a> 谢谢</p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Launchy's official homepage is <a href="http://www.launchy.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.launchy.net/</span></a></p></body></html> - <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;">Launchy 官方网站:<a href="http://www.launchy.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.launchy.net/</span></a></p><br/><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;">Launchy 汉化版 业余汉化 有问题联系 <a href="mailto:siknet@gmail.com"><span style=" text-decoration: underline; color:#0000ff;">重庆森林</span></a></p></body></html> + <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;">Launchy's official homepage is <a href="http://www.launchy.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.launchy.net/</span></a></p><br/><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;">Launchy中文修改版 欢迎来我的blog讨论 <a href="http://bborn.cn/blog"><span style=" text-decoration: underline; color:#0000ff;">http://bborn.cn/blog/</span></a></p></body></html> SettingsManager - + Launchy - + Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. - 无法转换为绿色软件模式,请检查在%1目录中是否有写入的权限. + diff --git a/translations/launchy_zh_TW.ts b/translations/launchy_zh_TW.ts index 5b1fe14..7b6cf21 100644 --- a/translations/launchy_zh_TW.ts +++ b/translations/launchy_zh_TW.ts @@ -38,12 +38,12 @@ 快速鍵 %1 已經被使用,請選擇另一個。 - + Launchy (press %1 to activate) Launchy (按 %1 啟動) - + A new version of Launchy is available. You can download it at <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> @@ -52,17 +52,17 @@ You can download it at <qt><a href="http://www.launchy.ne 你可以到這裡下載 <qt><a href="http://www.launchy.net/">http://www.launchy.net</a></qt> - + Show Launchy 顯示 Launchy - + Rebuild catalog 重新建立索引 - + Reload skin 重新載入面板 @@ -77,7 +77,7 @@ You can download it at <qt><a href="http://www.launchy.ne 你選擇的快捷鍵已經被占用, 請選擇其他的快捷鍵. - + A new version of Launchy is available Launchy 有新版本 @@ -94,12 +94,12 @@ You can download it at <qt><a href="http://www.launchy.net/ 重新建立索引 - + Options 選項 - + Exit 離開 @@ -150,257 +150,257 @@ You can download it at <qt><a href="http://www.launchy.net/ OptionsDialog + - Alt Alt - + Win Win + - Shift Shift + - Control Control - + Command Command - + Command+Alt Command+Alt - + Command+Shift Command+Shift - + Command+Control Command+Control - + Ctrl+Alt Ctrl+Alt - + Ctrl+Shift Ctrl+Shift - + Ctrl+Win Ctrl+Win - + Space - Space + 空白鍵 - + Tab Tab - + Backspace Backspace - + Enter Enter - + Esc Esc - + Home Home - + End End - + Insert - Insert + - + Delete - Delete + - + Page Up - Page Up + - + Page Down - Page Down + - + Pause Pause - + Print Print - + Scroll Lock - Scroll Lock + - + Num Lock - Num Lock + - + Up - + Down - + Left - + Right - + F1 F1 - + F2 F2 - + F3 F3 - + F4 F4 - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + F11 F11 - + F12 F12 - + F13 F13 - + F14 F14 - + F15 F15 - + Caps Lock Caps Lock - + Index has %n item(s) 索引了 %n 個項目 - + This is Launchy version %1 Launchy version %1 - + The hotkey %1 is already in use, please select another. 快速鍵 %1 已經被使用,請選擇另一個。 - + Plugin options 外掛程式選項 @@ -416,7 +416,7 @@ You can download it at <qt><a href="http://www.launchy.net/ 索引有 - + Launchy Launchy @@ -425,8 +425,9 @@ You can download it at <qt><a href="http://www.launchy.net/ 你選擇的快捷鍵已經被占用, 請選擇其他的快捷鍵. + Select a directory - 選擇一個目錄 + 選擇一個目錄 @@ -549,7 +550,7 @@ You can download it at <qt><a href="http://www.launchy.net/ 在瀏覽模式下顯示隱藏的文件 - + Portable mode (USB stick) 可攜模式 (可以放到 USB 隨身碟) @@ -581,37 +582,37 @@ You can download it at <qt><a href="http://www.launchy.net/ Port - + Skins 面板 - + Select a skin 選擇面板 - + Author information 作者資訊 - + Skin preview 預覽面板 - + Catalog 目錄 - + File Types 檔案類型 - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -624,7 +625,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">我很喜歡開發 Launchy,希望你也會喜歡它。它是免費的,但如果你認為 Launchy 值得,我會感謝你的</span><a href="http://www.launchy.net/#donate"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">捐款</span></a>。</p></body></html> - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -643,34 +644,34 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">開發者: Simon Capewell</span></p></body></html> - - + + + + - - + + - - - + Include executables 包含可執行檔 - + Include directories 包含目錄 - + Depth: 深度: - + Directories 目錄 @@ -747,19 +748,20 @@ p, li { white-space: pre-wrap; } Show network in browse mode - 在瀏覽模式下顯示網路 + 在瀏覽模式顯示網路 + Allow wildcards in browse mode - 在瀏覽模式下使用wildcards + - + Check for new versions of Launchy on startup 啟動時檢查新版本 - + Rescan Catalog 重新建立索引 @@ -769,22 +771,22 @@ p, li { white-space: pre-wrap; } 找到 0 個項目 - + Plugins 外掛程式 - + Available plugins 可用的外掛程式 - + Plugin options 外掛程式選項 - + About Launchy 關於 Launchy @@ -796,7 +798,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Verdana'; font-size:11pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">原作者語:我很高興開發Launchy,希望你能喜歡它。你可以免費使用,如果你覺得Launchy不錯,我期待你的 <a href="http://www.launchy.net/#donate"><span style=" text-decoration: underline; color:#0000ff;">贊助.</span></a></p>拼音處理方案采用李先靜的 <a href="http://sourceforge.net/projects/pinyin-kit/"><span style=" text-decoration: underline; color:#0000ff;">pinyin-kit</span></a> 謝謝</p></body></html> - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Verdana'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -810,14 +812,14 @@ p, li { white-space: pre-wrap; } SettingsManager - + Launchy - Launchy + Launchy - + Could not convert to portable mode. Please check you have write access to the %1 directory. - 無法轉換到可攜模式。請確定你有寫入 %1 目錄的權限。 + diff --git a/win/Microsoft.VC90.CRT.manifest b/win/Microsoft.VC90.CRT.manifest new file mode 100644 index 0000000..d3a615b --- /dev/null +++ b/win/Microsoft.VC90.CRT.manifest @@ -0,0 +1,13 @@ + + + + + + + diff --git a/win/installer/SETUP.iss b/win/installer/SETUP.iss index 439e4d9..0e7e257 100644 --- a/win/installer/SETUP.iss +++ b/win/installer/SETUP.iss @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "Launchy" -#define MyAppVerName "Launchy 2.5.1 Beta 2" +#define MyAppVerName "Launchy 2.5 Beta 3" #define MyAppPublisher "Code Jelly" #define MyAppURL "http://www.launchy.net" #define MyAppExeName "Launchy.exe" @@ -62,24 +62,15 @@ Source: ..\..\translations\launchy_zh.qm; DestDir: {app}\tr\; Flags: ignoreversi ; Libs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files -Source: ..\msvcp80.dll; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\msvcr80.dll; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\Microsoft.VC80.CRT.manifest; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 Source: ..\..\release\QtCore4.dll; DestDir: {app}; Flags: ignoreversion Source: ..\..\release\QtGui4.dll; DestDir: {app}; Flags: ignoreversion Source: ..\..\release\QtNetwork4.dll; DestDir: {app}; Flags: ignoreversion - -Source: ..\msvcp80.dll; DestDir: {app}\imageformats\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\msvcr80.dll; DestDir: {app}\imageformats\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\Microsoft.VC80.CRT.manifest; DestDir: {app}\imageformats\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 Source: ..\..\release\imageformats\qmng4.dll; DestDir: {app}\imageformats; Flags: ignoreversion +Source: ..\msvcp80.dll; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion +Source: ..\msvcr80.dll; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion +Source: ..\Microsoft.VC80.CRT.manifest; DestDir: {app}\Microsoft.VC80.CRT\; Flags: ignoreversion ; Plugins -; plugins may require all 3 runtimes -Source: ..\msvcp80.dll; DestDir: {app}\plugins\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\msvcr80.dll; DestDir: {app}\plugins\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\msvcp80.dll; DestDir: {app}\plugins\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 -Source: ..\Microsoft.VC80.CRT.manifest; DestDir: {app}\plugins\Microsoft.VC80.CRT\; Flags: ignoreversion; OnlyBelowVersion: 0, 6.0 Source: ..\..\release\plugins\controly.dll; DestDir: {app}\plugins\; Flags: ignoreversion Source: ..\..\release\plugins\calcy.dll; DestDir: {app}\plugins\; Flags: ignoreversion Source: ..\..\release\plugins\gcalc.dll; DestDir: {app}\plugins\; Flags: ignoreversion @@ -260,3 +251,6 @@ begin Result := true; end; end; + + + diff --git a/win/msvcm90.dll b/win/msvcm90.dll new file mode 100644 index 0000000..45fdb91 Binary files /dev/null and b/win/msvcm90.dll differ diff --git a/win/msvcp90.dll b/win/msvcp90.dll new file mode 100644 index 0000000..6b07c75 Binary files /dev/null and b/win/msvcp90.dll differ diff --git a/win/msvcr90.dll b/win/msvcr90.dll new file mode 100644 index 0000000..a68249a Binary files /dev/null and b/win/msvcr90.dll differ