1 #include "ignorelisttablewidget.h"
2 #include "ui_ignorelisttablewidget.h"
3 
4 #include "folderman.h"
5 
6 #include <QFile>
7 #include <QInputDialog>
8 #include <QLineEdit>
9 #include <QMessageBox>
10 
11 namespace OCC {
12 
13 static constexpr int patternCol = 0;
14 static constexpr int deletableCol = 1;
15 static constexpr int readOnlyRows = 3;
16 
IgnoreListTableWidget(QWidget * parent)17 IgnoreListTableWidget::IgnoreListTableWidget(QWidget *parent)
18     : QWidget(parent)
19     , ui(new Ui::IgnoreListTableWidget)
20 {
21     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
22     ui->setupUi(this);
23 
24     ui->descriptionLabel->setText(tr("Files or folders matching a pattern will not be synchronized.\n\n"
25                                      "Items where deletion is allowed will be deleted if they prevent a "
26                                      "directory from being removed. "
27                                      "This is useful for meta data."));
28 
29     ui->removePushButton->setEnabled(false);
30     connect(ui->tableWidget,         &QTableWidget::itemSelectionChanged,
31             this, &IgnoreListTableWidget::slotItemSelectionChanged);
32     connect(ui->removePushButton,    &QAbstractButton::clicked,
33             this, &IgnoreListTableWidget::slotRemoveCurrentItem);
34     connect(ui->addPushButton,       &QAbstractButton::clicked,
35             this, &IgnoreListTableWidget::slotAddPattern);
36     connect(ui->removeAllPushButton, &QAbstractButton::clicked,
37             this, &IgnoreListTableWidget::slotRemoveAllItems);
38 
39     ui->tableWidget->resizeColumnsToContents();
40     ui->tableWidget->horizontalHeader()->setSectionResizeMode(patternCol, QHeaderView::Stretch);
41     ui->tableWidget->verticalHeader()->setVisible(false);
42 }
43 
~IgnoreListTableWidget()44 IgnoreListTableWidget::~IgnoreListTableWidget()
45 {
46     delete ui;
47 }
48 
slotItemSelectionChanged()49 void IgnoreListTableWidget::slotItemSelectionChanged()
50 {
51     QTableWidgetItem *item = ui->tableWidget->currentItem();
52     if (!item) {
53         ui->removePushButton->setEnabled(false);
54         return;
55     }
56 
57     bool enable = item->flags() & Qt::ItemIsEnabled;
58     ui->removePushButton->setEnabled(enable);
59 }
60 
slotRemoveCurrentItem()61 void IgnoreListTableWidget::slotRemoveCurrentItem()
62 {
63     ui->tableWidget->removeRow(ui->tableWidget->currentRow());
64     if(ui->tableWidget->rowCount() == readOnlyRows)
65         ui->removeAllPushButton->setEnabled(false);
66 }
67 
slotRemoveAllItems()68 void IgnoreListTableWidget::slotRemoveAllItems()
69 {
70     ui->tableWidget->setRowCount(0);
71 }
72 
slotWriteIgnoreFile(const QString & file)73 void IgnoreListTableWidget::slotWriteIgnoreFile(const QString & file)
74 {
75     QFile ignores(file);
76     if (ignores.open(QIODevice::WriteOnly)) {
77         // rewrites the whole file since now the user can also remove system patterns
78         QFile::resize(file, 0);
79         for (int row = 0; row < ui->tableWidget->rowCount(); ++row) {
80             QTableWidgetItem *patternItem = ui->tableWidget->item(row, patternCol);
81             QTableWidgetItem *deletableItem = ui->tableWidget->item(row, deletableCol);
82             if (patternItem->flags() & Qt::ItemIsEnabled) {
83                 QByteArray prepend;
84                 if (deletableItem->checkState() == Qt::Checked) {
85                     prepend = "]";
86                 } else if (patternItem->text().startsWith('#')) {
87                     prepend = "\\";
88                 }
89                 ignores.write(prepend + patternItem->text().toUtf8() + '\n');
90             }
91         }
92     } else {
93         QMessageBox::warning(this, tr("Could not open file"),
94             tr("Cannot write changes to \"%1\".").arg(file));
95     }
96     ignores.close(); //close the file before reloading stuff.
97 
98     FolderMan *folderMan = FolderMan::instance();
99 
100     // We need to force a remote discovery after a change of the ignore list.
101     // Otherwise we would not download the files/directories that are no longer
102     // ignored (because the remote etag did not change)   (issue #3172)
103     foreach (Folder *folder, folderMan->map()) {
104         folder->journalDb()->forceRemoteDiscoveryNextSync();
105         folderMan->scheduleFolder(folder);
106     }
107 }
108 
slotAddPattern()109 void IgnoreListTableWidget::slotAddPattern()
110 {
111     bool okClicked = false;
112     QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"),
113         tr("Add a new ignore pattern:"),
114         QLineEdit::Normal, QString(), &okClicked);
115 
116     if (!okClicked || pattern.isEmpty())
117         return;
118 
119     addPattern(pattern, false, false);
120     ui->tableWidget->scrollToBottom();
121 }
122 
readIgnoreFile(const QString & file,bool readOnly)123 void IgnoreListTableWidget::readIgnoreFile(const QString &file, bool readOnly)
124 {
125     QFile ignores(file);
126     if (ignores.open(QIODevice::ReadOnly)) {
127         while (!ignores.atEnd()) {
128             QString line = QString::fromUtf8(ignores.readLine());
129             line.chop(1);
130             if (!line.isEmpty() && !line.startsWith("#")) {
131                 bool deletable = false;
132                 if (line.startsWith(']')) {
133                     deletable = true;
134                     line = line.mid(1);
135                 }
136                 addPattern(line, deletable, readOnly);
137             }
138         }
139     }
140 }
141 
addPattern(const QString & pattern,bool deletable,bool readOnly)142 int IgnoreListTableWidget::addPattern(const QString &pattern, bool deletable, bool readOnly)
143 {
144     int newRow = ui->tableWidget->rowCount();
145     ui->tableWidget->setRowCount(newRow + 1);
146 
147     auto *patternItem = new QTableWidgetItem;
148     patternItem->setText(pattern);
149     ui->tableWidget->setItem(newRow, patternCol, patternItem);
150 
151     auto *deletableItem = new QTableWidgetItem;
152     deletableItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
153     deletableItem->setCheckState(deletable ? Qt::Checked : Qt::Unchecked);
154     ui->tableWidget->setItem(newRow, deletableCol, deletableItem);
155 
156     if (readOnly) {
157         patternItem->setFlags(patternItem->flags() ^ Qt::ItemIsEnabled);
158         patternItem->setToolTip(readOnlyTooltip);
159         deletableItem->setFlags(deletableItem->flags() ^ Qt::ItemIsEnabled);
160     }
161 
162     ui->removeAllPushButton->setEnabled(true);
163 
164     return newRow;
165 }
166 
167 } // namespace OCC
168