]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/informationpanel.cpp
Fix issue that dragging pictures/videos to Google-Search/YouTube fails
[dolphin.git] / src / panels / information / informationpanel.cpp
1 /***************************************************************************
2 * Copyright (C) 2006-2009 by Peter Penz <peter.penz19@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 ***************************************************************************/
19
20 #include "informationpanel.h"
21
22 #include "informationpanelcontent.h"
23 #include <KIO/Job>
24 #include <KDirNotify>
25 #include <QApplication>
26 #include <QShowEvent>
27 #include <QVBoxLayout>
28
29 InformationPanel::InformationPanel(QWidget* parent) :
30 Panel(parent),
31 m_initialized(false),
32 m_infoTimer(0),
33 m_urlChangedTimer(0),
34 m_resetUrlTimer(0),
35 m_shownUrl(),
36 m_urlCandidate(),
37 m_invalidUrlCandidate(),
38 m_fileItem(),
39 m_selection(),
40 m_folderStatJob(0),
41 m_content(0)
42 {
43 }
44
45 InformationPanel::~InformationPanel()
46 {
47 }
48
49 void InformationPanel::setSelection(const KFileItemList& selection)
50 {
51 m_selection = selection;
52 m_fileItem = KFileItem();
53
54 if (!isVisible()) {
55 return;
56 }
57
58 const int count = selection.count();
59 if (count == 0) {
60 if (!isEqualToShownUrl(url())) {
61 m_shownUrl = url();
62 showItemInfo();
63 }
64 } else {
65 if ((count == 1) && !selection.first().url().isEmpty()) {
66 m_urlCandidate = selection.first().url();
67 }
68 m_infoTimer->start();
69 }
70 }
71
72 void InformationPanel::requestDelayedItemInfo(const KFileItem& item)
73 {
74 if (!isVisible() || (item.isNull() && m_fileItem.isNull())) {
75 return;
76 }
77
78 if (QApplication::mouseButtons() & Qt::LeftButton) {
79 // Ignore the request of an item information when a rubberband
80 // selection is ongoing.
81 return;
82 }
83
84 cancelRequest();
85
86 if (item.isNull()) {
87 // The cursor is above the viewport. If files are selected,
88 // show information regarding the selection.
89 if (m_selection.size() > 0) {
90 m_fileItem = KFileItem();
91 m_infoTimer->start();
92 }
93 } else if (item.url().isValid() && !isEqualToShownUrl(item.url())) {
94 // The cursor is above an item that is not shown currently
95 m_urlCandidate = item.url();
96 m_fileItem = item;
97 m_infoTimer->start();
98 }
99 }
100
101 bool InformationPanel::urlChanged()
102 {
103 if (!url().isValid()) {
104 return false;
105 }
106
107 if (!isVisible()) {
108 return true;
109 }
110
111 cancelRequest();
112 m_selection.clear();
113
114 if (!isEqualToShownUrl(url())) {
115 m_shownUrl = url();
116 m_fileItem = KFileItem();
117
118 // Update the content with a delay. This gives
119 // the directory lister the chance to show the content
120 // before expensive operations are done to show
121 // meta information.
122 m_urlChangedTimer->start();
123 }
124
125 return true;
126 }
127
128 void InformationPanel::showEvent(QShowEvent* event)
129 {
130 Panel::showEvent(event);
131 if (!event->spontaneous()) {
132 if (!m_initialized) {
133 // do a delayed initialization so that no performance
134 // penalty is given when Dolphin is started with a closed
135 // Information Panel
136 init();
137 }
138
139 m_shownUrl = url();
140 showItemInfo();
141 }
142 }
143
144 void InformationPanel::resizeEvent(QResizeEvent* event)
145 {
146 if (isVisible()) {
147 m_urlCandidate = m_shownUrl;
148 m_infoTimer->start();
149 }
150 Panel::resizeEvent(event);
151 }
152
153 void InformationPanel::contextMenuEvent(QContextMenuEvent* event)
154 {
155 // TODO: Move code from InformationPanelContent::configureSettings() here
156 m_content->configureSettings(customContextMenuActions());
157 Panel::contextMenuEvent(event);
158 }
159
160 void InformationPanel::showItemInfo()
161 {
162 if (!isVisible()) {
163 return;
164 }
165
166 cancelRequest();
167
168 if (m_fileItem.isNull() && (m_selection.count() > 1)) {
169 // The information for a selection of items should be shown
170 m_content->showItems(m_selection);
171 } else {
172 // The information for exactly one item should be shown
173 KFileItem item;
174 if (!m_fileItem.isNull()) {
175 item = m_fileItem;
176 } else if (!m_selection.isEmpty()) {
177 Q_ASSERT(m_selection.count() == 1);
178 item = m_selection.first();
179 }
180
181 if (item.isNull()) {
182 // No item is hovered and no selection has been done: provide
183 // an item for the currently shown directory.
184 m_folderStatJob = KIO::stat(url(), KIO::HideProgressInfo);
185 connect(m_folderStatJob, SIGNAL(result(KJob*)),
186 this, SLOT(slotFolderStatFinished(KJob*)));
187 } else {
188 m_content->showItem(item);
189 }
190 }
191 }
192
193 void InformationPanel::slotFolderStatFinished(KJob* job)
194 {
195 m_folderStatJob = 0;
196 const KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult();
197 m_content->showItem(KFileItem(entry, m_shownUrl));
198 }
199
200 void InformationPanel::slotInfoTimeout()
201 {
202 m_shownUrl = m_urlCandidate;
203 m_urlCandidate.clear();
204 showItemInfo();
205 }
206
207 void InformationPanel::reset()
208 {
209 if (m_invalidUrlCandidate == m_shownUrl) {
210 m_invalidUrlCandidate = KUrl();
211
212 // The current URL is still invalid. Reset
213 // the content to show the directory URL.
214 m_selection.clear();
215 m_shownUrl = url();
216 m_fileItem = KFileItem();
217 showItemInfo();
218 }
219 }
220
221 void InformationPanel::slotFileRenamed(const QString& source, const QString& dest)
222 {
223 if (m_shownUrl == KUrl(source)) {
224 m_shownUrl = KUrl(dest);
225 m_fileItem = KFileItem(KFileItem::Unknown, KFileItem::Unknown, m_shownUrl);
226
227 if ((m_selection.count() == 1) && (m_selection[0].url() == KUrl(source))) {
228 m_selection[0] = m_fileItem;
229 // Implementation note: Updating the selection is only required if exactly one
230 // item is selected, as the name of the item is shown. If this should change
231 // in future: Before parsing the whole selection take care to test possible
232 // performance bottlenecks when renaming several hundreds of files.
233 }
234
235 showItemInfo();
236 }
237 }
238
239 void InformationPanel::slotFilesAdded(const QString& directory)
240 {
241 if (m_shownUrl == KUrl(directory)) {
242 // If the 'trash' icon changes because the trash has been emptied or got filled,
243 // the signal filesAdded("trash:/") will be emitted.
244 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, KUrl(directory));
245 requestDelayedItemInfo(item);
246 }
247 }
248
249 void InformationPanel::slotFilesChanged(const QStringList& files)
250 {
251 foreach (const QString& fileName, files) {
252 if (m_shownUrl == KUrl(fileName)) {
253 showItemInfo();
254 break;
255 }
256 }
257 }
258
259 void InformationPanel::slotFilesRemoved(const QStringList& files)
260 {
261 foreach (const QString& fileName, files) {
262 if (m_shownUrl == KUrl(fileName)) {
263 // the currently shown item has been removed, show
264 // the parent directory as fallback
265 markUrlAsInvalid();
266 break;
267 }
268 }
269 }
270
271 void InformationPanel::slotEnteredDirectory(const QString& directory)
272 {
273 if (m_shownUrl == KUrl(directory)) {
274 KFileItem item(KFileItem::Unknown, KFileItem::Unknown, KUrl(directory));
275 requestDelayedItemInfo(item);
276 }
277 }
278
279 void InformationPanel::slotLeftDirectory(const QString& directory)
280 {
281 if (m_shownUrl == KUrl(directory)) {
282 // The signal 'leftDirectory' is also emitted when a media
283 // has been unmounted. In this case no directory change will be
284 // done in Dolphin, but the Information Panel must be updated to
285 // indicate an invalid directory.
286 markUrlAsInvalid();
287 }
288 }
289
290 void InformationPanel::cancelRequest()
291 {
292 delete m_folderStatJob;
293 m_folderStatJob = 0;
294
295 m_infoTimer->stop();
296 m_resetUrlTimer->stop();
297 // Don't reset m_urlChangedTimer. As it is assured that the timeout of m_urlChangedTimer
298 // has the smallest interval (see init()), it is not possible that the exceeded timer
299 // would overwrite an information provided by a selection or hovering.
300
301 m_invalidUrlCandidate.clear();
302 m_urlCandidate.clear();
303 }
304
305 bool InformationPanel::isEqualToShownUrl(const KUrl& url) const
306 {
307 return m_shownUrl.equals(url, KUrl::CompareWithoutTrailingSlash);
308 }
309
310 void InformationPanel::markUrlAsInvalid()
311 {
312 m_invalidUrlCandidate = m_shownUrl;
313 m_resetUrlTimer->start();
314 }
315
316 void InformationPanel::init()
317 {
318 m_infoTimer = new QTimer(this);
319 m_infoTimer->setInterval(300);
320 m_infoTimer->setSingleShot(true);
321 connect(m_infoTimer, SIGNAL(timeout()),
322 this, SLOT(slotInfoTimeout()));
323
324 m_urlChangedTimer = new QTimer(this);
325 m_urlChangedTimer->setInterval(200);
326 m_urlChangedTimer->setSingleShot(true);
327 connect(m_urlChangedTimer, SIGNAL(timeout()),
328 this, SLOT(showItemInfo()));
329
330 m_resetUrlTimer = new QTimer(this);
331 m_resetUrlTimer->setInterval(1000);
332 m_resetUrlTimer->setSingleShot(true);
333 connect(m_resetUrlTimer, SIGNAL(timeout()),
334 this, SLOT(reset()));
335
336 Q_ASSERT(m_urlChangedTimer->interval() < m_infoTimer->interval());
337 Q_ASSERT(m_urlChangedTimer->interval() < m_resetUrlTimer->interval());
338
339 org::kde::KDirNotify* dirNotify = new org::kde::KDirNotify(QString(), QString(),
340 QDBusConnection::sessionBus(), this);
341 connect(dirNotify, SIGNAL(FileRenamed(QString,QString)), SLOT(slotFileRenamed(QString,QString)));
342 connect(dirNotify, SIGNAL(FilesAdded(QString)), SLOT(slotFilesAdded(QString)));
343 connect(dirNotify, SIGNAL(FilesChanged(QStringList)), SLOT(slotFilesChanged(QStringList)));
344 connect(dirNotify, SIGNAL(FilesRemoved(QStringList)), SLOT(slotFilesRemoved(QStringList)));
345 connect(dirNotify, SIGNAL(enteredDirectory(QString)), SLOT(slotEnteredDirectory(QString)));
346 connect(dirNotify, SIGNAL(leftDirectory(QString)), SLOT(slotLeftDirectory(QString)));
347
348 m_content = new InformationPanelContent(this);
349 connect(m_content, SIGNAL(urlActivated(KUrl)), this, SIGNAL(urlActivated(KUrl)));
350
351 QVBoxLayout* layout = new QVBoxLayout(this);
352 layout->setContentsMargins(0, 0, 0, 0);
353 layout->addWidget(m_content);
354
355 m_initialized = true;
356 }
357
358 #include "informationpanel.moc"