not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / applets / trash / trash.cpp
blobc0d09f48362e544a41e2dd17379be2948cb4c4de
1 /***************************************************************************
2 * Copyright 2007 by Marco Martin <notmart@gmail.com> *
3 * *
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. *
8 * *
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. *
13 * *
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 ***************************************************************************/
20 #include "trash.h"
22 //QT
23 #include <QGraphicsSceneDragDropEvent>
24 #include <QApplication>
25 #include <QGraphicsLinearLayout>
27 //KDE
28 #include <KGlobalSettings>
29 #include <KCModuleProxy>
30 #include <KConfigDialog>
31 #include <KDebug>
32 #include <KLocale>
33 #include <KIconLoader>
34 #include <KMimeType>
35 #include <KRun>
36 #include <KSharedConfig>
37 #include <KMessageBox>
38 #include <KUrl>
39 #include <KProcess>
40 #include <KStandardDirs>
42 #include <kfileplacesmodel.h>
43 #include <KIO/CopyJob>
44 #include <KIO/JobUiDelegate>
46 //Plasma
47 #include <Plasma/IconWidget>
48 #include <Plasma/Containment>
49 #include <Plasma/ToolTipManager>
51 //Solid
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),
63 m_icon(0),
64 m_dirLister(0),
65 emptyTrash(0),
66 m_count(0),
67 m_showText(false),
68 m_places(0),
69 m_proxy(0),
70 m_emptyProcess(0)
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)));
80 createMenu();
83 Trash::~Trash()
87 void Trash::init()
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);
96 setAcceptDrops(true);
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()));
118 m_proxy->load();
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()));
143 void Trash::popup()
145 if (m_menu.isVisible()) {
146 m_menu.hide();
147 return;
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));
168 m_showText = true;
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));
172 } else {
173 //in a panel the icon always behaves like a button
174 connect(m_icon, SIGNAL(clicked()), this, SLOT(slotOpen()));
176 m_icon->setText(0);
177 m_icon->setInfoText(0);
178 m_showText = false;
179 m_icon->setDrawBackground(false);
181 setMinimumSize(m_icon->sizeFromIconSize(IconSize(KIconLoader::Small)));
183 updateIcon();
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;
198 m_emptyProcess = 0;
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,
205 text,
206 QString(),
207 KGuiItem(i18nc("@action:button", "Empty Trash"),
208 KIcon("user-trash"))
209 ) == KMessageBox::Continue;
211 if (del) {
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)
225 Q_UNUSED(exitCode)
226 Q_UNUSED(exitStatus)
227 //TODO: check the exit status and let the user know if it fails
228 delete m_emptyProcess;
229 m_emptyProcess = 0;
232 void Trash::updateIcon()
234 Plasma::ToolTipContent data;
235 data.setMainText(i18n("Trash"));
237 if (m_count > 0) {
238 m_icon->setIcon(KIcon("user-trash-full"));
240 data.setSubText(i18np("One item", "%1 items", m_count));
241 if (m_showText) {
242 m_icon->setInfoText(i18np("One item", "%1 items", m_count));
244 } else {
245 m_icon->setIcon(KIcon("user-trash"));
247 data.setSubText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
248 if (m_showText) {
249 m_icon->setInfoText(i18nc("The trash is empty. This is not an action, but a state", "Empty"));
253 m_icon->update();
255 data.setImage(m_icon->icon().pixmap(IconSize(KIconLoader::Desktop)));
257 if (!m_showText) {
258 Plasma::ToolTipManager::self()->setContent(this, data);
259 } else {
260 Plasma::ToolTipManager::self()->clearContent(this);
263 emptyTrash->setEnabled(m_count > 0);
266 void Trash::slotClear()
268 m_count = 0;
269 updateIcon();
272 void Trash::slotCompleted()
274 m_count = m_dirLister->items(KDirLister::AllItems).count();
275 updateIcon();
278 void Trash::slotDeleteItem(const KFileItem &)
280 m_count--;
281 updateIcon();
284 void Trash::slotApplyConfig()
286 m_proxy->save();
289 QList<QAction*> Trash::contextualActions()
291 return actions;
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) {
299 event->accept();
301 //some special operation was done instead of simply deleting a file
302 bool specialOperation = false;
304 if (!m_places) {
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();
324 } else {
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);
346 #include "trash.moc"