]> cloud.milkyroute.net Git - dolphin.git/blob - src/urlnavigator.cpp
commited initial version of Dolphin
[dolphin.git] / src / urlnavigator.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
3 * Copyright (C) 2006 by Aaron J. Seigo (<aseigo@kde.org>) *
4 * Copyright (C) 2006 by Patrice Tremblay *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20 ***************************************************************************/
21
22 #include "urlnavigator.h"
23
24 #include <assert.h>
25
26 #include <qcombobox.h>
27 #include <qfont.h>
28 #include <qlabel.h>
29 #include <q3listbox.h>
30 #include <qlineedit.h>
31 #include <qobject.h>
32 #include <q3popupmenu.h>
33 #include <qpushbutton.h>
34 #include <qsizepolicy.h>
35 #include <qtooltip.h>
36 //Added by qt3to4:
37 #include <Q3ValueList>
38 #include <QKeyEvent>
39 #include <QCheckBox>
40
41 #include <kaction.h>
42 #include <kactioncollection.h>
43 #include <kiconloader.h>
44 #include <kio/job.h>
45 #include <klocale.h>
46 #include <kprotocolinfo.h>
47 #include <kurl.h>
48 #include <kurlcombobox.h>
49 #include <kurlcompletion.h>
50 #include <kbookmarkmanager.h>
51
52 #include "bookmarkselector.h"
53 #include "dolphin.h"
54 #include "dolphinsettings.h"
55 #include "dolphinstatusbar.h"
56 #include "dolphinview.h"
57 #include "generalsettings.h"
58 #include "protocolcombo.h"
59 #include "urlnavigatorbutton.h"
60
61 URLNavigator::HistoryElem::HistoryElem()
62 : m_url(),
63 m_currentFileName(),
64 m_contentsX(0),
65 m_contentsY(0)
66 {
67 }
68
69 URLNavigator::HistoryElem::HistoryElem(const KUrl& url)
70 : m_url(url),
71 m_currentFileName(),
72 m_contentsX(0),
73 m_contentsY(0)
74 {
75 }
76
77 URLNavigator::HistoryElem::~HistoryElem()
78 {
79 }
80
81 URLNavigator::URLNavigator(const KUrl& url,
82 DolphinView* dolphinView) :
83 Q3HBox(dolphinView),
84 m_historyIndex(0),
85 m_dolphinView(dolphinView),
86 m_protocols(0),
87 m_protocolSeparator(0),
88 m_host(0)
89 {
90 m_history.prepend(HistoryElem(url));
91
92 QFontMetrics fontMetrics(font());
93 setMinimumHeight(fontMetrics.height() + 8);
94
95 m_toggleButton = new QCheckBox(this);
96 //m_toggleButton->setFlat(true);
97 //m_toggleButton->setToggleButton(true);
98 m_toggleButton->setFocusPolicy(Qt::NoFocus);
99 m_toggleButton->setMinimumHeight(minimumHeight());
100 connect(m_toggleButton, SIGNAL(clicked()),
101 this, SLOT(slotClicked()));
102 if (DolphinSettings::instance().generalSettings()->editableURL()) {
103 m_toggleButton->toggle();
104 }
105
106 m_bookmarkSelector = new BookmarkSelector(this);
107 connect(m_bookmarkSelector, SIGNAL(bookmarkActivated(int)),
108 this, SLOT(slotBookmarkActivated(int)));
109
110 m_pathBox = new KUrlComboBox(KUrlComboBox::Directories, true, this);
111
112 KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
113 m_pathBox->setCompletionObject(kurlCompletion);
114 m_pathBox->setAutoDeleteCompletionObject(true);
115
116 connect(m_pathBox, SIGNAL(returnPressed(const QString&)),
117 this, SLOT(slotReturnPressed(const QString&)));
118 connect(m_pathBox, SIGNAL(urlActivated(const KUrl&)),
119 this, SLOT(slotURLActivated(const KUrl&)));
120
121 connect(dolphinView, SIGNAL(contentsMoved(int, int)),
122 this, SLOT(slotContentsMoved(int, int)));
123 connect(dolphinView, SIGNAL(redirection(const KUrl&, const KUrl&)),
124 this, SLOT(slotRedirection(const KUrl&, const KUrl&)));
125 /* connect(dolphinView, SIGNAL(redirection(const KUrl&)),
126 this, SLOT(slotRedirection(const KUrl&)));*/
127 updateContent();
128 }
129
130 URLNavigator::~URLNavigator()
131 {
132 }
133
134 void URLNavigator::setURL(const KUrl& url)
135 {
136 QString urlStr(url.pathOrUrl());
137 //kdDebug() << "setURL(" << url << ")" << endl;
138 if (urlStr.at(0) == '~') {
139 // replace '~' by the home directory
140 urlStr.remove(0, 1);
141 urlStr.insert(0, QDir::home().path());
142 }
143
144 const KUrl transformedURL(urlStr);
145
146 if (m_historyIndex > 0) {
147 // Check whether the previous element of the history has the same URL.
148 // If yes, just go forward instead of inserting a duplicate history
149 // element.
150 const KUrl& nextURL = m_history[m_historyIndex - 1].url();
151 if (transformedURL == nextURL) {
152 goForward();
153 // kdDebug() << "goin' forward in history" << endl;
154 return;
155 }
156 }
157
158 const KUrl& currURL = m_history[m_historyIndex].url();
159 if (currURL == transformedURL) {
160 // don't insert duplicate history elements
161 // kdDebug() << "currURL == transformedURL" << endl;
162 return;
163 }
164
165 updateHistoryElem();
166
167 const Q3ValueListIterator<URLNavigator::HistoryElem> it = m_history.at(m_historyIndex);
168 m_history.insert(it, HistoryElem(transformedURL));
169
170 updateContent();
171
172 emit urlChanged(transformedURL);
173 emit historyChanged();
174
175 // Prevent an endless growing of the history: remembering
176 // the last 100 URLs should be enough...
177 if (m_historyIndex > 100) {
178 m_history.erase(m_history.begin());
179 --m_historyIndex;
180 }
181
182 /* kdDebug() << "history starting ====================" << endl;
183 int i = 0;
184 for (QValueListIterator<URLNavigator::HistoryElem> it = m_history.begin();
185 it != m_history.end();
186 ++it, ++i)
187 {
188 kdDebug() << i << ": " << (*it).url() << endl;
189 }
190 kdDebug() << "history done ========================" << endl;*/
191 }
192
193 const KUrl& URLNavigator::url() const
194 {
195 assert(!m_history.empty());
196 return m_history[m_historyIndex].url();
197 }
198
199 KUrl URLNavigator::url(int index) const
200 {
201 assert(index >= 0);
202 QString path(url().pathOrUrl());
203 path = path.section('/', 0, index);
204
205 if (path.at(path.length()) != '/')
206 {
207 path.append('/');
208 }
209
210 return path;
211 }
212
213 const Q3ValueList<URLNavigator::HistoryElem>& URLNavigator::history(int& index) const
214 {
215 index = m_historyIndex;
216 return m_history;
217 }
218
219 void URLNavigator::goBack()
220 {
221 updateHistoryElem();
222
223 const int count = m_history.count();
224 if (m_historyIndex < count - 1) {
225 ++m_historyIndex;
226 updateContent();
227 emit urlChanged(url());
228 emit historyChanged();
229 }
230 }
231
232 void URLNavigator::goForward()
233 {
234 if (m_historyIndex > 0) {
235 --m_historyIndex;
236 updateContent();
237 emit urlChanged(url());
238 emit historyChanged();
239 }
240 }
241
242 void URLNavigator::goUp()
243 {
244 setURL(url().upUrl());
245 }
246
247 void URLNavigator::goHome()
248 {
249 setURL(DolphinSettings::instance().generalSettings()->homeURL());
250 }
251
252 void URLNavigator::setURLEditable(bool editable)
253 {
254 if (isURLEditable() != editable) {
255 m_toggleButton->toggle();
256 slotClicked();
257 }
258 }
259
260 bool URLNavigator::isURLEditable() const
261 {
262 return m_toggleButton->isChecked();
263 }
264
265 void URLNavigator::editURL(bool editOrBrowse)
266 {
267 setURLEditable(editOrBrowse);
268
269 if (editOrBrowse)
270 {
271 m_pathBox->setFocus();
272 }
273 }
274
275 DolphinView* URLNavigator::dolphinView() const
276 {
277 return m_dolphinView;
278 }
279
280 void URLNavigator::keyReleaseEvent(QKeyEvent* event)
281 {
282 Q3HBox::keyReleaseEvent(event);
283 if (isURLEditable() && (event->key() == Qt::Key_Escape)) {
284 setURLEditable(false);
285 }
286 }
287
288 void URLNavigator::slotReturnPressed(const QString& text)
289 {
290 // Parts of the following code have been taken
291 // from the class KateFileSelector located in
292 // kate/app/katefileselector.hpp of Kate.
293 // Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
294 // Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
295 // Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
296
297 KUrl typedURL(text);
298 if (typedURL.hasPass()) {
299 typedURL.setPass(QString::null);
300 }
301
302 QStringList urls = m_pathBox->urls();
303 urls.remove(typedURL.url());
304 urls.prepend(typedURL.url());
305 m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
306
307 setURL(typedURL);
308 // The URL might have been adjusted by URLNavigator::setURL(), hence
309 // synchronize the result in the path box.
310 m_pathBox->setUrl(url());
311 }
312
313 void URLNavigator::slotURLActivated(const KUrl& url)
314 {
315 setURL(url);
316 }
317
318 void URLNavigator::slotRemoteHostActivated()
319 {
320 KUrl u = url();
321
322 QString host = m_host->text();
323 QString user;
324
325 int marker = host.find("@");
326 if (marker != -1)
327 {
328 user = host.left(marker);
329 u.setUser(user);
330 host = host.right(host.length() - marker - 1);
331 }
332
333 marker = host.find("/");
334 if (marker != -1)
335 {
336 u.setPath(host.right(host.length() - marker));
337 host.truncate(marker);
338 }
339 else
340 {
341 u.setPath("");
342 }
343
344 if (m_protocols->currentProtocol() != u.protocol() ||
345 host != u.host() ||
346 user != u.user())
347 {
348 u.setProtocol(m_protocols->currentProtocol());
349 u.setHost(m_host->text());
350
351 //TODO: get rid of this HACK for file:///!
352 if (u.protocol() == "file")
353 {
354 u.setHost("");
355 if (u.path().isEmpty())
356 {
357 u.setPath("/");
358 }
359 }
360
361 setURL(u);
362 }
363 }
364
365 void URLNavigator::slotProtocolChanged(const QString& protocol)
366 {
367 KUrl url;
368 url.setProtocol(protocol);
369 //url.setPath(KProtocolInfo::protocolClass(protocol) == ":local" ? "/" : "");
370 url.setPath("/");
371 Q3ValueList<QWidget*>::const_iterator it = m_navButtons.constBegin();
372 while (it != m_navButtons.constEnd()) {
373 (*it)->close();
374 (*it)->deleteLater();
375 ++it;
376 }
377 m_navButtons.clear();
378
379 if (KProtocolInfo::protocolClass(protocol) == ":local") {
380 setURL(url);
381 }
382 else {
383 if (!m_host) {
384 m_protocolSeparator = new QLabel("://", this);
385 m_host = new QLineEdit(this);
386
387 connect(m_host, SIGNAL(lostFocus()),
388 this, SLOT(slotRemoteHostActivated()));
389 connect(m_host, SIGNAL(returnPressed()),
390 this, SLOT(slotRemoteHostActivated()));
391 }
392 else {
393 m_host->setText("");
394 }
395 m_protocolSeparator->show();
396 m_host->show();
397 m_host->setFocus();
398 }
399 }
400
401 void URLNavigator::slotRequestActivation()
402 {
403 m_dolphinView->requestActivation();
404 }
405
406 void URLNavigator::slotBookmarkActivated(int index)
407 {
408 m_dolphinView->statusBar()->clear();
409 m_dolphinView->requestActivation();
410
411 KBookmark bookmark = DolphinSettings::instance().bookmark(index);
412 m_dolphinView->setURL(bookmark.url());
413 }
414
415 void URLNavigator::slotRedirection(const KUrl& oldUrl, const KUrl& newUrl)
416 {
417 // kdDebug() << "received redirection to " << newUrl << endl;
418 kdDebug() << "received redirection from " << oldUrl << " to " << newUrl << endl;
419 /* UrlStack::iterator it = m_urls.find(oldUrl);
420 if (it != m_urls.end())
421 {
422 m_urls.erase(++it, m_urls.end());
423 }
424
425 m_urls.append(newUrl);*/
426 }
427
428 void URLNavigator::slotContentsMoved(int x, int y)
429 {
430 m_history[m_historyIndex].setContentsX(x);
431 m_history[m_historyIndex].setContentsY(y);
432 }
433
434 void URLNavigator::slotClicked()
435 {
436 if (isURLEditable()) {
437 m_pathBox->setFocus();
438 updateContent();
439 }
440 else {
441 setURL(m_pathBox->currentText());
442 m_dolphinView->setFocus();
443 }
444 }
445
446 void URLNavigator::updateHistoryElem()
447 {
448 assert(m_historyIndex >= 0);
449 const KFileItem* item = m_dolphinView->currentFileItem();
450 if (item != 0) {
451 m_history[m_historyIndex].setCurrentFileName(item->name());
452 }
453 m_history[m_historyIndex].setContentsX(m_dolphinView->contentsX());
454 m_history[m_historyIndex].setContentsY(m_dolphinView->contentsY());
455 }
456
457 void URLNavigator::updateContent()
458 {
459 // delete all existing URL navigator buttons
460 Q3ValueList<QWidget*>::const_iterator it = m_navButtons.constBegin();
461 while (it != m_navButtons.constEnd()) {
462 (*it)->close();
463 (*it)->deleteLater();
464 ++it;
465 }
466 m_navButtons.clear();
467
468 m_bookmarkSelector->updateSelection(url());
469
470 QToolTip::remove(m_toggleButton);
471 QString path(url().pathOrUrl());
472 const KAction* action = Dolphin::mainWin().actionCollection()->action("editable_location");
473 // TODO: registry of default shortcuts
474 QString shortcut = action? action->shortcutText() : "Ctrl+L";
475 if (m_toggleButton->isChecked()) {
476 delete m_protocols; m_protocols = 0;
477 delete m_protocolSeparator; m_protocolSeparator = 0;
478 delete m_host; m_host = 0;
479
480 QToolTip::add(m_toggleButton, i18n("Browse (%1, Escape)").arg(shortcut));
481
482 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
483 m_pathBox->show();
484 m_pathBox->setUrl(url());
485 }
486 else {
487 QToolTip::add(m_toggleButton, i18n("Edit location (%1)").arg(shortcut));
488
489 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
490 m_pathBox->hide();
491 QString dir_name;
492
493 // get the data from the currently selected bookmark
494 KBookmark bookmark = m_bookmarkSelector->selectedBookmark();
495 //int bookmarkIndex = m_bookmarkSelector->selectedIndex();
496
497 QString bookmarkPath;
498 if (bookmark.isNull()) {
499 // No bookmark is a part of the current URL.
500 // The following code tries to guess the bookmark
501 // path. E. g. "fish://root@192.168.0.2/var/lib" writes
502 // "fish://root@192.168.0.2" to 'bookmarkPath', which leads to the
503 // navigation indication 'Custom Path > var > lib".
504 int idx = path.find(QString("//"));
505 idx = path.find("/", (idx < 0) ? 0 : idx + 2);
506 bookmarkPath = (idx < 0) ? path : path.left(idx);
507 }
508 else {
509 bookmarkPath = bookmark.url().pathOrUrl();
510 }
511 const uint len = bookmarkPath.length();
512
513 // calculate the start point for the URL navigator buttons by counting
514 // the slashs inside the bookmark URL
515 int slashCount = 0;
516 for (uint i = 0; i < len; ++i) {
517 if (bookmarkPath.at(i) == QChar('/')) {
518 ++slashCount;
519 }
520 }
521 if ((len > 0) && bookmarkPath.at(len - 1) == QChar('/')) {
522 assert(slashCount > 0);
523 --slashCount;
524 }
525
526 if (!url().isLocalFile() && bookmark.isNull()) {
527 QString protocol = url().protocol();
528 if (!m_protocols) {
529 m_protocols = new ProtocolCombo(protocol, this);
530 connect(m_protocols, SIGNAL(activated(const QString&)),
531 this, SLOT(slotProtocolChanged(const QString&)));
532 }
533 else {
534 m_protocols->setProtocol(protocol);
535 }
536 m_protocols->show();
537
538 if (KProtocolInfo::protocolClass(protocol) != ":local")
539 {
540 QString hostText = url().host();
541
542 if (!url().user().isEmpty())
543 {
544 hostText = url().user() + "@" + hostText;
545 }
546
547 if (!m_host) {
548 m_protocolSeparator = new QLabel("://", this);
549 m_host = new QLineEdit(hostText, this);
550
551 connect(m_host, SIGNAL(lostFocus()),
552 this, SLOT(slotRemoteHostActivated()));
553 connect(m_host, SIGNAL(returnPressed()),
554 this, SLOT(slotRemoteHostActivated()));
555 }
556 else {
557 m_host->setText(hostText);
558 }
559 m_protocolSeparator->show();
560 m_host->show();
561 }
562 else {
563 delete m_protocolSeparator; m_protocolSeparator = 0;
564 delete m_host; m_host = 0;
565 }
566 }
567 else if (m_protocols) {
568 m_protocols->hide();
569
570 if (m_host) {
571 m_protocolSeparator->hide();
572 m_host->hide();
573 }
574 }
575
576 // create URL navigator buttons
577 int idx = slashCount;
578 bool hasNext = true;
579 do {
580 dir_name = path.section('/', idx, idx);
581 const bool isFirstButton = (idx == slashCount);
582 hasNext = isFirstButton || !dir_name.isEmpty();
583 if (hasNext) {
584 URLNavigatorButton* button = new URLNavigatorButton(idx, this);
585 if (isFirstButton) {
586 // the first URL navigator button should get the name of the
587 // bookmark instead of the directory name
588 QString text = bookmark.text();
589 if (text.isEmpty()) {
590 if (url().isLocalFile())
591 {
592 text = i18n("Custom Path");
593 }
594 else
595 {
596 delete button;
597 ++idx;
598 continue;
599 }
600 }
601 button->setText(text);
602 }
603 button->show();
604 m_navButtons.append(button);
605 ++idx;
606 }
607 } while (hasNext);
608 }
609 }
610
611 #include "urlnavigator.moc"