Fix krazy2 errors(spelling, crashy, explicit) introduced by
[konversation:agateau-konversation.git] / src / dcc / transferpanel.cpp
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 (const QPoint&)), this, SLOT(popupRequested (const QPoint&)));
105
106             // misc.
107             connect(m_transferView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(doubleClicked(const QModelIndex&)));
108             connect(m_transferView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
109                     this, SLOT(setDetailPanelItem (const QItemSelection&, const 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
289                 if (newTransfer->queue())
290                 {
291                     newTransfer->start();
292                 }
293             }
294         }
295
296         //sort QModelIndexList descending
297         bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2)
298         {
299             return index1.row() >= index2.row();
300         }
301
302         void TransferPanel::clearDcc()
303         {
304             //selected item
305             Transfer *transfer = m_detailPanel->transfer();
306             if (transfer && transfer->getStatus() >= Transfer::Done)
307             {
308                 //item will be gone
309                 transfer = 0;
310             }
311
312             QModelIndexList indexes = m_transferView->selectedRows();
313             QModelIndexList indexesToRemove;
314
315             foreach (const QModelIndex &index, indexes)
316             {
317                 if (index.data(TransferListModel::TransferStatus).toInt() >= Transfer::Done)
318                 {
319                     indexesToRemove.append(index);
320                 }
321             }
322
323             //sort QModelIndexList descending
324             //NOTE: selectedRows() returned an unsorted list
325             qSort(indexesToRemove.begin(), indexesToRemove.end(), rowGreaterThan);
326
327             //remove from last to first item, to keep a valid row
328             foreach (const QModelIndex &index, indexesToRemove)
329             {
330                 m_transferView->model()->removeRow(index.row(), QModelIndex());
331                 //needed, otherwise valid rows "can be treated" as invalid,
332                 //proxymodel does not keep up with changes
333                 m_transferView->updateModel();
334             }
335
336             //remove all gone items
337             foreach (const QModelIndex &index, indexesToRemove)
338             {
339                 indexes.removeOne(index);
340             }
341
342             m_transferView->clearSelection();
343             QList<int> toSelectList;
344             //select everything that got not removed
345             foreach (const QModelIndex &index, indexes)
346             {
347                 int offset = 0;
348                 foreach (const QModelIndex &removedIndex, indexesToRemove)
349                 {
350                     if (removedIndex.row() < index.row())
351                     {
352                         ++offset;
353                     }
354                 }
355                 toSelectList.append(index.row() - offset);
356             }
357             m_transferView->selectRows(toSelectList);
358
359             if (transfer)
360             {
361                 m_detailPanel->setTransfer(transfer);
362             }
363             else if (!transfer || m_transferView->itemCount() == 0 || m_transferView->selectedIndexes().count() == 0)
364             {
365                 m_detailPanel->clear();
366             }
367
368             updateButton();
369         }
370
371         void TransferPanel::clearCompletedDcc()
372         {
373             //save selected item
374             Transfer *transfer = m_detailPanel->transfer();
375             if (transfer && transfer->getStatus() >= Transfer::Done)
376             {
377                 //item will be gone
378                 transfer = 0;
379             }
380
381             QModelIndexList indexesToRemove;
382             QModelIndexList selectedIndexes = m_transferView->selectedRows();
383
384             foreach (const QModelIndex &index, m_transferView->rowIndexes())
385             {
386                 if (index.data(TransferListModel::TransferStatus).toInt() >= Transfer::Done)
387                 {
388                     indexesToRemove.append(index);
389                 }
390             }
391
392             //sort QModelIndexList descending
393             //NOTE: selectedRows() returned an unsorted list
394             qSort(indexesToRemove.begin(), indexesToRemove.end(), rowGreaterThan);
395
396             //remove from last to first item, to keep a valid row
397             foreach (const QModelIndex &index, indexesToRemove)
398             {
399                 m_transferView->model()->removeRow(index.row(), QModelIndex());
400                 //needed, otherwise valid rows "can be treated" as invalid,
401                 //proxymodel does not keep up with changes
402                 m_transferView->updateModel();
403             }
404
405             //remove all gone items
406             foreach (const QModelIndex &index, indexesToRemove)
407             {
408                 selectedIndexes.removeOne(index);
409             }
410
411             m_transferView->clearSelection();
412             QList<int> toSelectList;
413             //select everything that got not removed
414             foreach (const QModelIndex &index, selectedIndexes)
415             {
416                 int offset = 0;
417                 foreach (const QModelIndex &removedIndex, indexesToRemove)
418                 {
419                     if (removedIndex.row() < index.row())
420                     {
421                         ++offset;
422                     }
423                 }
424                 toSelectList.append(index.row() - offset);
425             }
426             m_transferView->selectRows(toSelectList);
427
428             if (transfer)
429             {
430                 m_detailPanel->setTransfer(transfer);
431             }
432             else if (m_transferView->itemCount() == 0 || m_transferView->selectedIndexes().count() == 0 || !transfer)
433             {
434                 m_detailPanel->clear();
435             }
436
437             updateButton();
438         }
439
440         void TransferPanel::runDcc()
441         {
442             const int selectedRows = m_transferView->selectedRows().count();
443             if (selectedRows > 3)
444             {
445                 int ret = KMessageBox::questionYesNo(this,
446                                                      i18np("You have selected %1 file to execute, are you sure you want to continue?",
447                                                            "You have selected %1 files to execute, are you sure you want to continue?",
448                                                            selectedRows),
449                                                      i18np("Execute %1 file",
450                                                            "Execute %1 files",
451                                                            selectedRows)
452                                                      );
453
454                 if (ret == KMessageBox::No)
455                 {
456                     return;
457                 }
458             }
459
460             foreach (const QModelIndex &index, m_transferView->selectedRows())
461             {
462                 if (index.data(TransferListModel::TransferType).toInt() == Transfer::Send ||
463                     index.data(TransferListModel::TransferStatus).toInt() == Transfer::Done)
464                 {
465                     Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer)));
466                     if (transfer)
467                     {
468                         runFile(transfer);
469                     }
470                 }
471             }
472         }
473
474         void TransferPanel::openLocation()
475         {
476             foreach (const QModelIndex &index, m_transferView->selectedRows())
477             {
478                 Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer)));
479                 if (transfer)
480                 {
481                     openLocation(transfer);
482                 }
483             }
484         }
485
486         void TransferPanel::showFileInfo()
487         {
488             foreach (const QModelIndex &index, m_transferView->selectedRows())
489             {
490                 Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer)));
491                 if (transfer)
492                 {
493                     openFileInfoDialog(transfer);
494                 }
495             }
496         }
497
498         void TransferPanel::selectAll()
499         {
500             m_transferView->selectAll();
501             updateButton();
502         }
503
504         void TransferPanel::selectAllCompleted()
505         {
506             m_transferView->selectAllCompleted();
507             updateButton();
508         }
509
510         void TransferPanel::popupRequested(const QPoint &pos)
511         {
512             updateButton();
513             m_popup->popup(QWidget::mapToGlobal(pos));
514         }
515
516         void TransferPanel::doubleClicked(const QModelIndex &index)
517         {
518             Transfer *transfer = static_cast<Transfer*>(qVariantValue<QObject*>(index.data(TransferListModel::TransferPointer)));
519             if (transfer)
520             {
521                 runFile(transfer);
522             }
523         }
524
525         // virtual
526         void TransferPanel::childAdjustFocus()
527         {
528         }
529
530         TransferView *TransferPanel::getTransferView()
531         {
532             return m_transferView;
533         }
534
535         void TransferPanel::runFile(Transfer *transfer)
536         {
537             if (transfer->getType() == Transfer::Send || transfer->getStatus() == Transfer::Done)
538             {
539                 new KRun(transfer->getFileURL(), getTransferView());
540             }
541         }
542
543         void TransferPanel::openLocation(Transfer *transfer)
544         {
545             QString urlString = transfer->getFileURL().path();
546             if (!urlString.isEmpty())
547             {
548                 KUrl url(urlString);
549                 url.setFileName(QString());
550                 new KRun(url, 0, 0, true, true);
551             }
552         }
553
554         void TransferPanel::openFileInfoDialog(Transfer *transfer)
555         {
556             if (transfer->getType() == Transfer::Send || transfer->getStatus() == Transfer::Done)
557             {
558 #if KDE_IS_VERSION(4, 5, 0)
559                 QPointer<FileMetaDataDialog> fileDialog = new FileMetaDataDialog(transfer->getFileURL(), this);
560                 fileDialog->exec();
561                 delete fileDialog;
562 #else
563                 QStringList infoList;
564
565                 QString path = transfer->getFileURL().path();
566
567                 // get meta info object
568                 KFileMetaInfo fileMetaInfo(path, QString(), KFileMetaInfo::Everything);
569
570                 // is there any info for this file?
571                 if (fileMetaInfo.isValid())
572                 {
573                     const QHash<QString, KFileMetaInfoItem>& items = fileMetaInfo.items();
574                     QHash<QString, KFileMetaInfoItem>::const_iterator it = items.constBegin();
575                     const QHash<QString, KFileMetaInfoItem>::const_iterator end = items.constEnd();
576                     while (it != end)
577                     {
578                         const KFileMetaInfoItem &metaInfoItem = it.value();
579                         const QVariant &value = metaInfoItem.value();
580                         if (value.isValid())
581                         {
582                             // append item information to list
583                             infoList.append("- " + metaInfoItem.name() + ' ' + value.toString());
584                         }
585                         ++it;
586                     }
587
588                     // display information list if any available
589                     if(infoList.count())
590                     {
591                         KMessageBox::information(
592                             getTransferView(),
593                             "<qt>"+infoList.join("<br>")+"</qt>",
594                             i18n("File Information")
595                             );
596                     }
597                 }
598                 else
599                 {
600                     KMessageBox::sorry(getTransferView(), i18n("No detailed information for this file found."), i18n("File Information"));
601                 }
602 #endif
603             }
604         }
605
606     }
607 }
608
609 #include "transferpanel.moc"