Cppcheck
selectfilesdialog.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2012 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "selectfilesdialog.h"
00020 #include "ui_selectfilesdialog.h"
00021 #include "filelist.h"
00022 
00023 #include <QFileSystemModel>
00024 #include <QStringList>
00025 #include <QPushButton>
00026 
00027 class SelectFilesModel : public QFileSystemModel {
00028 private:
00029     /**
00030      * paths that are user-checked. on the screen all children
00031      * for these paths will appear to be checked too unless
00032      * they are "unchecked".
00033      */
00034     QStringList checked;
00035 
00036     /**
00037      * paths that are user-unchecked.
00038      */
00039     QStringList unchecked;
00040 
00041     /**
00042      * Get index in stringlist where start of string matches. If
00043      * many strings in the stringlist match then return the index
00044      * for the longest string.
00045      * \param paths stringlist with filepaths
00046      * \param filepath the filepath that is matched against the stringlist
00047      */
00048     int getindex(const QStringList &paths, const QString &filepath) const {
00049         int matchlen = 0;
00050         int matchindex = -1;
00051         for (int i = 0; i < paths.size(); ++i) {
00052             if (filepath.startsWith(paths[i])) {
00053                 // not a real match of paths..
00054                 if (paths[i].size() < filepath.size() && filepath[paths[i].size()] != '/')
00055                     continue;
00056 
00057                 // paths match. the return value is the index for the
00058                 // longest match
00059                 if (paths[i].size() > matchlen)
00060                     matchindex = i;
00061             }
00062         }
00063         return matchindex;
00064     }
00065 
00066     /**
00067      * Is filepath partially checked?
00068      * \param filepath the filepath to investigate
00069      * \param checkindex result from getindex(checked,filepath). If not given the getindex will be called.
00070      * \return true if filepath is partially checked
00071      */
00072     bool partiallyChecked(const QString &filepath, int checkindex = -2) const {
00073         const QString filepath2 = filepath.endsWith("/") ? filepath : (filepath + "/");
00074 
00075         for (int i = 0; i < unchecked.size(); ++i) {
00076             if (unchecked[i].startsWith(filepath2)) {
00077                 return true;
00078             }
00079         }
00080 
00081         if (checkindex == -2)
00082             checkindex = getindex(checked, filepath);
00083 
00084 
00085         if (checkindex == -1) {
00086             for (int i = 0; i < checked.size(); ++i) {
00087                 if (checked[i].startsWith(filepath2)) {
00088                     return true;
00089                 }
00090             }
00091         }
00092 
00093         return false;
00094     }
00095 
00096 public:
00097     SelectFilesModel() : QFileSystemModel() {
00098         class FileLister : private FileList {
00099         public:
00100             static QStringList filters() {
00101                 return GetDefaultFilters();
00102             }
00103         };
00104         setNameFilters(FileLister::filters());
00105         setNameFilterDisables(false);
00106         setRootPath("/");
00107     }
00108 
00109     Qt::ItemFlags flags(const QModelIndex& index) const {
00110         if (index.column() == 0)
00111             return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable;
00112         return QFileSystemModel::flags(index);
00113     }
00114 
00115     QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const {
00116         if (role == Qt::CheckStateRole) {
00117             const QString filepath = filePath(index);
00118             const int checkindex = getindex(checked, filepath);
00119             const int uncheckindex = getindex(unchecked, filepath);
00120 
00121             // If some children are not checked then this item should be partially checked..
00122             if (partiallyChecked(filepath, checkindex))
00123                 return Qt::PartiallyChecked;
00124 
00125             // Is item selected but not unselected?
00126             if (checkindex >= 0 && uncheckindex == -1)
00127                 return Qt::Checked;
00128             if (checkindex >= 0 && uncheckindex >= 0 &&
00129                 checked[checkindex].size() > unchecked[uncheckindex].size())
00130                 return Qt::Checked;
00131 
00132             // Item is either not selected at all or else it is unselected
00133             return Qt::Unchecked;
00134         }
00135         return QFileSystemModel::data(index, role);
00136     }
00137 
00138     bool setData(const QModelIndex& index, const QVariant& value, int role) {
00139         if (role == Qt::CheckStateRole) {
00140             const QString filepath = filePath(index);
00141 
00142             bool partiallychecked = partiallyChecked(filepath);
00143 
00144             if (unchecked.indexOf(filepath) != -1) {
00145                 // remove unchecked path
00146                 unchecked.removeAll(filepath);
00147             } else if (partiallychecked || checked.indexOf(filepath) != -1) {
00148                 // remove child selected paths
00149                 for (int i = checked.size() - 1; i >= 0; --i) {
00150                     if (checked[i].startsWith(filepath))
00151                         checked.removeAt(i);
00152                 }
00153 
00154                 // remove child unselected paths
00155                 for (int i = unchecked.size() - 1; i >= 0; --i) {
00156                     if (unchecked[i].startsWith(filepath))
00157                         unchecked.removeAt(i);
00158                 }
00159 
00160                 // If partialChecked then select this item
00161                 if (partiallychecked)
00162                     checked.append(filepath);
00163             } else {
00164                 const int checkindex = getindex(checked, filepath);
00165                 const int uncheckindex = getindex(unchecked, filepath);
00166                 if (checkindex == -1)
00167                     checked.append(filepath);
00168                 else if (uncheckindex >= 0 && checked[checkindex].size() < unchecked[uncheckindex].size())
00169                     checked.append(filepath);
00170                 else
00171                     unchecked.append(filepath);
00172             }
00173 
00174             if (rowCount(index) > 0)
00175                 emit(dataChanged(index, index.child(rowCount(index)-1,0)));
00176 
00177             // update parents
00178             QModelIndex parent = index.parent();
00179             while (parent != QModelIndex()) {
00180                 emit(dataChanged(parent,parent));
00181                 parent = parent.parent();
00182             }
00183 
00184             return true;
00185         }
00186         return QFileSystemModel::setData(index, value, role);
00187     }
00188 
00189     QStringList getFiles() const {
00190         QStringList ret;
00191 
00192         // List all files in "checked" folders..
00193         FileList fileLister;
00194         fileLister.AddPathList(checked);
00195         ret = fileLister.GetFileList();
00196 
00197         // Remove all items from ret that are unchecked but not checked..
00198         for (int i = ret.size() - 1; i >= 0; i--) {
00199             int uncheckindex = getindex(unchecked, ret[i]);
00200             if (uncheckindex == -1)
00201                 continue;
00202 
00203             // both checked and unchecked, check which to rely on
00204             int checkindex = getindex(checked, ret[i]);
00205             if (checked[checkindex].size() < unchecked[uncheckindex].size())
00206                 ret.removeAt(i);
00207         }
00208 
00209         return ret;
00210     }
00211 };
00212 
00213 
00214 
00215 SelectFilesDialog::SelectFilesDialog(QWidget *w) :
00216     QDialog(w),
00217     ui(new Ui::SelectFilesDialog)
00218 {
00219     ui->setupUi(this);
00220 
00221     selectfilesmodel = new SelectFilesModel;
00222 
00223     ui->treeView->setModel(selectfilesmodel);
00224     for (int i = 1; i < 4; ++i)
00225         ui->treeView->setColumnHidden(i, true);
00226 
00227     // Change text of "OK" button to "Check"
00228     QPushButton *okbutton = ui->buttonBox->button(QDialogButtonBox::Ok);
00229     if (okbutton)
00230         okbutton->setText(tr("Check"));
00231 }
00232 
00233 SelectFilesDialog::~SelectFilesDialog()
00234 {
00235     delete ui;
00236 }
00237 
00238 QStringList SelectFilesDialog::getFiles() const
00239 {
00240     return selectfilesmodel->getFiles();
00241 }