1 /***************************************************************************
2 * Copyright 2007 by Marco Martin <notmart@gmail.com> *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
18 ***************************************************************************/
23 #include <QGraphicsSceneDragDropEvent>
24 #include <QApplication>
25 #include <QGraphicsLinearLayout>
28 #include <KGlobalSettings>
29 #include <KCModuleProxy>
30 #include <KConfigDialog>
33 #include <KIconLoader>
36 #include <KSharedConfig>
37 #include <KMessageBox>
40 #include <KStandardDirs>
42 #include <kfileplacesmodel.h>
43 #include <KIO/CopyJob>
44 #include <KIO/JobUiDelegate>
47 #include <Plasma/IconWidget>
48 #include <Plasma/Containment>
49 #include <Plasma/ToolTipManager>
52 #include <solid/devicenotifier.h>
53 #include <solid/device.h>
54 #include <solid/deviceinterface.h>
55 #include <solid/predicate.h>
56 #include <solid/storageaccess.h>
57 #include <solid/opticaldrive.h>
58 #include <solid/opticaldisc.h>
61 Trash::Trash(QObject
*parent
, const QVariantList
&args
)
62 : Plasma::Applet(parent
, args
),
72 setHasConfigurationInterface(true);
73 setAspectRatioMode(Plasma::ConstrainedSquare
);
75 m_icon
= new Plasma::IconWidget(KIcon("user-trash"),QString(),this);
76 m_icon
->setNumDisplayLines(2);
77 m_icon
->setDrawBackground(true);
79 resize(m_icon
->sizeFromIconSize(IconSize(KIconLoader::Desktop
)));
89 registerAsDragHandle(m_icon
);
91 QGraphicsLinearLayout
*layout
= new QGraphicsLinearLayout(this);
92 layout
->setContentsMargins(0, 0, 0, 0);
93 layout
->setSpacing(0);
94 layout
->addItem(m_icon
);
98 m_dirLister
= new KDirLister();
99 connect( m_dirLister
, SIGNAL( clear() ),
100 this, SLOT( slotClear() ) );
101 connect( m_dirLister
, SIGNAL( completed() ),
102 this, SLOT( slotCompleted() ) );
103 connect( m_dirLister
, SIGNAL( deleteItem( const KFileItem
& ) ),
104 this, SLOT( slotDeleteItem( const KFileItem
& ) ) );
106 m_dirLister
->openUrl(KUrl("trash:/"));
108 connect(m_icon
, SIGNAL(activated()), this, SLOT(slotOpen()));
111 void Trash::createConfigurationInterface(KConfigDialog
*parent
)
113 m_proxy
= new KCModuleProxy("kcmtrash");
115 parent
->addPage(m_proxy
, i18n("Trash"), icon());
116 connect(parent
, SIGNAL(okClicked()), this, SLOT(slotApplyConfig()));
121 void Trash::createMenu()
123 QAction
* open
= new QAction(SmallIcon("document-open"),i18n("&Open"), this);
124 actions
.append(open
);
125 connect(open
, SIGNAL(triggered(bool)), this , SLOT(slotOpen()));
127 emptyTrash
= new QAction(SmallIcon("trash-empty"),i18n("&Empty Trashcan"), this);
128 actions
.append(emptyTrash
);
129 connect(emptyTrash
, SIGNAL(triggered(bool)), this , SLOT(slotEmpty()));
131 m_menu
.addTitle(i18n("Trash"));
132 m_menu
.addAction(open
);
133 m_menu
.addAction(emptyTrash
);
135 //add the menu as an action icon
136 QAction
* menu
= new QAction(SmallIcon("arrow-up-double"),i18n("&Menu"), this);
137 connect(menu
, SIGNAL(triggered(bool)), this , SLOT(popup()));
138 m_icon
->addIconAction(menu
);
140 connect(&m_menu
, SIGNAL(aboutToHide()), m_icon
, SLOT(setUnpressed()));
145 if (m_menu
.isVisible()) {
149 m_menu
.popup(popupPosition(m_menu
.sizeHint()));
150 m_icon
->setPressed();
153 void Trash::constraintsEvent(Plasma::Constraints constraints
)
155 setBackgroundHints(NoBackground
);
157 if (constraints
& Plasma::FormFactorConstraint
) {
158 disconnect(m_icon
, SIGNAL(activated()), this, SLOT(slotOpen()));
159 disconnect(m_icon
, SIGNAL(clicked()), this, SLOT(slotOpen()));
161 if (formFactor() == Plasma::Planar
||
162 formFactor() == Plasma::MediaCenter
) {
164 connect(m_icon
, SIGNAL(activated()), this, SLOT(slotOpen()));
166 m_icon
->setText(i18n("Trash"));
167 m_icon
->setInfoText(i18np("One item", "%1 items", m_count
));
169 m_icon
->setDrawBackground(true);
170 //Adding an arbitrary width to make room for a larger count of items
171 setMinimumSize(m_icon
->sizeFromIconSize(IconSize(KIconLoader::Desktop
))+=QSizeF(20,0));
173 //in a panel the icon always behaves like a button
174 connect(m_icon
, SIGNAL(clicked()), this, SLOT(slotOpen()));
177 m_icon
->setInfoText(0);
179 m_icon
->setDrawBackground(false);
181 setMinimumSize(m_icon
->sizeFromIconSize(IconSize(KIconLoader::Small
)));
187 void Trash::slotOpen()
189 emit
releaseVisualFocus();
190 KRun::runUrl(KUrl("trash:/"), "inode/directory", 0);
193 void Trash::slotEmpty()
195 if (m_emptyProcess
) {
196 //FIXME 4.3: Instead, tell the user the trash is still being empties and just return
197 delete m_emptyProcess
;
201 emit
releaseVisualFocus();
202 const QString
text(i18nc("@info", "Do you really want to empty the trash? All items will be deleted."));
203 //FIXME: should use KMessageBox::createKMessageBox so that it doesn't block the whole app!
204 const bool del
= KMessageBox::warningContinueCancel(&m_menu
,
207 KGuiItem(i18nc("@action:button", "Empty Trash"),
209 ) == KMessageBox::Continue
;
212 // We can't use KonqOperations here. To avoid duplicating its code (small, though),
213 // we can simply call ktrash.
214 //KonqOperations::emptyTrash(&m_menu);
215 m_emptyProcess
= new KProcess(this);
216 connect(m_emptyProcess
, SIGNAL(finished(int,QProcess::ExitStatus
)),
217 this, SLOT(emptyFinished(int,QProcess::ExitStatus
)));
218 (*m_emptyProcess
) << KStandardDirs::findExe("ktrash") << "--empty";
219 m_emptyProcess
->start();
223 void Trash::emptyFinished(int exitCode
, QProcess::ExitStatus exitStatus
)
227 //TODO: check the exit status and let the user know if it fails
228 delete m_emptyProcess
;
232 void Trash::updateIcon()
234 Plasma::ToolTipContent data
;
235 data
.setMainText(i18n("Trash"));
238 m_icon
->setIcon(KIcon("user-trash-full"));
240 data
.setSubText(i18np("One item", "%1 items", m_count
));
242 m_icon
->setInfoText(i18np("One item", "%1 items", m_count
));
245 m_icon
->setIcon(KIcon("user-trash"));
247 data
.setSubText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
249 m_icon
->setInfoText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
255 data
.setImage(m_icon
->icon().pixmap(IconSize(KIconLoader::Desktop
)));
258 Plasma::ToolTipManager::self()->setContent(this, data
);
260 Plasma::ToolTipManager::self()->clearContent(this);
263 emptyTrash
->setEnabled(m_count
> 0);
266 void Trash::slotClear()
272 void Trash::slotCompleted()
274 m_count
= m_dirLister
->items(KDirLister::AllItems
).count();
278 void Trash::slotDeleteItem(const KFileItem
&)
284 void Trash::slotApplyConfig()
289 QList
<QAction
*> Trash::contextualActions()
294 void Trash::dropEvent(QGraphicsSceneDragDropEvent
*event
)
296 if (KUrl::List::canDecode(event
->mimeData())) {
297 const KUrl::List urls
= KUrl::List::fromMimeData(event
->mimeData());
298 if (urls
.count() > 0) {
301 //some special operation was done instead of simply deleting a file
302 bool specialOperation
= false;
305 m_places
= new KFilePlacesModel(this);
308 foreach (const KUrl
& url
, urls
) {
309 const Solid::Predicate
predicate(Solid::DeviceInterface::StorageAccess
, "filePath", url
.path());
311 //query for mounted devices
312 const QList
<Solid::Device
> devList
= Solid::Device::listFromQuery(predicate
, QString());
315 //seek for an item in the places (e.g. Dolphin sidebar)
316 const QModelIndex index
= m_places
->closestItem(url
);
318 if (devList
.count() > 0) {
319 //Assuming a mountpoint has a single device
320 Solid::Device device
= devList
.first();
322 if (device
.is
<Solid::OpticalDisc
>()) {
323 device
.parent().as
<Solid::OpticalDrive
>()->eject();
325 device
.as
<Solid::StorageAccess
>()->teardown();
328 specialOperation
= true;
329 //hide if there is exactly that item in the places model
330 } else if (m_places
->bookmarkForIndex(index
).url() == url
) {
331 m_places
->removePlace(index
);
332 specialOperation
= true;
336 //finally, try to trash a file
337 if (!specialOperation
) {
338 KIO::Job
* job
= KIO::trash(urls
);
339 job
->ui()->setWindow(0);
340 job
->ui()->setAutoErrorHandlingEnabled(true);