#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
+#include <QProcess>
#include "base/rebase.hpp"
#include "gui/regui.hpp"
#include "textfinder.hpp"
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"));
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)
exportToStream(stream, 1);
}
-/**
- * @brief Destructor.
- */
-MainWindow::~MainWindow(){
- delete ui;
-}
-
/**
* Starts the about dialog.
*/
* @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;
}
}
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".
*/
}
}
+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);
}
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.
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.
*
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
*