]> gitweb.hamatoma.de Git - reqt/commitdiff
Context menu, win32 support
authorhama <hama@siduction.net>
Fri, 1 May 2015 23:10:01 +0000 (01:10 +0200)
committerhama <hama@siduction.net>
Fri, 1 May 2015 23:10:01 +0000 (01:10 +0200)
appl/refind/filefinder.cpp
appl/refind/mainwindow.cpp
appl/refind/mainwindow.hpp
appl/refind/mainwindow.ui
appl/refind/refind.pro
base/ReQStringUtil.cpp
base/ReQStringUtil.hpp
gui/ReGuiValidator.cpp

index 0024ac939ba627dabf7c40544e42cfdb80ff36e3..bc21de72f593344d76cbcddfecea2e93189a3fef 100644 (file)
@@ -111,7 +111,8 @@ void FileFinder::fillTable(const QString& path, int depth, QTableWidget* table,
    else
       entries = dir.entryInfoList(m_patterns, filters, QDir::NoSort);
    QList <QFileInfo>::iterator it;
-   QString relativePath = path.mid(1 + m_baseDir.length());
+   QString relativePath = ReQStringUtil::nativePath(
+               path.mid(1 + m_baseDir.length()));
    QString node, ext;
 
    for (it = entries.begin(); it != entries.end(); ++it){
index 7c6b74520b101cddda10c62abe402078014b0f90..ccf3ecff8d2a035605f623a7887fd549ddb5fac1 100644 (file)
@@ -16,6 +16,7 @@
 #include <QMouseEvent>
 #include <QDrag>
 #include <QMimeData>
+#include <QProcess>
 #include "base/rebase.hpp"
 #include "gui/regui.hpp"
 #include "textfinder.hpp"
@@ -42,7 +43,9 @@ MainWindow::MainWindow(const QString& startDir, const QString& homeDir,
             m_horizontalHeader(NULL),
             m_lastOrder(Qt::DescendingOrder),
             m_homeDir(),
-            m_storageFile(){
+            m_storageFile(),
+            m_fileHandler(),
+            m_dirHandler(){
    ui->setupUi(this);
    initializeHome();
    m_statusMessage = new QLabel(tr("Willkommen bei refind"));
@@ -90,7 +93,37 @@ MainWindow::MainWindow(const QString& startDir, const QString& homeDir,
    ui->tableWidget->setColumnWidth(TC_SIZE, 125);
    ui->tableWidget->setColumnWidth(TC_MODIFIED, 175);
    ui->tableWidget->setColumnWidth(TC_TYPE, 75);
-   ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
+   addContextMenu();
+}
+
+/**
+ * @brief Destructor.
+ */
+MainWindow::~MainWindow(){
+   delete ui;
+}
+
+/**
+ * Prepares the context menu of the result table.
+ *
+ */
+void MainWindow::addContextMenu(){
+    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(ui->tableWidget,
+            SIGNAL(customContextMenuRequested(const QPoint&)),
+            SLOT(handleTableContextMenu(const QPoint&)));
+    ContextHandler* handler = new ContextHandler();
+    handler->m_text = "kedit";
+    handler->m_program = "kedit";
+    handler->m_arguments = "${full}";
+    handler->m_changeToParentDirectory = ContextHandler::DM_UNDEF;
+    m_fileHandler.append(handler);
+    handler = new ContextHandler();
+    handler->m_text = "bash";
+    handler->m_program = "konsole";
+    handler->m_arguments = "${full}";
+    handler->m_changeToParentDirectory = ContextHandler::DM_TO_FILE;
+    m_dirHandler.append(handler);
 }
 
 void MainWindow::mousePressEvent(QMouseEvent* event)
@@ -154,13 +187,6 @@ void MainWindow::preview(){
    exportToStream(stream, 1);
 }
 
-/**
- * @brief Destructor.
- */
-MainWindow::~MainWindow(){
-   delete ui;
-}
-
 /**
  * Starts the about dialog.
  */
@@ -324,54 +350,37 @@ void MainWindow::exportFiles(){
  * @param maxRow    -1 or the maximum row to export
  */
 void MainWindow::exportToStream(QTextStream& stream, int maxRow){
+    QHash<QString, QString> placeholders;
+    buildGlobalPlaceholders(placeholders);
    if (!ui->comboBoxHeader->currentText().isEmpty()){
-      stream << replaceGlobalPlaceholder(ui->comboBoxHeader->currentText())
+      stream << replaceGlobalPlaceholders(ui->comboBoxHeader, placeholders)
          << endl;
    }
    int count = ui->tableWidget->rowCount();
    if (count > 0 && maxRow > 0)
       count = maxRow;
+   QString error;
    for (int ii = 0; ii < count; ii++){
       QString line = ui->comboBoxTemplate->currentText();
-      int start = 0;
-      QString replacement;
-      QString name;
-      while (start >= 0){
-         start = line.indexOf("${", start);
-         if (start < 0)
-            break;
-         int end = line.indexOf('}', start + 1);
-         if (end < 0)
-            break;
-         name = line.mid(start + 2, end - start - 2);
-         if (name == "full"){
-            QString path = ui->tableWidget->item(ii, TC_PATH)->text();
-            if (path.isEmpty())
-               path = ui->tableWidget->item(ii, TC_NODE)->text();
-            else
-               path += ui->tableWidget->item(ii, TC_NODE)->text();
-            replacement = m_lastBaseDir.absoluteFilePath(path);
-         }else if (name == "path")
-            replacement = ui->tableWidget->item(ii, TC_PATH)->text();
-         else if (name == "ext")
-            replacement = ui->tableWidget->item(ii, TC_EXT)->text();
-         else if (name == "node")
-            replacement = ui->tableWidget->item(ii, TC_NODE)->text();
-         else if (name == "modified")
-            replacement = ui->tableWidget->item(ii, TC_MODIFIED)->text();
-         else if (name == "size")
-            replacement = ui->tableWidget->item(ii, TC_SIZE)->text();
-         else{
-            guiError(ui->comboBoxTemplate, tr("unknown placeholder: ") + name);
-            break;
-         }
-         line = line.replace("${" + name + "}", replacement);
-         start += replacement.length();
+      QHash<QString, QString> placeholders;
+      QString path = m_lastBaseDir.absoluteFilePath(
+                  ReQStringUtil::pathAppend(
+                  ui->tableWidget->item(ii, TC_PATH)->text(),
+                  ui->tableWidget->item(ii, TC_NODE)->text()));
+      placeholders.insert("full", ReQStringUtil::nativePath(path));
+      placeholders.insert("path", ui->tableWidget->item(ii, TC_PATH)->text());
+      placeholders.insert("ext", ui->tableWidget->item(ii, TC_EXT)->text());
+      placeholders.insert("node", ui->tableWidget->item(ii, TC_NODE)->text());
+      placeholders.insert("modified", ui->tableWidget->item(ii, TC_MODIFIED)->text());
+      placeholders.insert("size", ui->tableWidget->item(ii, TC_SIZE)->text());
+      if (! ReQStringUtil::replacePlaceholders(line, placeholders, &error)){
+          guiError(ui->comboBoxTemplate, error);
+          break;
       }
       stream << replaceEscSequences(line) << endl;
    }
    if (!ui->comboBoxFooter->currentText().isEmpty()){
-      stream << replaceGlobalPlaceholder(ui->comboBoxFooter->currentText())
+      stream << replaceGlobalPlaceholders(ui->comboBoxFooter, placeholders)
          << endl;
    }
 }
@@ -420,6 +429,73 @@ void MainWindow::handlePlaceholder(QComboBox* target){
       target->setCurrentText(target->currentText() + dialog.var());
 }
 
+/**
+ * Handles the request of a context menu of the result table.
+ *
+ * @param position  the position of a mouse click
+ */
+void MainWindow::handleTableContextMenu(const QPoint& position){
+    int row = ui->tableWidget->rowAt(position.y());
+    if (row >= 0){
+        QMenu menu;
+
+        QString node = ui->tableWidget->item(row, TC_NODE)->text();
+        QString parent = buildAbsPath(row);
+        QString full = ReQStringUtil::pathAppend(parent, node);
+        QFileInfo file(full);
+        QList<ContextHandler*>& list = file.isDir() ? m_dirHandler : m_fileHandler;
+        QList<ContextHandler*>::const_iterator it;
+        QHash<QAction*, ContextHandler*> actions;
+        ContextHandler* handler;
+        for (it = list.begin(); it != list.end(); ++it){
+            handler = *it;
+            QString text = handler->m_text + " " + node;
+            actions.insert(menu.addAction(text), handler);
+        }
+        QAction* selectedItem = menu.exec(ui->tableWidget->viewport()->mapToGlobal(position));
+        if (selectedItem != NULL)
+        {
+            handler = *actions.find(selectedItem);
+            QString arguments = handler->m_arguments;
+            QString dir;
+            switch(handler->m_changeToParentDirectory){
+            case ContextHandler::DM_TO_PARENT:
+                dir = parent;
+                break;
+            case ContextHandler::DM_TO_FILE:
+                dir = full;
+                break;
+            default:
+                dir = ui->comboBoxDirectory->currentText();
+                break;
+            }
+            QMap<QString, QString> placeholders;
+            placeholders.insert("full", full);
+            placeholders.insert("node", node);
+            placeholders.insert("path", parent);
+            placeholders.insert("ext", ReQStringUtil::extensionOf(node));
+            QString error;
+            QStringList args = arguments.split(' ');
+            bool hasErrors = false;
+            for (int ix = 0; ix < args.size(); ix++){
+                QString arg = args.at(ix);
+                if (! ReQStringUtil::replacePlaceholders(arg, placeholders, &error)){
+                    guiError(NULL, error);
+                    hasErrors = true;
+                    break;
+                }
+                args.replace(ix, arg);
+            }
+            if (! hasErrors){
+                QProcess::startDetached(handler->m_program, args, dir, NULL);
+                setStatusMessage(false, "call of " + handler->m_program + " "
+                             + arguments);
+            }
+        }
+
+    }
+}
+
 /**
  * Handles the push of "select placeholder for the header".
  */
@@ -440,52 +516,31 @@ void MainWindow::prepareTextFind(){
    }
 }
 
+void MainWindow::buildGlobalPlaceholders(QHash<QString, QString>& hash){
+
+    hash.insert("filepatterns", ui->comboBoxFilePatterns->currentText());
+    hash.insert("base", m_lastBaseDir.absolutePath());
+    hash.insert("textpattern", ui->comboBoxTextPattern->currentText());
+    hash.insert("dirs", QString::number(m_statistics.m_dirs));
+    hash.insert("files", QString::number(m_statistics.m_files));
+    hash.insert("runtime", QString::number(m_statistics.m_runtimeSeconds, 'g', 3));
+    hash.insert("bytes", QString::number(m_statistics.m_bytes));
+    hash.insert("megabytes", QString::number((double) m_statistics.m_bytes / 1000000));
+    hash.insert("datetime", QDateTime::currentDateTime().toLocalTime().toString(
+          "yyyy.MM.dd/hh:mm:ss"));
+}
 /**
  * Replaces placeholders valid in header and footer.
  *
  * @param text  the text to convert
  * @return      <code>text</code> with the esc sequences replaced
  */
-QString MainWindow::replaceGlobalPlaceholder(const QString& text){
-   int start = 0;
-   QString replacement;
-   QString name;
-   QString rc = text;
-   while (start >= 0){
-      start = rc.indexOf("${", start);
-      if (start < 0)
-         break;
-      int end = rc.indexOf('}', start + 1);
-      if (end < 0)
-         break;
-      name = rc.mid(start + 2, end - start - 2);
-      if (name == "filepatterns")
-         replacement = ui->comboBoxFilePatterns->currentText();
-      else if (name == "base")
-         replacement = m_lastBaseDir.absolutePath();
-      else if (name == "textpattern")
-         replacement = ui->comboBoxTextPattern->currentText();
-      else if (name == "dirs")
-         replacement = QString::number(m_statistics.m_dirs);
-      else if (name == "files")
-         replacement = QString::number(m_statistics.m_files);
-      else if (name == "runtime")
-         replacement = QString::number(m_statistics.m_runtimeSeconds, 'g', 3);
-      else if (name == "bytes")
-         replacement = QString::number(m_statistics.m_bytes);
-      else if (name == "megabytes")
-         replacement = QString::number((double) m_statistics.m_bytes / 1000000);
-      else if (name == "datetime")
-         replacement = QDateTime::currentDateTime().toLocalTime().toString(
-            "yyyy.MM.dd/hh:mm:ss");
-      else{
-         QString msg = tr("unknown placeholder: ") + name;
-         guiError(ui->comboBoxFooter, msg);
-         break;
-      }
-      rc = rc.replace("${" + name + "}", replacement);
-      start += replacement.length();
-   }
+QString MainWindow::replaceGlobalPlaceholders(QComboBox* combo,
+       QHash<QString, QString>& placeholders){
+    QString rc = combo->currentText();
+    QString error;
+    if (! ReQStringUtil::replacePlaceholders(rc, placeholders, &error))
+        guiError(combo, error);
    return replaceEscSequences(rc);
 }
 
index 8992d8603f066d09ba5442968adf9b5425a1ed80..55cd987b5c87a9422f2c5c610a9c1e9a1d98f024 100644 (file)
@@ -47,6 +47,21 @@ struct Statistics {
    double m_runtimeSeconds;
 };
 
+class ContextHandler {
+public:
+    enum DirMode {
+        DM_UNDEF,
+        DM_TO_PARENT,
+        DM_TO_FILE
+    };
+
+public:
+    QString m_text;
+    QString m_program;
+    QString m_arguments;
+    DirMode m_changeToParentDirectory;
+};
+
 class MainWindow: public QMainWindow, public ReGuiValidator {
 
    Q_OBJECT
@@ -65,6 +80,7 @@ private slots:
    void filePlaceholder();
    void footerPlaceholder();
    void fullNameToClipboard();
+   void handleTableContextMenu(const QPoint& position);
    void headerClicked(int col);
    void headerPlaceholder();
    void preview();
@@ -76,15 +92,18 @@ private slots:
    void up();
 
 private:
+   void addContextMenu();
    QString buildAbsPath(int row);
    QDir::Filters buildFileTypes();
+   void buildGlobalPlaceholders(QHash<QString, QString>& hash);
    QString cellAsText(int row, int col);
    void exportToStream(QTextStream& stream, int maxRow = -1);
    void handlePlaceholder(QComboBox* target);
    void initializeHome();
    void mousePressEvent(QMouseEvent* event);
    void prepareTextFind();
-   QString replaceGlobalPlaceholder(const QString& text);
+   QString replaceGlobalPlaceholders(QComboBox* combo,
+                                     QHash<QString, QString>& placeholders);
    void restoreState();
    virtual void setStatusMessage(bool error, const QString& message);
 private:
@@ -99,6 +118,10 @@ private:
    Statistics m_statistics;
    QString m_homeDir;
    QString m_storageFile;
+   QAction* m_actionEditor;
+   QAction* m_actionStartShell;
+   QList <ContextHandler*> m_fileHandler;
+   QList <ContextHandler*> m_dirHandler;
 };
 
 #endif // MAINWINDOW_HPP
index 72fe81f2b70f214002497d446fa1d921fa34ad21..6752c61c7903bd15f767e2ed926105bded9dbb69 100644 (file)
       </item>
       <item>
        <widget class="QTableWidget" name="tableWidget">
+        <property name="editTriggers">
+         <set>QAbstractItemView::NoEditTriggers</set>
+        </property>
+        <property name="dragEnabled">
+         <bool>true</bool>
+        </property>
+        <property name="selectionBehavior">
+         <enum>QAbstractItemView::SelectRows</enum>
+        </property>
+        <attribute name="horizontalHeaderStretchLastSection">
+         <bool>true</bool>
+        </attribute>
         <column>
          <property name="text">
           <string>Filename</string>
           <string>Size (MByte)</string>
          </property>
          <property name="textAlignment">
-          <set>AlignRight|AlignVCenter</set>
+          <set>AlignRight|AlignBottom</set>
          </property>
         </column>
         <column>
index 6c1fb75c42b8c4554fae862901638f122da41401..709b269d8cd142903b7d34b78166da6045b8ae61 100644 (file)
@@ -24,7 +24,8 @@ SOURCES += main.cpp\
         ../../gui/ReStateStorage.cpp \
         ../../gui/ReGuiValidator.cpp \
         dialogglobalplaceholder.cpp \
-        dialogfileplaceholder.cpp
+        dialogfileplaceholder.cpp \
+    utils.cpp
 
 
 HEADERS  += mainwindow.hpp \
@@ -37,7 +38,8 @@ HEADERS  += mainwindow.hpp \
         ../../gui/ReGuiValidator.hpp \
         ../../gui/regui.hpp \
         dialogglobalplaceholder.hpp \
-        dialogfileplaceholder.hpp
+        dialogfileplaceholder.hpp \
+    utils.hpp
 
 
 FORMS    += mainwindow.ui \
index edd3ddd2e215bdb98cd038c7bc3b462803baa0c4..af4a9606f7a00ea7abd23f6596fa8ab12e9ebf68 100644 (file)
@@ -35,6 +35,31 @@ ReString ReQStringUtil::chomp(const ReString& text)
     return last == text.length() - 1 ? text : text.mid(0, last + 1);
 }
 
+/**
+ * Extracts the extension of a filename.
+ *
+ * @param filename  the filename (with or without path)
+ * @return          "": no extension found<br>
+ *                  otherwise: the extension of <code>filename</code>
+ */
+ReString ReQStringUtil::extensionOf(const ReString& filename)
+{
+    QString rc;
+
+    int index = filename.lastIndexOf('.');
+    if (index > 0){
+        int index2 = filename.lastIndexOf('/');
+        if (index2 < index){
+#if defined __WIN32__
+            index2 = filename.lastIndexOf('\\');
+            if (index2 < index)
+                rc = filename.mid(index);
+#endif
+        }
+    }
+    return rc;
+}
+
 
 /**
  * @brief Determines the length and vlaue of an integer.
@@ -108,29 +133,6 @@ int ReQStringUtil::lengthOfUInt(const ReString& text, int start, int radix,
    return rc;
 }
 
-/**
- * Skips a character in a text at a given position if it has an expected value.
- *
- * @param text      text to inspect
- * @param expected  the character which is expected
- * @param index     IN/OUT: the position of the expected character.
- *                  Will be incremented if the expected character is found
- * @param length    IN/OUT: IN: 0: do nothing<br>
- *                  OUT: 0: the expected character was not found.
- *                  otherwise: the length is incremented
- */
-void ReQStringUtil::skipExpected(const ReString& text, QChar expected,
-   int& index, int& length){
-   if (length == 0){
-      // error state, do nothing
-   }else if (index >= text.length() || text[index] != expected){
-      length = 0;
-   }else{
-      index++;
-      length++;
-   }
-}
-
 /**
  * Returns the length of a date in a string.
  *
@@ -356,6 +358,89 @@ int ReQStringUtil::lengthOfReal(const ReString& text, int start, qreal* pValue){
    return found ? ix - start : 0;
 }
 
+/**
+ * Appends a relative path to base directory name (absolute or relative).
+ *
+ * @param base  the base directory, relative or absolute
+ * @param toAdd a relative path (relative to <code>base</code>)
+ * @return      the combined path
+ */
+QString ReQStringUtil::pathAppend(const QString& base, const QString& path)
+{
+    QString rc;
+    if (!base.isEmpty())
+        rc = QDir::cleanPath(base + QDir::separator() + path);
+    else {
+        rc = path;
+        rc.replace("\\", "/");
+        if (path.startsWith("/"))
+            rc.remove(0, 1);
+    }
+    return rc;
+}
+
+/**
+ * Replaces placeholders by their values.
+ *
+ * Example for a placeholder: ${path}
+ *
+ * @param text          IN/OUT: the text to inspect/change
+ * @param placeholders  a hashmap with (name, value) pairs, e.g. ("path", "/")
+ * @param error         OUT: NULL or the error message (unknown name)
+ * @return              <code>true</code>: success<br>
+ *                      <code>false</code>: unknown name found (not replaced)
+ */
+bool ReQStringUtil::replacePlaceholders(QString& text,
+    const QHash<QString, QString>& placeholders, QString* error){
+    int start = 0;
+    bool rc = true;
+    QString name;
+    QHash<QString, QString>::const_iterator it;
+    while (start >= 0){
+       start = text.indexOf("${", start);
+       if (start < 0)
+          break;
+       int end = text.indexOf('}', start + 1);
+       if (end < 0)
+          break;
+       name = text.mid(start + 2, end - start - 2);
+       it = placeholders.find(name);
+       if (it == placeholders.end()){
+           rc = false;
+           if (error != NULL) {
+               *error = QObject::tr("unknown placeholder: ") + name;
+           }
+       }else{
+           text = text.replace("${" + name + "}", *it);
+       }
+       start += (*it).length();
+    }
+    return rc;
+}
+
+/**
+ * Skips a character in a text at a given position if it has an expected value.
+ *
+ * @param text      text to inspect
+ * @param expected  the character which is expected
+ * @param index     IN/OUT: the position of the expected character.
+ *                  Will be incremented if the expected character is found
+ * @param length    IN/OUT: IN: 0: do nothing<br>
+ *                  OUT: 0: the expected character was not found.
+ *                  otherwise: the length is incremented
+ */
+void ReQStringUtil::skipExpected(const ReString& text, QChar expected,
+   int& index, int& length){
+   if (length == 0){
+      // error state, do nothing
+   }else if (index >= text.length() || text[index] != expected){
+      length = 0;
+   }else{
+      index++;
+      length++;
+   }
+}
+
 /**
  * @brief Converts a ReString into an utf-8 string
  *
index e968926f2dd61d6de45f562345e5076c21f2bdd8..55a08881f9375b8e9c9067a01add6637a628343f 100644 (file)
@@ -15,6 +15,7 @@
 class ReQStringUtil {
 public:
     static ReString chomp(const ReString& text);
+    static ReString extensionOf(const ReString& filename);
     static int lengthOfDate(const ReString& text, int start = 0, QDate* value =
             NULL);
     static int lengthOfDateTime(const ReString& text, int start = 0,
@@ -28,7 +29,24 @@ public:
       int radix = 10, uint64_t* value = NULL);
    static int lengthOfUInt(const ReString& text, int start, int radix,
       uint* pValue);
-   static void skipExpected(const ReString& text, QChar expected, int& index, int& length);
+   /**
+    * Returns the path with native path separators.
+    *
+    * @param path   the path to change
+    * @return       the path with native path separators
+    */
+   inline static QString nativePath(const QString& path){
+#if defined __WIN32__
+       QString rc(path); return rc.replace("/", "\\");
+#else
+       return path;
+#endif
+   }
+   static QString pathAppend(const QString& base, const QString& path);
+   static bool replacePlaceholders(QString& text, const QHash<QString,
+                                  QString>& placeholders, QString* error);
+   static void skipExpected(const ReString& text, QChar expected, int& index,
+                            int& length);
    /**
     * @brief Returns the value of a hexadecimal digit.
     *
index d7a145fbaa17559c800b6998772bc503405a30bf..6665aef93dea490872144cf25b414cb0469ea2de 100644 (file)
@@ -116,7 +116,8 @@ QString ReGuiValidator::comboText(QComboBox* combo){
  * @param message   the error message
  */
 void ReGuiValidator::guiError(QWidget* widget, const QString& message){
-   widget->setFocus(Qt::OtherFocusReason);
+    if (widget != NULL)
+        widget->setFocus(Qt::OtherFocusReason);
    setStatusMessage(true, message);
    m_errors++;
 }