1 /***************************************************************************
2 * Copyright 2007 by Aaron Seigo <aseigo@kde.org *
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 ***************************************************************************/
22 #include <QGraphicsSceneDragDropEvent>
23 #include <QGraphicsSceneMouseEvent>
24 #include <QGraphicsItem>
27 #include <QGraphicsLinearLayout>
29 #include <KGlobalSettings>
31 #include <KDesktopFile>
32 #include <KIconLoader>
35 #include <KPropertiesDialog>
37 #include <KSharedConfig>
40 #include <KWindowSystem>
41 #include <kio/copyjob.h>
42 #include <kio/netaccess.h>
44 #include <Plasma/Theme>
45 #include <Plasma/IconWidget>
46 #include <Plasma/Containment>
47 #include <Plasma/ToolTipManager>
49 IconApplet::IconApplet(QObject
*parent
, const QVariantList
&args
)
50 : Plasma::Applet(parent
, args
),
55 setBackgroundHints(NoBackground
);
56 setHasConfigurationInterface(true);
57 m_icon
= new Plasma::IconWidget(this);
59 if (args
.count() > 0) {
60 setUrl(args
.value(0).toString());
61 m_icon
->setText(m_text
);
64 resize(m_icon
->sizeFromIconSize(IconSize(KIconLoader::Desktop
)));
65 //kDebug() << "sized to:" << geometry();
68 void IconApplet::init()
70 QGraphicsLinearLayout
*layout
= new QGraphicsLinearLayout(this);
71 layout
->setContentsMargins(0, 0, 0, 0);
72 layout
->setSpacing(0);
74 layout
->addItem(m_icon
);
76 KConfigGroup cg
= config();
78 if (!m_url
.isValid()) {
79 setUrl(cg
.readEntry("Url", m_url
));
83 registerAsDragHandle(m_icon
);
84 Plasma::ToolTipManager::self()->registerWidget(m_icon
);
86 setAspectRatioMode(Plasma::ConstrainedSquare
);
88 // we do this right away since we may have our config
89 // read shortly by the containment. usually applets don't need
90 // this, but desktop icons requires some hacks.
92 // in particular, if we were created with a url passed into via
93 // the args parameter in the ctor, then there won't be an entry
94 // in our config, and desktop icons support banks on the fact
96 cg
.writeEntry("Url", m_url
);
99 IconApplet::~IconApplet()
104 void IconApplet::saveState(KConfigGroup
&cg
) const
106 cg
.writeEntry("Url", m_url
);
109 void IconApplet::setUrl(const KUrl
& url
)
111 m_url
= KIO::NetAccess::mostLocalUrl(url
, 0);
113 m_mimetype
= KMimeType::findByUrl(url
);
115 if (m_url
.isLocalFile() && KDesktopFile::isDesktopFile(m_url
.toLocalFile())) {
116 KDesktopFile
f(m_url
.toLocalFile());
117 m_text
= f
.readName();
118 //corrupted desktop file?
119 if (m_text
.isNull()) {
120 m_text
= m_url
.fileName();
122 m_icon
->setIcon(f
.readIcon());
124 m_genericName
= f
.readGenericName();
126 m_text
= m_url
.fileName();
128 if(m_text
.isEmpty() && m_url
.isLocalFile()) {
129 //handle special case like the / folder
130 m_text
= m_url
.directory();
131 }else if(m_text
.isEmpty()) {
132 //if we can't find a name, at least take the protocol name, like trash, remote etc.
133 m_text
= m_url
.protocol();
136 m_icon
->setIcon(KMimeType::iconNameForUrl(url
));
139 if (m_icon
->icon().isNull()) {
140 m_icon
->setIcon("unknown");
143 kDebug() << "url was" << url
<< "and is" << m_url
;
146 void IconApplet::openUrl()
148 if (m_url
.isValid()) {
149 emit
releaseVisualFocus();
150 KRun
*run
= new KRun(m_url
, 0);
154 void IconApplet::constraintsEvent(Plasma::Constraints constraints
)
156 setBackgroundHints(NoBackground
);
158 if (constraints
& Plasma::FormFactorConstraint
) {
159 disconnect(m_icon
, SIGNAL(activated()), this, SLOT(openUrl()));
160 disconnect(m_icon
, SIGNAL(clicked()), this, SLOT(openUrl()));
162 if (formFactor() == Plasma::Planar
||
163 formFactor() == Plasma::MediaCenter
) {
164 connect(m_icon
, SIGNAL(activated()), this, SLOT(openUrl()));
165 m_icon
->setText(m_text
);
166 //FIXME TOOL TIP MANAGER
167 //m_icon->setToolTip(Plasma::ToolTipData());
168 m_icon
->setDrawBackground(true);
170 //in the panel the icon behaves like a button
171 connect(m_icon
, SIGNAL(clicked()), this, SLOT(openUrl()));
172 m_icon
->setText(QString());
173 Plasma::ToolTipContent
data(m_text
, m_genericName
, m_icon
->icon());
174 Plasma::ToolTipManager::self()->setContent(m_icon
, data
);
175 m_icon
->setDrawBackground(false);
180 void IconApplet::showConfigurationInterface()
183 m_dialog
= new KPropertiesDialog(m_url
, 0 /*no parent widget*/);
184 connect(m_dialog
, SIGNAL(applied()), this, SLOT(acceptedPropertiesDialog()));
185 connect(m_dialog
, SIGNAL(propertiesClosed()), this, SLOT(propertiesDialogClosed()));
186 m_dialog
->setWindowTitle(i18n("%1 Icon Settings", m_url
.fileName()));
189 KWindowSystem::setOnDesktop(m_dialog
->winId(), KWindowSystem::currentDesktop());
191 KWindowSystem::activateWindow(m_dialog
->winId());
195 void IconApplet::setDisplayLines(int displayLines
)
198 if (m_icon
->numDisplayLines() == displayLines
) {
201 m_icon
->setNumDisplayLines(displayLines
);
206 int IconApplet::displayLines()
209 return m_icon
->numDisplayLines();
214 void IconApplet::acceptedPropertiesDialog()
216 KConfigGroup cg
= config();
217 m_url
= m_dialog
->kurl();
218 cg
.writeEntry("Url", m_url
);
223 void IconApplet::propertiesDialogClosed()
228 void IconApplet::dropEvent(QGraphicsSceneDragDropEvent
*event
)
230 if (!KUrl::List::canDecode(event
->mimeData())) {
234 KUrl::List urls
= KUrl::List::fromMimeData(event
->mimeData());
236 if (urls
.count() > 0) {
243 if (m_url
.isEmpty()) {
244 setUrl(urls
.first());
245 //TODO: why we don't call updateConstraints()?
246 constraintsEvent(Plasma::FormFactorConstraint
);
247 } else if (m_url
.isLocalFile() &&
249 (m_mimetype
->is("application/x-executable") ||
250 m_mimetype
->is("application/x-shellscript") ||
251 KDesktopFile::isDesktopFile(m_url
.toLocalFile()))) {
255 foreach (const KUrl
&url
, urls
) {
256 if (url
.isLocalFile()) {
257 params
+= ' ' + KShell::quoteArg(url
.path());
259 params
+= ' ' + KShell::quoteArg(url
.prettyUrl());
265 //Extract the command from the Desktop file
266 if (KDesktopFile::isDesktopFile(m_url
.toLocalFile())) {
267 KDesktopFile
f(m_url
.toLocalFile());
268 KConfigGroup config
= f
.desktopGroup();
269 commandStr
= config
.readPathEntry( "Exec", QString() );
271 if (commandStr
.isEmpty()) {
272 QString path
= f
.readUrl();
273 if (path
.isEmpty()) {
277 if (path
.isEmpty()) {
282 KMimeType::Ptr mime
= KMimeType::findByUrl(dest
);
283 if (m_mimetype
->is("inode/directory")) {
284 dropUrls(urls
, dest
, event
->modifiers());
288 //Else just exec the local executable
289 commandStr
= KShell::quoteArg(m_url
.path());
292 KRun::runCommand(commandStr
+ ' ' + params
, 0);
293 } else if (m_mimetype
->is("inode/directory")) {
294 dropUrls(urls
, m_url
, event
->modifiers());
298 QPainterPath
IconApplet::shape() const
300 return m_icon
->shape();
303 //dropUrls from DolphinDropController
304 void IconApplet::dropUrls(const KUrl::List
& urls
,
305 const KUrl
& destination
,
306 Qt::KeyboardModifiers modifier
)
308 kDebug() << "Source" << urls
;
309 kDebug() << "Destination:" << destination
;
311 Qt::DropAction action
= Qt::CopyAction
;
313 const bool shiftPressed
= modifier
& Qt::ShiftModifier
;
314 const bool controlPressed
= modifier
& Qt::ControlModifier
;
315 const bool altPressed
= modifier
& Qt::AltModifier
;
316 if (shiftPressed
&& controlPressed
) {
317 // shortcut for 'Link Here' is used
318 action
= Qt::LinkAction
;
319 } else if (shiftPressed
) {
320 // shortcut for 'Move Here' is used
321 action
= Qt::MoveAction
;
322 } else if (controlPressed
) {
323 // shortcut for 'Copy Here' is used
324 action
= Qt::CopyAction
;
325 } else if (altPressed
) {
326 // shortcut for 'Link Here' is used
327 action
= Qt::LinkAction
;
329 // open a context menu which offers the following actions:
337 QString seq
= QKeySequence(Qt::ShiftModifier
).toString();
338 seq
.chop(1); // chop superfluous '+'
339 QAction
* moveAction
= popup
.addAction(KIcon("go-jump"),
340 i18nc("@action:inmenu",
341 "&Move Here\t<shortcut>%1</shortcut>", seq
));
343 seq
= QKeySequence(Qt::ControlModifier
).toString();
345 QAction
* copyAction
= popup
.addAction(KIcon("edit-copy"),
346 i18nc("@action:inmenu",
347 "&Copy Here\t<shortcut>%1</shortcut>", seq
));
349 seq
= QKeySequence(Qt::ControlModifier
+ Qt::ShiftModifier
).toString();
351 QAction
* linkAction
= popup
.addAction(KIcon("insert-link"),
352 i18nc("@action:inmenu",
353 "&Link Here\t<shortcut>%1</shortcut>", seq
));
355 popup
.addSeparator();
356 popup
.addAction(KIcon("process-stop"), i18nc("@action:inmenu", "Cancel"));
358 QAction
* activatedAction
= popup
.exec(QCursor::pos());
359 if (activatedAction
== moveAction
) {
360 action
= Qt::MoveAction
;
361 } else if (activatedAction
== copyAction
) {
362 action
= Qt::CopyAction
;
363 } else if (activatedAction
== linkAction
) {
364 action
= Qt::LinkAction
;
372 KIO::move(urls
, destination
);
376 KIO::copy(urls
, destination
);
380 KIO::link(urls
, destination
);