1 #include "archivelistwidget.h"
2 #include "archivelistwidgetitem.h"
3 #include "debug.h"
4 #include "restoredialog.h"
5 
6 #include <QKeyEvent>
7 #include <QMessageBox>
8 
9 #define DELETE_CONFIRMATION_THRESHOLD 10
10 
ArchiveListWidget(QWidget * parent)11 ArchiveListWidget::ArchiveListWidget(QWidget *parent) : QListWidget(parent)
12 {
13     _filter.setCaseSensitivity(Qt::CaseInsensitive);
14     _filter.setPatternSyntax(QRegExp::Wildcard);
15     connect(this, &QListWidget::itemActivated, [&](QListWidgetItem *item) {
16         if(item)
17         {
18             ArchiveListWidgetItem *archiveItem =
19                 static_cast<ArchiveListWidgetItem *>(item);
20             if(archiveItem && !archiveItem->archive()->deleteScheduled())
21                 emit inspectArchive(archiveItem->archive());
22         }
23     });
24 }
25 
~ArchiveListWidget()26 ArchiveListWidget::~ArchiveListWidget()
27 {
28     clear();
29 }
30 
setArchives(QList<ArchivePtr> archives)31 void ArchiveListWidget::setArchives(QList<ArchivePtr> archives)
32 {
33     std::sort(archives.begin(), archives.end(),
34               [](const ArchivePtr &a, const ArchivePtr &b) {
35                   return (a->timestamp() > b->timestamp());
36               });
37     setUpdatesEnabled(false);
38     clear();
39     foreach(ArchivePtr archive, archives)
40         insertArchive(archive, count());
41     setUpdatesEnabled(true);
42 }
43 
addArchive(ArchivePtr archive)44 void ArchiveListWidget::addArchive(ArchivePtr archive)
45 {
46     if(!archive)
47     {
48         DEBUG << "Null ArchivePtr passed.";
49         return;
50     }
51 
52     int pos = 0;
53     for(; pos < count(); ++pos)
54     {
55         ArchiveListWidgetItem *archiveItem =
56             static_cast<ArchiveListWidgetItem *>(item(pos));
57         if(archiveItem
58            && (archive->timestamp() > archiveItem->archive()->timestamp()))
59         {
60             break;
61         }
62     }
63     insertArchive(archive, pos);
64 }
65 
deleteItem()66 void ArchiveListWidget::deleteItem()
67 {
68     ArchiveListWidgetItem *archiveItem =
69         qobject_cast<ArchiveListWidgetItem *>(sender());
70     if(archiveItem)
71     {
72         ArchivePtr archive = archiveItem->archive();
73         auto       confirm = QMessageBox::question(this, tr("Confirm delete"),
74                                              tr("Are you sure you want to "
75                                                 "delete archive %1 "
76                                                 "(this cannot be undone)?")
77                                                  .arg(archive->name()));
78         if(confirm == QMessageBox::Yes)
79         {
80             QList<ArchivePtr> archiveList;
81             archiveList.append(archive);
82             emit deleteArchives(archiveList);
83         }
84     }
85 }
86 
deleteSelectedItems()87 void ArchiveListWidget::deleteSelectedItems()
88 {
89     if(selectedItems().isEmpty())
90         return;
91 
92     QList<ArchiveListWidgetItem *> selectedListItems;
93     // Any archives pending deletion in the selection? if so deny action
94     foreach(QListWidgetItem *item, selectedItems())
95     {
96         ArchiveListWidgetItem *archiveItem =
97             static_cast<ArchiveListWidgetItem *>(item);
98         if(!archiveItem || archiveItem->archive()->deleteScheduled())
99             return;
100         else
101             selectedListItems << archiveItem;
102     }
103 
104     int  selectedItemsCount = selectedItems().count();
105     auto confirm =
106         QMessageBox::question(this, tr("Confirm delete"),
107                               tr("Are you sure you want to delete %1 "
108                                  "selected archive(s) "
109                                  "(this cannot be undone)?")
110                                   .arg(selectedItemsCount));
111     if(confirm != QMessageBox::Yes)
112         return;
113 
114     // Some more deletion confirmation, if count of archives to be
115     // removed is bigger than threshold
116     if(selectedItemsCount >= DELETE_CONFIRMATION_THRESHOLD)
117     {
118         // Inform of purge operation if all archives are to be removed
119         if(selectedItemsCount == count())
120         {
121             confirm =
122                 QMessageBox::question(this, tr("Confirm delete"),
123                                       tr("Are you sure you want to delete "
124                                          "all of your archives?\nFor your "
125                                          "information, there's a purge "
126                                          "action in Settings -> Account "
127                                          "page that achieves the same "
128                                          "thing but more efficiently."));
129         }
130         else
131         {
132             confirm = QMessageBox::question(this, tr("Confirm delete"),
133                                             tr("This will permanently delete "
134                                                "the %1 selected archives. "
135                                                "Proceed?")
136                                                 .arg(selectedItemsCount));
137         }
138     }
139 
140     if(confirm == QMessageBox::Yes)
141     {
142         QList<ArchivePtr> archivesToDelete;
143         foreach(ArchiveListWidgetItem *archiveItem, selectedListItems)
144         {
145             archivesToDelete.append(archiveItem->archive());
146         }
147         if(!archivesToDelete.isEmpty())
148             emit deleteArchives(archivesToDelete);
149     }
150 }
151 
inspectSelectedItem()152 void ArchiveListWidget::inspectSelectedItem()
153 {
154     if(!selectedItems().isEmpty())
155     {
156         ArchiveListWidgetItem *archiveItem =
157             static_cast<ArchiveListWidgetItem *>(selectedItems().first());
158         if(archiveItem && !archiveItem->archive()->deleteScheduled())
159             emit inspectArchive(archiveItem->archive());
160     }
161 }
162 
restoreSelectedItem()163 void ArchiveListWidget::restoreSelectedItem()
164 {
165     if(!selectedItems().isEmpty())
166     {
167         ArchiveListWidgetItem *archiveItem =
168             static_cast<ArchiveListWidgetItem *>(selectedItems().first());
169         if(archiveItem && !archiveItem->archive()->deleteScheduled())
170         {
171             RestoreDialog *restoreDialog =
172                 new RestoreDialog(this, archiveItem->archive());
173             restoreDialog->show();
174             connect(restoreDialog, &RestoreDialog::accepted, [=] {
175                 emit restoreArchive(restoreDialog->archive(),
176                                     restoreDialog->getOptions());
177             });
178         }
179     }
180 }
181 
setFilter(QString regex)182 void ArchiveListWidget::setFilter(QString regex)
183 {
184     setUpdatesEnabled(false);
185     clearSelection();
186     _filter.setPattern(regex);
187     for(int i = 0; i < count(); ++i)
188     {
189         ArchiveListWidgetItem *archiveItem =
190             static_cast<ArchiveListWidgetItem *>(item(i));
191         if(archiveItem)
192         {
193             if(archiveItem->archive()->name().contains(_filter))
194                 archiveItem->setHidden(false);
195             else
196                 archiveItem->setHidden(true);
197         }
198     }
199     setUpdatesEnabled(true);
200     emit countChanged(count(), visibleItemsCount());
201 }
202 
removeItem()203 void ArchiveListWidget::removeItem()
204 {
205     ArchiveListWidgetItem *archiveItem =
206         qobject_cast<ArchiveListWidgetItem *>(sender());
207     if(archiveItem)
208     {
209         delete archiveItem; // Removes item from the list
210         emit countChanged(count(), visibleItemsCount());
211     }
212 }
213 
insertArchive(ArchivePtr archive,int pos)214 void ArchiveListWidget::insertArchive(ArchivePtr archive, int pos)
215 {
216     if(!archive)
217     {
218         DEBUG << "Null ArchivePtr passed.";
219         return;
220     }
221 
222     ArchiveListWidgetItem *item = new ArchiveListWidgetItem(archive);
223     connect(item, &ArchiveListWidgetItem::requestDelete, this,
224             &ArchiveListWidget::deleteItem);
225     connect(item, &ArchiveListWidgetItem::requestInspect, this,
226             &ArchiveListWidget::inspectItem);
227     connect(item, &ArchiveListWidgetItem::requestRestore, this,
228             &ArchiveListWidget::restoreItem);
229     connect(item, &ArchiveListWidgetItem::requestGoToJob, this,
230             &ArchiveListWidget::goToJob);
231     connect(item, &ArchiveListWidgetItem::removeItem, this,
232             &ArchiveListWidget::removeItem);
233     insertItem(pos, item);
234     setItemWidget(item, item->widget());
235     item->setHidden(!archive->name().contains(_filter));
236     emit countChanged(count(), visibleItemsCount());
237 }
238 
visibleItemsCount()239 int ArchiveListWidget::visibleItemsCount()
240 {
241     int count = 0;
242     foreach(QListWidgetItem *item, findItems("*", Qt::MatchWildcard))
243     {
244         if(item && !item->isHidden())
245             count++;
246     }
247     return count;
248 }
249 
inspectItem()250 void ArchiveListWidget::inspectItem()
251 {
252     if(sender())
253         emit inspectArchive(
254             qobject_cast<ArchiveListWidgetItem *>(sender())->archive());
255 }
256 
restoreItem()257 void ArchiveListWidget::restoreItem()
258 {
259     ArchiveListWidgetItem *archiveItem =
260         qobject_cast<ArchiveListWidgetItem *>(sender());
261     if(archiveItem)
262     {
263         RestoreDialog *restoreDialog =
264             new RestoreDialog(this, archiveItem->archive());
265         restoreDialog->show();
266         connect(restoreDialog, &RestoreDialog::accepted, [=] {
267             emit restoreArchive(restoreDialog->archive(),
268                                 restoreDialog->getOptions());
269         });
270     }
271 }
272 
goToJob()273 void ArchiveListWidget::goToJob()
274 {
275     if(sender())
276         emit displayJobDetails(
277             qobject_cast<ArchiveListWidgetItem *>(sender())->archive()->jobRef());
278 }
279 
selectArchive(ArchivePtr archive)280 void ArchiveListWidget::selectArchive(ArchivePtr archive)
281 {
282     if(!archive)
283     {
284         DEBUG << "Null ArchivePtr passed.";
285         return;
286     }
287 
288     for(int i = 0; i < count(); ++i)
289     {
290         ArchiveListWidgetItem *archiveItem =
291             static_cast<ArchiveListWidgetItem *>(item(i));
292         if(archiveItem
293            && (archiveItem->archive()->objectKey() == archive->objectKey()))
294         {
295             clearSelection();
296             setCurrentItem(archiveItem);
297             scrollToItem(currentItem(), QAbstractItemView::EnsureVisible);
298             break;
299         }
300     }
301 }
302 
keyPressEvent(QKeyEvent * event)303 void ArchiveListWidget::keyPressEvent(QKeyEvent *event)
304 {
305     switch(event->key())
306     {
307     case Qt::Key_Delete:
308         deleteSelectedItems();
309         break;
310     case Qt::Key_Escape:
311         if(!selectedItems().isEmpty())
312             clearSelection();
313         else
314             QListWidget::keyPressEvent(event);
315         break;
316     default:
317         QListWidget::keyPressEvent(event);
318     }
319 }
320