1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> |
4 | ** Copyright (C) 2009 Tony Murray <murraytony@gmail.com> |
5 | ** |
6 | ** This file is part of KDE. |
7 | ** |
8 | ** This program is free software; you can redistribute it and/or modify |
9 | ** it under the terms of the GNU General Public License as published by |
10 | ** the Free Software Foundation; either version 2 of the License, or |
11 | ** (at your option) any later version. |
12 | ** |
13 | ** This program is distributed in the hope that it will be useful, |
14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | ** GNU General Public License for more details. |
17 | ** |
18 | ** You should have received a copy of the GNU General Public License |
19 | ** along with this program; see the file COPYING. If not, write to |
20 | ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | ** Boston, MA 02110-1301, USA. |
22 | ** |
23 | ****************************************************************************/ |
24 | |
25 | #include "remotedesktopsmodel.h" |
26 | #include "bookmarkmanager.h" |
27 | |
28 | #include <KStandardDirs> |
29 | #include <KDebug> |
30 | #include <KLocale> |
31 | |
32 | RemoteDesktopsModel::RemoteDesktopsModel(QObject *parent) |
33 | : QAbstractTableModel(parent) |
34 | { |
35 | const QString file = KStandardDirs::locateLocal("data" , "krdc/bookmarks.xml" ); |
36 | m_manager = KBookmarkManager::managerForFile(file, "krdc" ); |
37 | m_manager->setUpdate(true); |
38 | connect(m_manager, SIGNAL(changed(QString,QString)), SLOT(bookmarksChanged())); |
39 | buildModelFromBookmarkGroup(m_manager->root()); |
40 | |
41 | #ifdef BUILD_ZEROCONF |
42 | // Add RDP and NX if they start announcing via Zeroconf: |
43 | m_protocols["_rfb._tcp" ] = "vnc" ; |
44 | |
45 | zeroconfBrowser = new DNSSD::ServiceBrowser("_rfb._tcp" , true); |
46 | connect(zeroconfBrowser, SIGNAL(finished()), this, SLOT(servicesChanged())); |
47 | zeroconfBrowser->startBrowse(); |
48 | kDebug(5010) << "Browsing for zeroconf hosts." ; |
49 | #endif |
50 | } |
51 | |
52 | RemoteDesktopsModel::~RemoteDesktopsModel() |
53 | { |
54 | } |
55 | |
56 | int RemoteDesktopsModel::columnCount(const QModelIndex &) const |
57 | { |
58 | return 6; // same as count of RemoteDesktopsModel::DisplayItems enum |
59 | } |
60 | |
61 | int RemoteDesktopsModel::rowCount(const QModelIndex &) const |
62 | { |
63 | return remoteDesktops.size(); |
64 | } |
65 | |
66 | Qt::ItemFlags RemoteDesktopsModel::flags(const QModelIndex &index) const |
67 | { |
68 | if (!index.isValid()) |
69 | return 0; |
70 | if (index.column() == RemoteDesktopsModel::Favorite) { |
71 | return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; |
72 | } |
73 | return Qt::ItemIsEnabled; |
74 | } |
75 | |
76 | bool RemoteDesktopsModel::setData(const QModelIndex &index, const QVariant &value, int role) |
77 | { |
78 | if (index.isValid() && role == Qt::CheckStateRole && index.column() == RemoteDesktopsModel::Favorite) { |
79 | bool checked = (Qt::CheckState)value.toUInt() == Qt::Checked; |
80 | remoteDesktops[index.row()].favorite = checked; |
81 | |
82 | RemoteDesktop rd = remoteDesktops.at(index.row()); |
83 | if (checked) { |
84 | KBookmarkGroup root = m_manager->root(); |
85 | root.addBookmark(rd.title, rd.url); |
86 | m_manager->emitChanged(root); |
87 | } else { |
88 | BookmarkManager::removeByUrl(m_manager, rd.url, true, rd.title); |
89 | } |
90 | return true; |
91 | } |
92 | return false; |
93 | } |
94 | |
95 | QVariant RemoteDesktopsModel::data(const QModelIndex &index, int role) const |
96 | { |
97 | if (!index.isValid()) |
98 | return QVariant(); |
99 | |
100 | RemoteDesktop item = remoteDesktops.at(index.row()); |
101 | |
102 | switch (role) { |
103 | case Qt::DisplayRole: |
104 | switch (index.column()) { |
105 | case RemoteDesktopsModel::Favorite: |
106 | return item.favorite; |
107 | case RemoteDesktopsModel::Title: |
108 | return item.title; |
109 | case RemoteDesktopsModel::LastConnected: |
110 | return QVariant(item.lastConnected.dateTime()); |
111 | case RemoteDesktopsModel::VisitCount: |
112 | return item.visits; |
113 | case RemoteDesktopsModel::Created: |
114 | if (item.created.isNull()) return QVariant(); |
115 | return KGlobal::locale()->formatDateTime(item.created.toLocalZone(), KLocale::ShortDate); |
116 | case RemoteDesktopsModel::Source: |
117 | switch (item.source) { |
118 | case RemoteDesktop::Bookmarks: |
119 | return i18nc("Where each displayed link comes from" , "Bookmarks" ); |
120 | case RemoteDesktop::History: |
121 | return i18nc("Where each displayed link comes from" , "History" ); |
122 | case RemoteDesktop::Zeroconf: |
123 | return i18nc("Where each displayed link comes from" , "Zeroconf" ); |
124 | case RemoteDesktop::None: |
125 | return i18nc("Where each displayed link comes from" , "None" ); |
126 | } |
127 | default: |
128 | return QVariant(); |
129 | } |
130 | |
131 | case Qt::CheckStateRole: |
132 | if (index.column() == RemoteDesktopsModel::Favorite) |
133 | return item.favorite ? Qt::Checked : Qt::Unchecked; |
134 | return QVariant(); |
135 | |
136 | case Qt::ToolTipRole: |
137 | switch(index.column()) { |
138 | case RemoteDesktopsModel::Favorite: |
139 | if (item.favorite) { |
140 | return i18nc("Remove the selected url from the bookarks menu" , "Remove the bookmark for %1." , item.title); |
141 | } else { |
142 | return i18nc("Add the selected url to the bookmarks menu" , "Bookmark %1." , item.title); |
143 | } |
144 | case RemoteDesktopsModel::LastConnected: |
145 | if (!item.lastConnected.isNull()) { |
146 | return KGlobal::locale()->formatDateTime(item.lastConnected.toLocalZone(), KLocale::FancyLongDate); |
147 | } |
148 | break; // else show default tooltip |
149 | case RemoteDesktopsModel::Created: |
150 | if (!item.created.isNull()) { |
151 | return KGlobal::locale()->formatDateTime(item.created.toLocalZone(), KLocale::FancyLongDate); |
152 | } |
153 | break; // else show default tooltip |
154 | default: |
155 | break; |
156 | } |
157 | return item.url; //use the url for the tooltip |
158 | |
159 | case 10001: //url for dockwidget |
160 | return item.url; |
161 | |
162 | case 10002: //filter |
163 | return QUrl::fromPercentEncoding(QString(item.url + item.title).toUtf8()); // return both user visible title and url data, percent encoded |
164 | |
165 | case 10003: //title for dockwidget |
166 | return item.title; |
167 | |
168 | default: |
169 | return QVariant(); |
170 | } |
171 | } |
172 | |
173 | QVariant RemoteDesktopsModel::(int section, Qt::Orientation orientation, |
174 | int role) const |
175 | { |
176 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { |
177 | switch (section) { |
178 | case RemoteDesktopsModel::Favorite: |
179 | return QVariant(); // the favorite column is to small for a header |
180 | case RemoteDesktopsModel::Title: |
181 | return i18nc("Header of the connections list, title/url for remote connection" , "Remote Desktop" ); |
182 | case RemoteDesktopsModel::LastConnected: |
183 | return i18nc("Header of the connections list, the last time this connection was initiated" , "Last Connected" ); |
184 | case RemoteDesktopsModel::VisitCount: |
185 | return i18nc("Header of the connections list, the number of times this connection has been visited" , "Visits" ); |
186 | case RemoteDesktopsModel::Created: |
187 | return i18nc("Header of the connections list, the time when this entry was created" , "Created" ); |
188 | case RemoteDesktopsModel::Source: |
189 | return i18nc("Header of the connections list, where this entry comes from" , "Source" ); |
190 | } |
191 | } |
192 | return QVariant(); |
193 | } |
194 | |
195 | // does not trigger view update, you must do this by hand after using this function |
196 | void RemoteDesktopsModel::removeAllItemsFromSources(RemoteDesktop::Sources sources) |
197 | { |
198 | QMutableListIterator<RemoteDesktop> iter(remoteDesktops); |
199 | while (iter.hasNext()) { |
200 | iter.next(); |
201 | // if it matches any of the specified sources, remove it |
202 | if ((iter.value().source & sources) > 0) |
203 | iter.remove(); |
204 | } |
205 | } |
206 | |
207 | void RemoteDesktopsModel::bookmarksChanged() |
208 | { |
209 | kDebug(5010); |
210 | removeAllItemsFromSources(RemoteDesktop::Bookmarks | RemoteDesktop::History); |
211 | buildModelFromBookmarkGroup(m_manager->root()); |
212 | reset(); |
213 | } |
214 | |
215 | // Danger Will Roobinson, confusing code ahead! |
216 | void RemoteDesktopsModel::buildModelFromBookmarkGroup(const KBookmarkGroup &group) |
217 | { |
218 | KBookmark bm = group.first(); |
219 | while (!bm.isNull()) { |
220 | if (bm.isGroup()) { |
221 | // recurse subfolders and treat it special if it is the history folder |
222 | buildModelFromBookmarkGroup(bm.toGroup()); |
223 | } else { // not a group |
224 | |
225 | RemoteDesktop item; |
226 | item.title = bm.fullText(); |
227 | item.url = bm.url().url(); |
228 | int index = remoteDesktops.indexOf(item); //search for this url to see if we need to update it |
229 | bool newItem = index < 0; // do we need to create a new item? |
230 | |
231 | // we want to merge all copies of a url into one link, so if the item exists, update it |
232 | if (group.metaDataItem("krdc-history" ) == "historyfolder" ) { |
233 | // set source and favorite (will override later if needed) |
234 | item.source = RemoteDesktop::History; |
235 | item.favorite = false; |
236 | |
237 | // since we are in the history folder collect statitics and add them |
238 | KDateTime connected = KDateTime(); |
239 | KDateTime created = KDateTime(); |
240 | bool ok = false; |
241 | // first the created datetime |
242 | created.setTime_t(bm.metaDataItem("time_added" ).toLongLong(&ok)); |
243 | if (ok) (newItem ? item : remoteDesktops[index]).created = created; |
244 | // then the last visited datetime |
245 | ok = false; |
246 | connected.setTime_t(bm.metaDataItem("time_visited" ).toLongLong(&ok)); |
247 | if (ok) (newItem ? item : remoteDesktops[index]).lastConnected = connected; |
248 | // finally the visited count |
249 | ok = false; |
250 | int visits = bm.metaDataItem("visit_count" ).toInt(&ok); |
251 | if (ok) (newItem ? item : remoteDesktops[index]).visits = visits; |
252 | } else { |
253 | if (newItem) { |
254 | // if this is a new item, just add the rest of the required data |
255 | item.lastConnected = KDateTime(); |
256 | item.created = KDateTime(); |
257 | item.visits = 0; |
258 | item.favorite = true; |
259 | item.source = RemoteDesktop::Bookmarks; |
260 | } else { |
261 | // otherwise override these fields with the info from the bookmark |
262 | remoteDesktops[index].title = bm.fullText(); |
263 | remoteDesktops[index].favorite = true; |
264 | remoteDesktops[index].source = RemoteDesktop::Bookmarks; |
265 | } |
266 | } |
267 | // if we have a new item, add it |
268 | if (newItem) |
269 | remoteDesktops.append(item); |
270 | } |
271 | bm = group.next(bm); // next item in the group |
272 | } |
273 | } |
274 | |
275 | #ifdef BUILD_ZEROCONF |
276 | void RemoteDesktopsModel::servicesChanged() |
277 | { |
278 | //redo list because it is easier than finding and removing one that disappeared |
279 | QList<DNSSD::RemoteService::Ptr> services = zeroconfBrowser->services(); |
280 | KUrl url; |
281 | removeAllItemsFromSources(RemoteDesktop::Zeroconf); |
282 | foreach(DNSSD::RemoteService::Ptr service, services) { |
283 | url.setProtocol(m_protocols[service->type()].toLower()); |
284 | url.setHost(service->hostName()); |
285 | url.setPort(service->port()); |
286 | |
287 | RemoteDesktop item; |
288 | item.url = url.url(); |
289 | |
290 | if (!remoteDesktops.contains(item)) { |
291 | item.title = service->serviceName(); |
292 | item.source = RemoteDesktop::Zeroconf; |
293 | item.created = KDateTime::currentLocalDateTime(); |
294 | item.favorite = false; |
295 | item.visits = 0; |
296 | remoteDesktops.append(item); |
297 | } |
298 | } |
299 | reset(); |
300 | } |
301 | #endif |
302 | |
303 | #include "remotedesktopsmodel.moc" |
304 | |