1 #include "backuplistwidget.h"
2 #include "backuplistwidgetitem.h"
3 #include "debug.h"
4 #include "utils.h"
5 
6 #include <QDropEvent>
7 #include <QFileInfo>
8 #include <QMessageBox>
9 #include <QMimeData>
10 #include <QSettings>
11 
BackupListWidget(QWidget * parent)12 BackupListWidget::BackupListWidget(QWidget *parent) : QListWidget(parent)
13 {
14     QSettings   settings;
15     QStringList urls = settings.value("app/backup_list").toStringList();
16     if(!urls.isEmpty())
17     {
18         QList<QUrl> urllist;
19         foreach(QString url, urls)
20             urllist << QUrl::fromUserInput(url);
21         if(!urllist.isEmpty())
22             QMetaObject::invokeMethod(this, "addItemsWithUrls", QUEUED,
23                                       Q_ARG(QList<QUrl>, urllist));
24     }
25     connect(this, &QListWidget::itemActivated, [&](QListWidgetItem *item) {
26         static_cast<BackupListWidgetItem *>(item)->browseUrl();
27     });
28 }
29 
~BackupListWidget()30 BackupListWidget::~BackupListWidget()
31 {
32     QStringList urls;
33     for(int i = 0; i < count(); ++i)
34     {
35         BackupListWidgetItem *backupItem =
36             static_cast<BackupListWidgetItem *>(item(i));
37         urls << backupItem->url().toString(QUrl::FullyEncoded);
38     }
39     QSettings settings;
40     settings.setValue("app/backup_list", urls);
41     settings.sync();
42     clear();
43 }
44 
addItemWithUrl(QUrl url)45 void BackupListWidget::addItemWithUrl(QUrl url)
46 {
47     if(url.isEmpty())
48         return;
49 
50     QString fileUrl = url.toLocalFile();
51     if(fileUrl.isEmpty())
52         return;
53     QFileInfo file(fileUrl);
54     if(!file.exists())
55         return;
56 
57     QList<QUrl> urls    = itemUrls();
58     bool        matches = false;
59     foreach(QUrl existingUrl, urls)
60     {
61         if(url == existingUrl)
62         {
63             matches = true;
64             break;
65         }
66         QFileInfo existingFile(existingUrl.toLocalFile());
67         if(existingFile.isDir()
68            && fileUrl.startsWith(existingFile.absoluteFilePath()))
69         {
70             matches = true;
71             break;
72         }
73     }
74 
75     if(matches)
76     {
77         auto confirm =
78             QMessageBox::question(this, tr("Confirm action"),
79                                   tr("The file or directory:\n    %1\n"
80                                      "was already in the backup list;"
81                                      " adding it again will have no effect.\n"
82                                      "Add anyway?")
83                                       .arg(url.toLocalFile()));
84         if(confirm == QMessageBox::No)
85             return;
86     }
87 
88     BackupListWidgetItem *item = new BackupListWidgetItem(url);
89     connect(item, &BackupListWidgetItem::requestDelete, this,
90             &BackupListWidget::removeItems);
91     connect(item, &BackupListWidgetItem::requestUpdate, this,
92             &BackupListWidget::recomputeListTotals);
93     insertItem(count(), item);
94     setItemWidget(item, item->widget());
95     emit itemWithUrlAdded(url);
96 }
97 
addItemsWithUrls(QList<QUrl> urls)98 void BackupListWidget::addItemsWithUrls(QList<QUrl> urls)
99 {
100     setUpdatesEnabled(false);
101     foreach(QUrl url, urls)
102         addItemWithUrl(url);
103     recomputeListTotals();
104     setUpdatesEnabled(true);
105 }
106 
setItemsWithUrls(QList<QUrl> urls)107 void BackupListWidget::setItemsWithUrls(QList<QUrl> urls)
108 {
109     setUpdatesEnabled(false);
110     clear();
111     setUpdatesEnabled(true);
112     addItemsWithUrls(urls);
113 }
114 
itemUrls()115 QList<QUrl> BackupListWidget::itemUrls()
116 {
117     QList<QUrl> urls;
118     for(int i = 0; i < count(); ++i)
119     {
120         BackupListWidgetItem *backupItem =
121             static_cast<BackupListWidgetItem *>(item(i));
122         urls << backupItem->url().toString(QUrl::FullyEncoded);
123     }
124     return urls;
125 }
126 
removeItems()127 void BackupListWidget::removeItems()
128 {
129     setUpdatesEnabled(false);
130     if(selectedItems().count() == 0)
131     {
132         // attempt to remove the sender
133         BackupListWidgetItem *backupItem =
134             qobject_cast<BackupListWidgetItem *>(sender());
135         if(backupItem)
136             delete backupItem;
137     }
138     else
139     {
140         foreach(QListWidgetItem *item, selectedItems())
141         {
142             if(item && item->isSelected())
143                 delete item;
144         }
145     }
146     setUpdatesEnabled(true);
147     recomputeListTotals();
148 }
149 
recomputeListTotals()150 void BackupListWidget::recomputeListTotals()
151 {
152     quint64 items = 0;
153     quint64 size  = 0;
154     for(int i = 0; i < count(); ++i)
155     {
156         BackupListWidgetItem *backupItem =
157             static_cast<BackupListWidgetItem *>(item(i));
158         if(backupItem && (backupItem->count() != 0))
159         {
160             items += backupItem->count();
161             size  += backupItem->size();
162         }
163     }
164     emit itemTotals(items, size);
165 }
166 
dragMoveEvent(QDragMoveEvent * event)167 void BackupListWidget::dragMoveEvent(QDragMoveEvent *event)
168 {
169     if(!event->mimeData()->hasUrls())
170     {
171         event->ignore();
172         return;
173     }
174     event->accept();
175 }
176 
dragEnterEvent(QDragEnterEvent * event)177 void BackupListWidget::dragEnterEvent(QDragEnterEvent *event)
178 {
179     if(event->mimeData()->hasUrls())
180         event->acceptProposedAction();
181 }
182 
dropEvent(QDropEvent * event)183 void BackupListWidget::dropEvent(QDropEvent *event)
184 {
185     QList<QUrl> urls = event->mimeData()->urls();
186     if(!urls.isEmpty())
187         addItemsWithUrls(urls);
188 
189     event->acceptProposedAction();
190 }
191 
keyPressEvent(QKeyEvent * event)192 void BackupListWidget::keyPressEvent(QKeyEvent *event)
193 {
194     switch(event->key())
195     {
196     case Qt::Key_Delete:
197     case Qt::Key_Backspace:
198         removeItems();
199         break;
200     case Qt::Key_Escape:
201         if(!selectedItems().isEmpty())
202             clearSelection();
203         else
204             QListWidget::keyPressEvent(event);
205         break;
206     default:
207         QListWidget::keyPressEvent(event);
208     }
209 }
210 
changeEvent(QEvent * event)211 void BackupListWidget::changeEvent(QEvent *event)
212 {
213     if(event->type() == QEvent::LanguageChange)
214         recomputeListTotals();
215     QWidget::changeEvent(event);
216 }
217