1 // Copyright (C) 2014-2018 Manuel Schneider
2 
3 #include <QDebug>
4 #include <QKeyEvent>
5 #include <QMimeDatabase>
6 #include <QSortFilterProxyModel>
7 #include <QStandardItemModel>
8 #include <QStringListModel>
9 #include <QtConcurrent>
10 #include <thread>
11 #include "mimetypedialog.h"
12 #include "ui_mimetypedialog.h"
13 
14 
15 /** ***************************************************************************/
MimeTypeDialog(const QStringList & filters,QWidget * parent)16 Files::MimeTypeDialog::MimeTypeDialog(const QStringList &filters, QWidget *parent) :
17     QDialog(parent), ui(new Ui::MimeTypeDialog) {
18     ui->setupUi(this);
19 
20     // Populate a standard itemmodel with mime types
21     QStandardItemModel *standardItemModel = new QStandardItemModel(this);
22     QList<QStandardItem*> items;
23     for (QMimeType mimeType : QMimeDatabase().allMimeTypes()) {
24         QStandardItem *item = new QStandardItem(mimeType.name());
25         item->setToolTip(mimeType.filterString());
26         item->setData(mimeType.iconName());
27         items.append(item);
28     }
29     standardItemModel->appendColumn(items);
30     standardItemModel->sort(0);
31 
32     // Get the images in background
33     auto bg_task = [this, standardItemModel](){
34         static QIcon fallback = QIcon::fromTheme("unknown"); // TODO: resource fallback
35         for (int i = 0; i < standardItemModel->rowCount(); ++i) {
36             QStandardItem *item = standardItemModel->item(i);
37             item->setIcon(QIcon::fromTheme(item->data().toString(), fallback));
38             if (exit_thread)
39                 break;
40         }
41         qDebug() << "DONE";
42     };
43 
44     future = QtConcurrent::run(bg_task);
45 
46     // Add a proxy model for mimtype filtering
47     QSortFilterProxyModel *mimeFilterModel = new QSortFilterProxyModel(this);
48     mimeFilterModel->setSourceModel(standardItemModel);
49     ui->listView_mimeTypes->setModel(mimeFilterModel);
50 
51     // Add a stinglist model to the filter model
52     filtersModel = new QStringListModel(filters, this);
53     ui->listView_filters->setModel(filtersModel);
54 
55     // Set the filter for the proxymodel if the users typed something
56     connect(ui->lineEdit, &QLineEdit::textChanged,
57             mimeFilterModel, &QSortFilterProxyModel::setFilterFixedString);
58 
59     // On mimetype list activation add the mimetype to the filter list
60     connect(ui->listView_mimeTypes, &QListView::activated, [this](const QModelIndex &index){
61         filtersModel->insertRow(filtersModel->rowCount());
62         filtersModel->setData(filtersModel->index(filtersModel->rowCount()-1,0), index.data());
63     });
64 
65     // On ">" button click add the mimetype to the filter list
66     connect(ui->toolButton_copyMimetype, &QToolButton::clicked, [this](){
67         QModelIndex index = ui->listView_mimeTypes->currentIndex();
68         filtersModel->insertRow(filtersModel->rowCount());
69         filtersModel->setData(filtersModel->index(filtersModel->rowCount()-1,0), index.data());
70     });
71 
72     // Add a new line on "+"
73     connect(ui->toolButton_add, &QToolButton::clicked, [this](){
74         int row = filtersModel->rowCount();
75         filtersModel->insertRow(row);
76         ui->listView_filters->setCurrentIndex(filtersModel->index(row, 0));
77         ui->listView_filters->edit(filtersModel->index(row, 0));
78     });
79 
80     // Remove the selected line on "-"
81     connect(ui->toolButton_remove, &QToolButton::clicked, [this](){
82         QModelIndex index = ui->listView_filters->currentIndex();
83         if ( index.isValid() )
84             filtersModel->removeRow(index.row());
85     });
86 
87     // Let the listview intercept the input of the filter line edit (for navigation and activation)
88     ui->lineEdit->installEventFilter(this);
89 }
90 
91 
92 
93 /** ***************************************************************************/
~MimeTypeDialog()94 Files::MimeTypeDialog::~MimeTypeDialog() {
95     exit_thread = true;
96     future.waitForFinished();
97     delete ui;
98 }
99 
100 
101 
102 /** ***************************************************************************/
filters() const103 QStringList Files::MimeTypeDialog::filters() const {
104     return filtersModel->stringList();
105 }
106 
107 
108 
109 /** ***************************************************************************/
eventFilter(QObject *,QEvent * event)110 bool Files::MimeTypeDialog::eventFilter(QObject * /*theres only the linedit*/, QEvent *event) {
111 
112     if (event->type() == QEvent::KeyPress) {
113         QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
114         switch (keyEvent->key()) {
115         case Qt::Key_Up:
116         case Qt::Key_Down:
117         case Qt::Key_Enter:
118         case Qt::Key_Return:
119             QApplication::sendEvent(ui->listView_mimeTypes, keyEvent);
120             return true;
121         default:
122             return false;
123         }
124     }
125     return false;
126 }
127 
128 
129 
130 /** ***************************************************************************/
keyPressEvent(QKeyEvent * evt)131 void Files::MimeTypeDialog::keyPressEvent(QKeyEvent *evt) {
132     // Eat keys for desired behaviour
133     switch ( evt->key() ) {
134     case Qt::Key_Enter:
135     case Qt::Key_Return:
136     case Qt::Key_Escape:
137         return;
138     }
139     QDialog::keyPressEvent(evt);
140 }
141