00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "trash.h"
00021
00022
00023 #include <QGraphicsSceneDragDropEvent>
00024 #include <QApplication>
00025 #include <QGraphicsLinearLayout>
00026
00027
00028 #include <KGlobalSettings>
00029 #include <KCModuleProxy>
00030 #include <KConfigDialog>
00031 #include <KDebug>
00032 #include <KLocale>
00033 #include <KIconLoader>
00034 #include <KMimeType>
00035 #include <KRun>
00036 #include <KSharedConfig>
00037 #include <KMessageBox>
00038 #include <KUrl>
00039 #include <KProcess>
00040 #include <KStandardDirs>
00041
00042 #include <kfileplacesmodel.h>
00043 #include <KIO/CopyJob>
00044 #include <KIO/JobUiDelegate>
00045
00046
00047 #include <Plasma/IconWidget>
00048 #include <Plasma/Containment>
00049 #include <Plasma/ToolTipManager>
00050
00051
00052 #include <solid/devicenotifier.h>
00053 #include <solid/device.h>
00054 #include <solid/deviceinterface.h>
00055 #include <solid/predicate.h>
00056 #include <solid/storageaccess.h>
00057 #include <solid/opticaldrive.h>
00058 #include <solid/opticaldisc.h>
00059
00060
00061 Trash::Trash(QObject *parent, const QVariantList &args)
00062 : Plasma::Applet(parent, args),
00063 m_icon(0),
00064 m_dirLister(0),
00065 emptyTrash(0),
00066 m_count(0),
00067 m_showText(false),
00068 m_places(0),
00069 m_proxy(0),
00070 m_emptyProcess(0)
00071 {
00072 setHasConfigurationInterface(true);
00073 setAspectRatioMode(Plasma::ConstrainedSquare);
00074
00075 m_icon = new Plasma::IconWidget(KIcon("user-trash"),QString(),this);
00076 m_icon->setNumDisplayLines(2);
00077 m_icon->setDrawBackground(true);
00078
00079 resize(m_icon->sizeFromIconSize(IconSize(KIconLoader::Desktop)));
00080 createMenu();
00081 }
00082
00083 Trash::~Trash()
00084 {
00085 }
00086
00087 void Trash::init()
00088 {
00089 registerAsDragHandle(m_icon);
00090
00091 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
00092 layout->setContentsMargins(0, 0, 0, 0);
00093 layout->setSpacing(0);
00094 layout->addItem(m_icon);
00095
00096 setAcceptDrops(true);
00097
00098 m_dirLister = new KDirLister();
00099 connect( m_dirLister, SIGNAL( clear() ),
00100 this, SLOT( slotClear() ) );
00101 connect( m_dirLister, SIGNAL( completed() ),
00102 this, SLOT( slotCompleted() ) );
00103 connect( m_dirLister, SIGNAL( deleteItem( const KFileItem & ) ),
00104 this, SLOT( slotDeleteItem( const KFileItem & ) ) );
00105
00106 m_dirLister->openUrl(KUrl("trash:/"));
00107
00108 connect(m_icon, SIGNAL(activated()), this, SLOT(slotOpen()));
00109 }
00110
00111 void Trash::createConfigurationInterface(KConfigDialog *parent)
00112 {
00113 m_proxy = new KCModuleProxy("kcmtrash");
00114
00115 parent->addPage(m_proxy, i18n("Trash"), icon());
00116 connect(parent, SIGNAL(okClicked()), this, SLOT(slotApplyConfig()));
00117
00118 m_proxy->load();
00119 }
00120
00121 void Trash::createMenu()
00122 {
00123 QAction* open = new QAction(SmallIcon("document-open"),i18n("&Open"), this);
00124 actions.append(open);
00125 connect(open, SIGNAL(triggered(bool)), this , SLOT(slotOpen()));
00126
00127 emptyTrash = new QAction(SmallIcon("trash-empty"),i18n("&Empty Trashcan"), this);
00128 actions.append(emptyTrash);
00129 connect(emptyTrash, SIGNAL(triggered(bool)), this , SLOT(slotEmpty()));
00130
00131 m_menu.addTitle(i18n("Trash"));
00132 m_menu.addAction(open);
00133 m_menu.addAction(emptyTrash);
00134
00135
00136 QAction* menu = new QAction(SmallIcon("arrow-up-double"),i18n("&Menu"), this);
00137 connect(menu, SIGNAL(triggered(bool)), this , SLOT(popup()));
00138 m_icon->addIconAction(menu);
00139
00140 connect(&m_menu, SIGNAL(aboutToHide()), m_icon, SLOT(setUnpressed()));
00141 }
00142
00143 void Trash::popup()
00144 {
00145 if (m_menu.isVisible()) {
00146 m_menu.hide();
00147 return;
00148 }
00149 m_menu.popup(popupPosition(m_menu.sizeHint()));
00150 m_icon->setPressed();
00151 }
00152
00153 void Trash::constraintsEvent(Plasma::Constraints constraints)
00154 {
00155 setBackgroundHints(NoBackground);
00156
00157 if (constraints & Plasma::FormFactorConstraint) {
00158 disconnect(m_icon, SIGNAL(activated()), this, SLOT(slotOpen()));
00159 disconnect(m_icon, SIGNAL(clicked()), this, SLOT(slotOpen()));
00160
00161 if (formFactor() == Plasma::Planar ||
00162 formFactor() == Plasma::MediaCenter) {
00163
00164 connect(m_icon, SIGNAL(activated()), this, SLOT(slotOpen()));
00165
00166 m_icon->setText(i18n("Trash"));
00167 m_icon->setInfoText(i18np("One item", "%1 items", m_count));
00168 m_showText = true;
00169 m_icon->setDrawBackground(true);
00170
00171 setMinimumSize(m_icon->sizeFromIconSize(IconSize(KIconLoader::Desktop))+=QSizeF(20,0));
00172 } else {
00173
00174 connect(m_icon, SIGNAL(clicked()), this, SLOT(slotOpen()));
00175
00176 m_icon->setText(0);
00177 m_icon->setInfoText(0);
00178 m_showText = false;
00179 m_icon->setDrawBackground(false);
00180
00181 setMinimumSize(m_icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
00182 }
00183 updateIcon();
00184 }
00185 }
00186
00187 void Trash::slotOpen()
00188 {
00189 emit releaseVisualFocus();
00190 KRun::runUrl(KUrl("trash:/"), "inode/directory", 0);
00191 }
00192
00193 void Trash::slotEmpty()
00194 {
00195 if (m_emptyProcess) {
00196
00197 delete m_emptyProcess;
00198 m_emptyProcess = 0;
00199 }
00200
00201 emit releaseVisualFocus();
00202 const QString text(i18nc("@info", "Do you really want to empty the trash? All items will be deleted."));
00203
00204 const bool del = KMessageBox::warningContinueCancel(&m_menu,
00205 text,
00206 QString(),
00207 KGuiItem(i18nc("@action:button", "Empty Trash"),
00208 KIcon("user-trash"))
00209 ) == KMessageBox::Continue;
00210
00211 if (del) {
00212
00213
00214
00215 m_emptyProcess = new KProcess(this);
00216 connect(m_emptyProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
00217 this, SLOT(emptyFinished(int,QProcess::ExitStatus)));
00218 (*m_emptyProcess) << KStandardDirs::findExe("ktrash") << "--empty";
00219 m_emptyProcess->start();
00220 }
00221 }
00222
00223 void Trash::emptyFinished(int exitCode, QProcess::ExitStatus exitStatus)
00224 {
00225 Q_UNUSED(exitCode)
00226 Q_UNUSED(exitStatus)
00227
00228 delete m_emptyProcess;
00229 m_emptyProcess = 0;
00230 }
00231
00232 void Trash::updateIcon()
00233 {
00234 Plasma::ToolTipContent data;
00235 data.setMainText(i18n("Trash"));
00236
00237 if (m_count > 0) {
00238 m_icon->setIcon(KIcon("user-trash-full"));
00239
00240 data.setSubText(i18np("One item", "%1 items", m_count));
00241 if (m_showText) {
00242 m_icon->setInfoText(i18np("One item", "%1 items", m_count));
00243 }
00244 } else {
00245 m_icon->setIcon(KIcon("user-trash"));
00246
00247 data.setSubText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
00248 if (m_showText) {
00249 m_icon->setInfoText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
00250 }
00251 }
00252
00253 m_icon->update();
00254
00255 data.setImage(m_icon->icon().pixmap(IconSize(KIconLoader::Desktop)));
00256
00257 if (!m_showText) {
00258 Plasma::ToolTipManager::self()->setContent(this, data);
00259 } else {
00260 Plasma::ToolTipManager::self()->clearContent(this);
00261 }
00262
00263 emptyTrash->setEnabled(m_count > 0);
00264 }
00265
00266 void Trash::slotClear()
00267 {
00268 m_count = 0;
00269 updateIcon();
00270 }
00271
00272 void Trash::slotCompleted()
00273 {
00274 m_count = m_dirLister->items(KDirLister::AllItems).count();
00275 updateIcon();
00276 }
00277
00278 void Trash::slotDeleteItem(const KFileItem &)
00279 {
00280 m_count--;
00281 updateIcon();
00282 }
00283
00284 void Trash::slotApplyConfig()
00285 {
00286 m_proxy->save();
00287 }
00288
00289 QList<QAction*> Trash::contextualActions()
00290 {
00291 return actions;
00292 }
00293
00294 void Trash::dropEvent(QGraphicsSceneDragDropEvent *event)
00295 {
00296 if (KUrl::List::canDecode(event->mimeData())) {
00297 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00298 if (urls.count() > 0) {
00299 event->accept();
00300
00301
00302 bool specialOperation = false;
00303
00304 if (!m_places) {
00305 m_places = new KFilePlacesModel(this);
00306 }
00307
00308 foreach (const KUrl& url, urls) {
00309 const Solid::Predicate predicate(Solid::DeviceInterface::StorageAccess, "filePath", url.path());
00310
00311
00312 const QList<Solid::Device> devList = Solid::Device::listFromQuery(predicate, QString());
00313
00314
00315
00316 const QModelIndex index = m_places->closestItem(url);
00317
00318 if (devList.count() > 0) {
00319
00320 Solid::Device device = devList.first();
00321
00322 if (device.is<Solid::OpticalDisc>()) {
00323 device.parent().as<Solid::OpticalDrive>()->eject();
00324 } else {
00325 device.as<Solid::StorageAccess>()->teardown();
00326 }
00327
00328 specialOperation = true;
00329
00330 } else if (m_places->bookmarkForIndex(index).url() == url) {
00331 m_places->removePlace(index);
00332 specialOperation = true;
00333 }
00334 }
00335
00336
00337 if (!specialOperation) {
00338 KIO::Job* job = KIO::trash(urls);
00339 job->ui()->setWindow(0);
00340 job->ui()->setAutoErrorHandlingEnabled(true);
00341 }
00342 }
00343 }
00344 }
00345
00346 #include "trash.moc"
00347