1 | /* |
2 | This program is free software; you can redistribute it and/or modify |
3 | it under the terms of the GNU General Public License as published by |
4 | the Free Software Foundation; either version 2 of the License, or |
5 | (at your option) any later version. |
6 | */ |
7 | |
8 | /* |
9 | begin: Mit Aug 7 2002 |
10 | copyright: (C) 2002 by Dario Abatianni |
11 | email: eisfuchs@tigress.com |
12 | */ |
13 | /* |
14 | Copyright (C) 2004-2008 Shintaro Matsuoka <shin@shoegazed.org> |
15 | Copyright (C) 2009,2010 Bernd Buschinski <b.buschinski@web.de> |
16 | */ |
17 | |
18 | #include "transferpanel.h" |
19 | #include "application.h" |
20 | #include "transferdetailedinfopanel.h" |
21 | #include "transfermanager.h" |
22 | #include "transfersend.h" |
23 | #include "preferences.h" |
24 | #include "transferview.h" |
25 | #include "transferlistmodel.h" |
26 | |
27 | #include <QSplitter> |
28 | |
29 | #include <KGlobal> |
30 | #include <KMessageBox> |
31 | #include <KMenu> |
32 | #include <KRun> |
33 | #include <KAuthorized> |
34 | #include <KFileMetaInfo> |
35 | #include <KToolBar> |
36 | |
37 | namespace Konversation |
38 | { |
39 | namespace DCC |
40 | { |
41 | TransferPanel::TransferPanel(QWidget *parent) |
42 | : ChatWindow(parent) |
43 | { |
44 | setType(ChatWindow::DccTransferPanel); |
45 | setName(i18n("DCC Status" )); |
46 | |
47 | initGUI(); |
48 | |
49 | connect(Application::instance()->getDccTransferManager(), SIGNAL(newTransferAdded(Konversation::DCC::Transfer*)), |
50 | this, SLOT(slotNewTransferAdded(Konversation::DCC::Transfer*))); |
51 | } |
52 | |
53 | TransferPanel::~TransferPanel() |
54 | { |
55 | KConfigGroup config(KGlobal::config(), "DCC Settings" ); |
56 | const QByteArray state = m_splitter->saveState(); |
57 | config.writeEntry(QString("PanelSplitter" ), state.toBase64()); |
58 | } |
59 | |
60 | void TransferPanel::initGUI() |
61 | { |
62 | setSpacing(0); |
63 | m_toolBar = new KToolBar(this, true, true); |
64 | m_toolBar->setObjectName("dccstatus_toolbar" ); |
65 | |
66 | m_splitter = new QSplitter(this); |
67 | m_splitter->setOrientation(Qt::Vertical); |
68 | |
69 | m_transferView = new TransferView(m_splitter); |
70 | |
71 | connect(m_transferView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), |
72 | this, SLOT(updateButton())); |
73 | connect(m_transferView, SIGNAL(runSelectedTransfers()), |
74 | this, SLOT(runDcc())); |
75 | |
76 | // detailed info panel |
77 | m_detailPanel = new TransferDetailedInfoPanel(m_splitter); |
78 | |
79 | m_splitter->setStretchFactor(0, QSizePolicy::Expanding); |
80 | |
81 | // popup menu |
82 | m_popup = new KMenu(this); |
83 | m_selectAll = m_popup->addAction(i18n("&Select All Items" ), this, SLOT(selectAll())); |
84 | m_selectAllCompleted = m_popup->addAction(i18n("S&elect All Completed Items" ), this, SLOT(selectAllCompleted())); |
85 | m_popup->addSeparator(); // ----- |
86 | m_accept = m_popup->addAction(KIcon("media-playback-start" ), i18n("&Accept" ), this, SLOT(acceptDcc())); |
87 | m_accept->setStatusTip(i18n("Start receiving" )); |
88 | m_abort = m_popup->addAction(KIcon("process-stop" ),i18n("A&bort" ), this, SLOT(abortDcc())); |
89 | m_abort->setStatusTip(i18n("Abort the transfer(s)" )); |
90 | m_popup->addSeparator(); // ----- |
91 | m_resend = m_popup->addAction(KIcon("edit-redo" ),i18n("Resend" ), this, SLOT(resendFile())); |
92 | m_clear = m_popup->addAction(KIcon("edit-delete" ),i18nc("clear selected dcctransfer" ,"&Clear" ), this, SLOT(clearDcc())); |
93 | m_clear->setStatusTip(i18n("Clear all selected Items" )); |
94 | m_clearCompleted = m_popup->addAction(KIcon("edit-clear-list" ),i18n("Clear Completed" ), this, SLOT(clearCompletedDcc())); |
95 | m_clearCompleted->setStatusTip(i18n("Clear Completed Items" )); |
96 | m_popup->addSeparator(); // ----- |
97 | m_open = m_popup->addAction(KIcon("system-run" ), i18n("&Open File" ), this, SLOT(runDcc())); |
98 | m_open->setStatusTip(i18n("Run the file" )); |
99 | m_openLocation = m_popup->addAction(KIcon("document-open-folder" ), i18n("Open Location" ), this, SLOT(openLocation())); |
100 | m_openLocation->setStatusTip(i18n("Open the file location" )); |
101 | m_info = m_popup->addAction(KIcon("dialog-information" ), i18n("File &Information" ), this, SLOT(showFileInfo())); |
102 | |
103 | m_transferView->setContextMenuPolicy(Qt::CustomContextMenu); |
104 | connect(m_transferView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(popupRequested(QPoint))); |
105 | |
106 | // misc. |
107 | connect(m_transferView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(doubleClicked(QModelIndex))); |
108 | connect(m_transferView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), |
109 | this, SLOT(setDetailPanelItem(QItemSelection,QItemSelection))); |
110 | |
111 | m_toolBar->addAction(m_accept); |
112 | m_toolBar->addAction(m_abort); |
113 | m_toolBar->addAction(m_clear); |
114 | m_toolBar->addAction(m_clearCompleted); |
115 | m_toolBar->addAction(m_open); |
116 | m_toolBar->addAction(m_openLocation); |
117 | |
118 | KConfigGroup config(KGlobal::config(), "DCC Settings" ); |
119 | QByteArray state; |
120 | if (config.hasKey("PanelSplitter" )) |
121 | { |
122 | state = config.readEntry("PanelSplitter" , state); |
123 | state = QByteArray::fromBase64(state); |
124 | m_splitter->restoreState(state); |
125 | } |
126 | |
127 | updateButton(); |
128 | } |
129 | |
130 | void TransferPanel::slotNewTransferAdded(Transfer *transfer) |
131 | { |
132 | connect(transfer, SIGNAL(statusChanged(Konversation::DCC::Transfer*,int,int)), this, SLOT(slotTransferStatusChanged())); |
133 | m_transferView->addTransfer(transfer); |
134 | if (m_transferView->itemCount() == 1) |
135 | { |
136 | m_transferView->selectAll(); |
137 | m_detailPanel->setTransfer(transfer); |
138 | updateButton(); |
139 | } |
140 | } |
141 | |
142 | void TransferPanel::slotTransferStatusChanged() |
143 | { |
144 | updateButton(); |
145 | activateTabNotification(Konversation::tnfSystem); |
146 | } |
147 | |
148 | void TransferPanel::updateButton() |
149 | { |
150 | bool accept = false, |
151 | abort = false, |
152 | clear = false, |
153 | info = false, |
154 | open = false, |
155 | openLocation = false, |
156 | resend = false, |
157 | selectAll = false, |
158 | selectAllCompleted = false; |
159 | |
160 | QItemSelectionModel *selectionModel = m_transferView->selectionModel(); |
161 | foreach (const QModelIndex &index, m_transferView->rowIndexes()) |
162 | { |
163 | Transfer::Type type = (Transfer::Type)index.data(TransferListModel::TransferType).toInt(); |
164 | Transfer::Status status = (Transfer::Status)index.data(TransferListModel::TransferStatus).toInt(); |
165 | |
166 | selectAll = true; |
167 | selectAllCompleted |= (status >= Transfer::Done); |
168 | |
169 | if (selectionModel->isRowSelected(index.row(), QModelIndex())) |
170 | { |
171 | accept |= (status == Transfer::Queued); |
172 | |
173 | abort |= (status < Transfer::Done); |
174 | |
175 | clear |= (status >= Transfer::Done); |
176 | |
177 | info |= (type == Transfer::Send || |
178 | status == Transfer::Done); |
179 | |
180 | open |= (type == Transfer::Send || |
181 | status == Transfer::Done); |
182 | |
183 | openLocation = true; |
184 | |
185 | resend |= (type == Transfer::Send && |
186 | status >= Transfer::Done); |
187 | } |
188 | } |
189 | |
190 | if (!KAuthorized::authorizeKAction("allow_downloading" )) |
191 | { |
192 | accept = false; |
193 | } |
194 | |
195 | m_selectAll->setEnabled(selectAll); |
196 | m_selectAllCompleted->setEnabled(selectAllCompleted); |
197 | m_accept->setEnabled(accept); |
198 | m_abort->setEnabled(abort); |
199 | m_clear->setEnabled(clear); |
200 | m_clearCompleted->setEnabled(selectAllCompleted); |
201 | m_open->setEnabled(open); |
202 | m_openLocation->setEnabled(openLocation); |
203 | m_resend->setEnabled(resend); |
204 | m_info->setEnabled(info); |
205 | } |
206 | |
207 | void TransferPanel::setDetailPanelItem (const QItemSelection &/*newindex*/, const QItemSelection &/*oldindex*/) |
208 | { |
209 | QModelIndex index; |
210 | |
211 | if (m_transferView->selectionModel()->selectedRows().contains(m_transferView->selectionModel()->currentIndex())) |
212 | { |
213 | index = m_transferView->selectionModel()->currentIndex(); |
214 | } |
215 | else if (!m_transferView->selectionModel()->selectedRows().isEmpty()) |
216 | { |
217 | index = m_transferView->selectionModel()->selectedRows().first(); |
218 | } |
219 | |
220 | if (index.isValid()) |
221 | { |
222 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
223 | if (transfer) |
224 | { |
225 | m_detailPanel->setTransfer(transfer); |
226 | } |
227 | } |
228 | } |
229 | |
230 | void TransferPanel::acceptDcc() |
231 | { |
232 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
233 | { |
234 | if (index.data(TransferListModel::TransferType).toInt() == Transfer::Receive && |
235 | index.data(TransferListModel::TransferStatus).toInt() == Transfer::Queued) |
236 | { |
237 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
238 | if (transfer) |
239 | { |
240 | transfer->start(); |
241 | } |
242 | } |
243 | } |
244 | updateButton(); |
245 | } |
246 | |
247 | void TransferPanel::abortDcc() |
248 | { |
249 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
250 | { |
251 | if (index.data(TransferListModel::TransferStatus).toInt() < Transfer::Done) |
252 | { |
253 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
254 | if (transfer) |
255 | { |
256 | transfer->abort(); |
257 | } |
258 | } |
259 | } |
260 | updateButton(); |
261 | } |
262 | |
263 | void TransferPanel::resendFile() |
264 | { |
265 | QList<Transfer*> transferList; |
266 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
267 | { |
268 | if (index.data(TransferListModel::TransferType).toInt() == Transfer::Send && |
269 | index.data(TransferListModel::TransferStatus).toInt() >= Transfer::Done) |
270 | { |
271 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
272 | if (!transfer) |
273 | { |
274 | continue; |
275 | } |
276 | transferList.append(transfer); |
277 | } |
278 | } |
279 | |
280 | foreach (Transfer* transfer, transferList) |
281 | { |
282 | TransferSend *newTransfer = Application::instance()->getDccTransferManager()->newUpload(); |
283 | |
284 | newTransfer->setConnectionId(transfer->getConnectionId()); |
285 | newTransfer->setPartnerNick(transfer->getPartnerNick()); |
286 | newTransfer->setFileURL(transfer->getFileURL()); |
287 | newTransfer->setFileName(transfer->getFileName()); |
288 | newTransfer->setReverse(transfer->isReverse()); |
289 | |
290 | if (newTransfer->queue()) |
291 | { |
292 | newTransfer->start(); |
293 | } |
294 | } |
295 | } |
296 | |
297 | //sort QModelIndexList descending |
298 | bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) |
299 | { |
300 | return index1.row() >= index2.row(); |
301 | } |
302 | |
303 | void TransferPanel::clearDcc() |
304 | { |
305 | //selected item |
306 | Transfer *transfer = m_detailPanel->transfer(); |
307 | if (transfer && transfer->getStatus() >= Transfer::Done) |
308 | { |
309 | //item will be gone |
310 | transfer = 0; |
311 | } |
312 | |
313 | QModelIndexList indexes = m_transferView->selectedRows(); |
314 | QModelIndexList indexesToRemove; |
315 | |
316 | foreach (const QModelIndex &index, indexes) |
317 | { |
318 | if (index.data(TransferListModel::TransferStatus).toInt() >= Transfer::Done) |
319 | { |
320 | indexesToRemove.append(index); |
321 | } |
322 | } |
323 | |
324 | //sort QModelIndexList descending |
325 | //NOTE: selectedRows() returned an unsorted list |
326 | qSort(indexesToRemove.begin(), indexesToRemove.end(), rowGreaterThan); |
327 | |
328 | //remove from last to first item, to keep a valid row |
329 | foreach (const QModelIndex &index, indexesToRemove) |
330 | { |
331 | m_transferView->model()->removeRow(index.row(), QModelIndex()); |
332 | //needed, otherwise valid rows "can be treated" as invalid, |
333 | //proxymodel does not keep up with changes |
334 | m_transferView->updateModel(); |
335 | } |
336 | |
337 | //remove all gone items |
338 | foreach (const QModelIndex &index, indexesToRemove) |
339 | { |
340 | indexes.removeOne(index); |
341 | } |
342 | |
343 | m_transferView->clearSelection(); |
344 | QList<int> toSelectList; |
345 | //select everything that got not removed |
346 | foreach (const QModelIndex &index, indexes) |
347 | { |
348 | int offset = 0; |
349 | foreach (const QModelIndex &removedIndex, indexesToRemove) |
350 | { |
351 | if (removedIndex.row() < index.row()) |
352 | { |
353 | ++offset; |
354 | } |
355 | } |
356 | toSelectList.append(index.row() - offset); |
357 | } |
358 | m_transferView->selectRows(toSelectList); |
359 | |
360 | if (transfer) |
361 | { |
362 | m_detailPanel->setTransfer(transfer); |
363 | } |
364 | else if (!transfer || m_transferView->itemCount() == 0 || m_transferView->selectedIndexes().count() == 0) |
365 | { |
366 | m_detailPanel->clear(); |
367 | } |
368 | |
369 | updateButton(); |
370 | } |
371 | |
372 | void TransferPanel::clearCompletedDcc() |
373 | { |
374 | //save selected item |
375 | Transfer *transfer = m_detailPanel->transfer(); |
376 | if (transfer && transfer->getStatus() >= Transfer::Done) |
377 | { |
378 | //item will be gone |
379 | transfer = 0; |
380 | } |
381 | |
382 | QModelIndexList indexesToRemove; |
383 | QModelIndexList selectedIndexes = m_transferView->selectedRows(); |
384 | |
385 | foreach (const QModelIndex &index, m_transferView->rowIndexes()) |
386 | { |
387 | if (index.data(TransferListModel::TransferStatus).toInt() >= Transfer::Done) |
388 | { |
389 | indexesToRemove.append(index); |
390 | } |
391 | } |
392 | |
393 | //sort QModelIndexList descending |
394 | //NOTE: selectedRows() returned an unsorted list |
395 | qSort(indexesToRemove.begin(), indexesToRemove.end(), rowGreaterThan); |
396 | |
397 | //remove from last to first item, to keep a valid row |
398 | foreach (const QModelIndex &index, indexesToRemove) |
399 | { |
400 | m_transferView->model()->removeRow(index.row(), QModelIndex()); |
401 | //needed, otherwise valid rows "can be treated" as invalid, |
402 | //proxymodel does not keep up with changes |
403 | m_transferView->updateModel(); |
404 | } |
405 | |
406 | //remove all gone items |
407 | foreach (const QModelIndex &index, indexesToRemove) |
408 | { |
409 | selectedIndexes.removeOne(index); |
410 | } |
411 | |
412 | m_transferView->clearSelection(); |
413 | QList<int> toSelectList; |
414 | //select everything that got not removed |
415 | foreach (const QModelIndex &index, selectedIndexes) |
416 | { |
417 | int offset = 0; |
418 | foreach (const QModelIndex &removedIndex, indexesToRemove) |
419 | { |
420 | if (removedIndex.row() < index.row()) |
421 | { |
422 | ++offset; |
423 | } |
424 | } |
425 | toSelectList.append(index.row() - offset); |
426 | } |
427 | m_transferView->selectRows(toSelectList); |
428 | |
429 | if (transfer) |
430 | { |
431 | m_detailPanel->setTransfer(transfer); |
432 | } |
433 | else if (m_transferView->itemCount() == 0 || m_transferView->selectedIndexes().count() == 0 || !transfer) |
434 | { |
435 | m_detailPanel->clear(); |
436 | } |
437 | |
438 | updateButton(); |
439 | } |
440 | |
441 | void TransferPanel::runDcc() |
442 | { |
443 | const int selectedRows = m_transferView->selectedRows().count(); |
444 | if (selectedRows > 3) |
445 | { |
446 | int ret = KMessageBox::questionYesNo(this, |
447 | i18np("You have selected %1 file to execute, are you sure you want to continue?" , |
448 | "You have selected %1 files to execute, are you sure you want to continue?" , |
449 | selectedRows), |
450 | i18np("Execute %1 file" , |
451 | "Execute %1 files" , |
452 | selectedRows) |
453 | ); |
454 | |
455 | if (ret == KMessageBox::No) |
456 | { |
457 | return; |
458 | } |
459 | } |
460 | |
461 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
462 | { |
463 | if (index.data(TransferListModel::TransferType).toInt() == Transfer::Send || |
464 | index.data(TransferListModel::TransferStatus).toInt() == Transfer::Done) |
465 | { |
466 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
467 | if (transfer) |
468 | { |
469 | transfer->runFile(); |
470 | } |
471 | } |
472 | } |
473 | } |
474 | |
475 | void TransferPanel::openLocation() |
476 | { |
477 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
478 | { |
479 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
480 | if (transfer) |
481 | { |
482 | openLocation(transfer); |
483 | } |
484 | } |
485 | } |
486 | |
487 | void TransferPanel::showFileInfo() |
488 | { |
489 | foreach (const QModelIndex &index, m_transferView->selectedRows()) |
490 | { |
491 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
492 | if (transfer) |
493 | { |
494 | openFileInfoDialog(transfer); |
495 | } |
496 | } |
497 | } |
498 | |
499 | void TransferPanel::selectAll() |
500 | { |
501 | m_transferView->selectAll(); |
502 | updateButton(); |
503 | } |
504 | |
505 | void TransferPanel::selectAllCompleted() |
506 | { |
507 | m_transferView->selectAllCompleted(); |
508 | updateButton(); |
509 | } |
510 | |
511 | void TransferPanel::(const QPoint &pos) |
512 | { |
513 | updateButton(); |
514 | m_popup->popup(QWidget::mapToGlobal(m_transferView->viewport()->mapTo(this, pos))); |
515 | } |
516 | |
517 | void TransferPanel::doubleClicked(const QModelIndex &index) |
518 | { |
519 | Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer))); |
520 | if (transfer) |
521 | { |
522 | transfer->runFile(); |
523 | } |
524 | } |
525 | |
526 | // virtual |
527 | void TransferPanel::childAdjustFocus() |
528 | { |
529 | } |
530 | |
531 | TransferView *TransferPanel::getTransferView() |
532 | { |
533 | return m_transferView; |
534 | } |
535 | |
536 | void TransferPanel::openLocation(Transfer *transfer) |
537 | { |
538 | QString urlString = transfer->getFileURL().path(); |
539 | if (!urlString.isEmpty()) |
540 | { |
541 | KUrl url(urlString); |
542 | url.setFileName(QString()); |
543 | new KRun(url, 0, 0, true, true); |
544 | } |
545 | } |
546 | |
547 | void TransferPanel::openFileInfoDialog(Transfer *transfer) |
548 | { |
549 | if (transfer->getType() == Transfer::Send || transfer->getStatus() == Transfer::Done) |
550 | { |
551 | QPointer<FileMetaDataDialog> fileDialog = new FileMetaDataDialog(transfer->getFileURL(), this); |
552 | fileDialog->exec(); |
553 | delete fileDialog; |
554 | } |
555 | } |
556 | |
557 | } |
558 | } |
559 | |
560 | #include "transferpanel.moc" |
561 | |