1/***************************************************************************
2 * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
3 * Copyright (C) 2007 by Kevin Ottens (ervin@kde.org) *
4 * *
5 * This library is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Lesser General Public *
7 * License as published by the Free Software Foundation; either *
8 * version 2 of the License, or (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * Lesser General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Lesser General Public *
16 * License along with this library; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21#include "kurlnavigatorplacesselector_p.h"
22
23#include <kiconloader.h>
24#include <kglobalsettings.h>
25#include <kfileplacesmodel.h>
26#include <kmenu.h>
27#include <kmimetype.h>
28#include <kdebug.h>
29
30#include <QtGui/QDragEnterEvent>
31#include <QtGui/QDragLeaveEvent>
32#include <QtGui/QDropEvent>
33#include <QtGui/QPainter>
34#include <QtGui/QPixmap>
35#include <kicon.h>
36
37namespace KDEPrivate
38{
39
40KUrlNavigatorPlacesSelector::KUrlNavigatorPlacesSelector(QWidget* parent, KFilePlacesModel* placesModel) :
41 KUrlNavigatorButtonBase(parent),
42 m_selectedItem(-1),
43 m_placesModel(placesModel)
44{
45 setFocusPolicy(Qt::NoFocus);
46
47 m_placesMenu = new KMenu(this);
48
49 updateMenu();
50
51 connect(m_placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
52 this, SLOT(updateMenu()));
53 connect(m_placesModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
54 this, SLOT(updateMenu()));
55 connect(m_placesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
56 this, SLOT(updateMenu()));
57 connect(m_placesMenu, SIGNAL(triggered(QAction*)),
58 this, SLOT(activatePlace(QAction*)));
59
60 setMenu(m_placesMenu);
61
62 setAcceptDrops(true);
63}
64
65KUrlNavigatorPlacesSelector::~KUrlNavigatorPlacesSelector()
66{
67}
68
69void KUrlNavigatorPlacesSelector::updateMenu()
70{
71 m_placesMenu->clear();
72
73 updateSelection(m_selectedUrl);
74 const int rowCount = m_placesModel->rowCount();
75 for (int i = 0; i < rowCount; ++i) {
76 QModelIndex index = m_placesModel->index(i, 0);
77 QAction* action = new QAction(m_placesModel->icon(index),
78 m_placesModel->text(index),
79 m_placesMenu);
80 m_placesMenu->addAction(action);
81 action->setData(i);
82 if (i == m_selectedItem) {
83 setIcon(m_placesModel->icon(index));
84 }
85 }
86
87 updateTeardownAction();
88}
89
90void KUrlNavigatorPlacesSelector::updateTeardownAction()
91{
92 const int rowCount = m_placesModel->rowCount();
93 if (m_placesMenu->actions().size()==rowCount+2) {
94 // remove teardown action
95 QAction *action = m_placesMenu->actions().at(rowCount+1);
96 m_placesMenu->removeAction(action);
97 delete action;
98
99 // remove separator
100 action = m_placesMenu->actions().at(rowCount);
101 m_placesMenu->removeAction(action);
102 delete action;
103 }
104
105 const QModelIndex index = m_placesModel->index(m_selectedItem, 0);
106 QAction *teardown = m_placesModel->teardownActionForIndex(index);
107 if (teardown!=0) {
108 teardown->setParent(m_placesMenu);
109 teardown->setData("teardownAction");
110
111 m_placesMenu->addSeparator();
112 m_placesMenu->addAction(teardown);
113 }
114}
115
116void KUrlNavigatorPlacesSelector::updateSelection(const KUrl& url)
117{
118 const QModelIndex index = m_placesModel->closestItem(url);
119 if (index.isValid()) {
120 m_selectedItem = index.row();
121 m_selectedUrl = url;
122 setIcon(m_placesModel->icon(index));
123 } else {
124 m_selectedItem = -1;
125 // No bookmark has been found which matches to the given Url. Show
126 // a generic folder icon as pixmap for indication:
127 setIcon(KIcon("folder"));
128 }
129 updateTeardownAction();
130}
131
132KUrl KUrlNavigatorPlacesSelector::selectedPlaceUrl() const
133{
134 const QModelIndex index = m_placesModel->index(m_selectedItem, 0);
135 return index.isValid() ? m_placesModel->url(index) : KUrl();
136}
137
138QString KUrlNavigatorPlacesSelector::selectedPlaceText() const
139{
140 const QModelIndex index = m_placesModel->index(m_selectedItem, 0);
141 return index.isValid() ? m_placesModel->text(index) : QString();
142}
143
144QSize KUrlNavigatorPlacesSelector::sizeHint() const
145{
146 const int height = KUrlNavigatorButtonBase::sizeHint().height();
147 return QSize(height, height);
148}
149
150void KUrlNavigatorPlacesSelector::paintEvent(QPaintEvent* event)
151{
152 Q_UNUSED(event);
153 QPainter painter(this);
154 drawHoverBackground(&painter);
155
156 // draw icon
157 const QPixmap pixmap = icon().pixmap(QSize(22, 22).expandedTo(iconSize()), QIcon::Normal);
158 const int x = (width() - pixmap.width()) / 2;
159 const int y = (height() - pixmap.height()) / 2;
160 painter.drawPixmap(x, y, pixmap);
161}
162
163void KUrlNavigatorPlacesSelector::dragEnterEvent(QDragEnterEvent* event)
164{
165 if (event->mimeData()->hasUrls()) {
166 setDisplayHintEnabled(DraggedHint, true);
167 event->acceptProposedAction();
168
169 update();
170 }
171}
172
173void KUrlNavigatorPlacesSelector::dragLeaveEvent(QDragLeaveEvent* event)
174{
175 KUrlNavigatorButtonBase::dragLeaveEvent(event);
176
177 setDisplayHintEnabled(DraggedHint, false);
178 update();
179}
180
181void KUrlNavigatorPlacesSelector::dropEvent(QDropEvent* event)
182{
183 setDisplayHintEnabled(DraggedHint, false);
184 update();
185
186 const KUrl::List urlList = KUrl::List::fromMimeData(event->mimeData());
187 if (urlList.isEmpty()) {
188 return;
189 }
190 foreach(const KUrl &url, urlList) {
191 KMimeType::Ptr mimetype = KMimeType::findByUrl(url);
192 if (mimetype->is("inode/directory")) {
193 m_placesModel->addPlace(url.fileName(), url);
194 }
195 }
196}
197
198void KUrlNavigatorPlacesSelector::activatePlace(QAction* action)
199{
200 Q_ASSERT(action != 0);
201 if (action->data().toString()=="teardownAction") {
202 QModelIndex index = m_placesModel->index(m_selectedItem, 0);
203 m_placesModel->requestTeardown(index);
204 return;
205 }
206
207 QModelIndex index = m_placesModel->index(action->data().toInt(), 0);
208
209 m_lastClickedIndex = QPersistentModelIndex();
210
211 if (m_placesModel->setupNeeded(index)) {
212 connect(m_placesModel, SIGNAL(setupDone(QModelIndex,bool)),
213 this, SLOT(onStorageSetupDone(QModelIndex,bool)));
214
215 m_lastClickedIndex = index;
216 m_placesModel->requestSetup(index);
217 return;
218 } else if (index.isValid()) {
219 m_selectedItem = index.row();
220 setIcon(m_placesModel->icon(index));
221 updateTeardownAction();
222 emit placeActivated(m_placesModel->url(index));
223 }
224}
225
226void KUrlNavigatorPlacesSelector::onStorageSetupDone(const QModelIndex &index, bool success)
227{
228 if (m_lastClickedIndex == index) {
229 if (success) {
230 m_selectedItem = index.row();
231 setIcon(m_placesModel->icon(index));
232 updateTeardownAction();
233 emit placeActivated(m_placesModel->url(index));
234 }
235 m_lastClickedIndex = QPersistentModelIndex();
236 }
237}
238
239} // namespace KDEPrivate
240
241#include "kurlnavigatorplacesselector_p.moc"
242
243