Mercurial > retraceit
view src/folderselectdialog.cpp @ 90:c3000fa6ca56
Add back button to subfolder selection dialog
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Fri, 19 Jun 2015 14:27:56 +0200 |
parents | 3916cb3c9105 |
children | 0cf81afa82c1 |
line wrap: on
line source
/* Copyright (C) 2015 by ETH Zürich * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "folderselectdialog.h" #include "constants.h" #include <QSortFilterProxyModel> #include <QStandardItemModel> #include <QTableView> #include <QVBoxLayout> #include <QLineEdit> #include <QLabel> #include <QApplication> #include <QStyle> #include <QFileDialog> #include <QStandardPaths> #include <QPushButton> #include <QHeaderView> #include <QDebug> #include <QSettings> #include <QStringList> #include <QStandardItem> #include <QMessageBox> static ulong ipStringToLong(const QString str) { QStringList octets = str.split("."); if (!octets.size() > 3) { qWarning() << "invalid call to str to long"; return 0; } ulong s1 = octets.at(0).toLong(); ulong s2 = octets.at(1).toLong(); ulong s3 = octets.at(2).toLong(); ulong s4 = octets.at(3).toLong(); return (s1 << 24) | (s2 << 16) | (s3 << 8) | s4; } class IPAwareSortModel : public QSortFilterProxyModel { public: bool lessThan(const QModelIndex &left, const QModelIndex &right) const { QString leftString = sourceModel()->data(left).toString(); QString rightString = sourceModel()->data(right).toString(); static QRegExp ipPattern("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"); if (ipPattern.indexIn(leftString) != -1 && ipPattern.indexIn(rightString) != -1) { return ipStringToLong(leftString) > ipStringToLong(rightString); } else { return QSortFilterProxyModel::lessThan(left, right); } } }; FolderSelectDialog::FolderSelectDialog(const QString& startFolder, const QString& folderPattern, const QString& pathLabel, QWidget * parent, Qt::WindowFlags f) : QDialog(parent, f), mCurFolder(startFolder), mFolderPattern(folderPattern), mPathLabelString(pathLabel), mPathLabel(NULL), mPathLineEdit(NULL) { mSortModel = new IPAwareSortModel(); mModel = new QStandardItemModel(); mShowPathSelection = !pathLabel.isEmpty(); setupGUI(); if (mShowPathSelection) { mPathLabel->setText("<b>" + pathLabel + ":</b> "); } setFolder(mCurFolder); #ifndef Q_OS_WIN QIcon windowIcon = QIcon(":/icon-64.png"); setWindowIcon(windowIcon); #endif } void FolderSelectDialog::setupGUI() { QVBoxLayout *base = new QVBoxLayout; QHBoxLayout *folderChangeArea = new QHBoxLayout; if (mShowPathSelection) { mPathLabel = new QLabel; folderChangeArea->addWidget(mPathLabel); base->addLayout(folderChangeArea); QPushButton *folderSelect = new QPushButton(); folderSelect->setToolTip(tr("Select folder")); folderSelect->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon)); connect(folderSelect, &QPushButton::clicked, this, &FolderSelectDialog::changeFolderClicked); folderChangeArea->addWidget(folderSelect); mPathLineEdit = new QLineEdit; mPathLineEdit->setClearButtonEnabled(true); connect(mPathLineEdit, &QLineEdit::textChanged, this, &FolderSelectDialog::pathLineChanged); folderChangeArea->addWidget(mPathLineEdit); mGoButton = new QPushButton(tr("Go")); mGoButton->setEnabled(false); QPushButton *backBtn = new QPushButton; backBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowBack)); backBtn->setToolTip(tr("Back to exam selection.")); folderChangeArea->addWidget(mGoButton); connect(mGoButton, &QPushButton::clicked, this, &FolderSelectDialog::goClicked); connect(mPathLineEdit, &QLineEdit::returnPressed, this, &FolderSelectDialog::goClicked); } mFilterWidget = new FilterWidget(mSortModel, false); base->addWidget(mFilterWidget); connect(mSortModel, &QSortFilterProxyModel::sourceModelChanged, mFilterWidget, &FilterWidget::headersChanged); mView = new QTableView; mView->setModel(mSortModel); mView->setSelectionBehavior(QAbstractItemView::SelectRows); mView->setSelectionMode(QAbstractItemView::SingleSelection); mView->setSortingEnabled(true); mView->setEditTriggers(QAbstractItemView::NoEditTriggers); connect(mView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FolderSelectDialog::selectionChanged); connect(mView, &QTableView::doubleClicked, this, &FolderSelectDialog::wantToAccept); base->addWidget(mView); QHBoxLayout * bottomButtons = new QHBoxLayout; base->addLayout(bottomButtons); mOkButton = new QPushButton(tr("Ok")); mOkButton->setEnabled(false); connect(mOkButton, &QPushButton::clicked, this, &FolderSelectDialog::wantToAccept); bottomButtons->addStretch(-1); QPushButton *backBtn = NULL; if (!mShowPathSelection) { backBtn = new QPushButton(tr("Back")); backBtn->setToolTip(tr("Back to exam selection.")); connect(backBtn, &QPushButton::clicked, this, &FolderSelectDialog::backClicked); bottomButtons->addWidget(backBtn); } bottomButtons->addWidget(mOkButton); setLayout(base); } void FolderSelectDialog::selectionChanged (const QItemSelection& selected, const QItemSelection& deselected) { mOkButton->setEnabled(!selected.indexes().isEmpty()); if (mOkButton->isEnabled()) { mOkButton->setFocus(); } } void FolderSelectDialog::pathLineChanged() { const QString path = mPathLineEdit->text(); if (path.isEmpty()) { mGoButton->setEnabled(false); return; } mGoButton->setEnabled(true); } void FolderSelectDialog::goClicked() { const QString path = mPathLineEdit->text(); QDir dir(path); if (!dir.exists()) { QMessageBox::warning(this, tr("Error!"), tr("Failed to access directory: '%1'").arg(path)); mGoButton->setEnabled(false); return; } setFolder(mPathLineEdit->text()); QSettings settings; /* assuming go is only available in root folder mode */ settings.setValue(ROOT_FOLDER_KEY, mPathLineEdit->text()); } void FolderSelectDialog::setFolder(const QString& folder) { if (folder.isEmpty()) { return; } mCurFolder = folder; if (mPathLineEdit) { mPathLineEdit->setText(mCurFolder); } QStringList columns = mFolderPattern.split(PATTERN_SEPERATOR); mModel->clear(); mModel->setHorizontalHeaderLabels(columns); QDir dir(folder); qDebug() << "Folder set to: " << folder; QStringList errors; foreach (const QString & subfolder, dir.entryList(QDir::Dirs | QDir::Readable | QDir::NoDotAndDotDot)) { qDebug() << "Looking at: " << subfolder; QStringList itemData = subfolder.split(PATTERN_SEPERATOR); if (itemData.size() != columns.size()) { errors << subfolder; continue; } QList<QStandardItem*> items; foreach (const QString& part, itemData) { QStandardItem * item = new QStandardItem(part); item->setData(dir.absoluteFilePath(subfolder)); items.append(item); } mModel->appendRow(items); } mSortModel->setSourceModel(mModel); if (!errors.isEmpty()) { QString errMsg = tr("The following folders did not match the pattern: %1").arg(mFolderPattern); errMsg += "\n" + errors.join("\n"); QMessageBox::warning(this, tr("Failed to parse some folders."), errMsg); } mView->resizeColumnsToContents(); } void FolderSelectDialog::wantToAccept() { QItemSelectionModel *selection = mView->selectionModel(); QModelIndexList selected = selection->selectedIndexes(); if (selected.isEmpty()) { /* Ok should not be enabled in that case */ return; } const QString folder = selected[0].data(Qt::UserRole + 1).toString(); emit folderSelected(folder); accept(); } void FolderSelectDialog::changeFolderClicked() { const QString oldFolder = mCurFolder; const QString startLoc = mCurFolder.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) : mCurFolder; QString outFolder = QFileDialog::getExistingDirectory( this, tr("Select %1").arg(mPathLabelString), startLoc); if (outFolder.isEmpty()) { /* User aborted */ return; } setFolder(outFolder); }