/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2012 Daniel Marjamäki and Cppcheck team. * * 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 3 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, see . */ #include "selectfilesdialog.h" #include "ui_selectfilesdialog.h" #include "filelist.h" #include #include #include class SelectFilesModel : public QFileSystemModel { private: /** * paths that are user-checked. on the screen all children * for these paths will appear to be checked too unless * they are "unchecked". */ QStringList checked; /** * paths that are user-unchecked. */ QStringList unchecked; /** * Get index in stringlist where start of string matches. If * many strings in the stringlist match then return the index * for the longest string. * \param paths stringlist with filepaths * \param filepath the filepath that is matched against the stringlist */ int getindex(const QStringList &paths, const QString &filepath) const { int matchlen = 0; int matchindex = -1; for (int i = 0; i < paths.size(); ++i) { if (filepath.startsWith(paths[i])) { // not a real match of paths.. if (paths[i].size() < filepath.size() && filepath[paths[i].size()] != '/') continue; // paths match. the return value is the index for the // longest match if (paths[i].size() > matchlen) matchindex = i; } } return matchindex; } /** * Is filepath partially checked? * \param filepath the filepath to investigate * \param checkindex result from getindex(checked,filepath). If not given the getindex will be called. * \return true if filepath is partially checked */ bool partiallyChecked(const QString &filepath, int checkindex = -2) const { const QString filepath2 = filepath.endsWith("/") ? filepath : (filepath + "/"); for (int i = 0; i < unchecked.size(); ++i) { if (unchecked[i].startsWith(filepath2)) { return true; } } if (checkindex == -2) checkindex = getindex(checked, filepath); if (checkindex == -1) { for (int i = 0; i < checked.size(); ++i) { if (checked[i].startsWith(filepath2)) { return true; } } } return false; } public: SelectFilesModel() : QFileSystemModel() { class FileLister : private FileList { public: static QStringList filters() { return GetDefaultFilters(); } }; setNameFilters(FileLister::filters()); setNameFilterDisables(false); setRootPath("/"); } Qt::ItemFlags flags(const QModelIndex& index) const { if (index.column() == 0) return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable; return QFileSystemModel::flags(index); } QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const { if (role == Qt::CheckStateRole) { const QString filepath = filePath(index); const int checkindex = getindex(checked, filepath); const int uncheckindex = getindex(unchecked, filepath); // If some children are not checked then this item should be partially checked.. if (partiallyChecked(filepath, checkindex)) return Qt::PartiallyChecked; // Is item selected but not unselected? if (checkindex >= 0 && uncheckindex == -1) return Qt::Checked; if (checkindex >= 0 && uncheckindex >= 0 && checked[checkindex].size() > unchecked[uncheckindex].size()) return Qt::Checked; // Item is either not selected at all or else it is unselected return Qt::Unchecked; } return QFileSystemModel::data(index, role); } bool setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::CheckStateRole) { const QString filepath = filePath(index); bool partiallychecked = partiallyChecked(filepath); if (unchecked.indexOf(filepath) != -1) { // remove unchecked path unchecked.removeAll(filepath); } else if (partiallychecked || checked.indexOf(filepath) != -1) { // remove child selected paths for (int i = checked.size() - 1; i >= 0; --i) { if (checked[i].startsWith(filepath)) checked.removeAt(i); } // remove child unselected paths for (int i = unchecked.size() - 1; i >= 0; --i) { if (unchecked[i].startsWith(filepath)) unchecked.removeAt(i); } // If partialChecked then select this item if (partiallychecked) checked.append(filepath); } else { const int checkindex = getindex(checked, filepath); const int uncheckindex = getindex(unchecked, filepath); if (checkindex == -1) checked.append(filepath); else if (uncheckindex >= 0 && checked[checkindex].size() < unchecked[uncheckindex].size()) checked.append(filepath); else unchecked.append(filepath); } if (rowCount(index) > 0) emit(dataChanged(index, index.child(rowCount(index)-1,0))); // update parents QModelIndex parent = index.parent(); while (parent != QModelIndex()) { emit(dataChanged(parent,parent)); parent = parent.parent(); } return true; } return QFileSystemModel::setData(index, value, role); } QStringList getFiles() const { QStringList ret; // List all files in "checked" folders.. FileList fileLister; fileLister.AddPathList(checked); ret = fileLister.GetFileList(); // Remove all items from ret that are unchecked but not checked.. for (int i = ret.size() - 1; i >= 0; i--) { int uncheckindex = getindex(unchecked, ret[i]); if (uncheckindex == -1) continue; // both checked and unchecked, check which to rely on int checkindex = getindex(checked, ret[i]); if (checked[checkindex].size() < unchecked[uncheckindex].size()) ret.removeAt(i); } return ret; } }; SelectFilesDialog::SelectFilesDialog(QWidget *w) : QDialog(w), ui(new Ui::SelectFilesDialog) { ui->setupUi(this); selectfilesmodel = new SelectFilesModel; ui->treeView->setModel(selectfilesmodel); for (int i = 1; i < 4; ++i) ui->treeView->setColumnHidden(i, true); // Change text of "OK" button to "Check" QPushButton *okbutton = ui->buttonBox->button(QDialogButtonBox::Ok); if (okbutton) okbutton->setText(tr("Check")); } SelectFilesDialog::~SelectFilesDialog() { delete ui; } QStringList SelectFilesDialog::getFiles() const { return selectfilesmodel->getFiles(); }