remotedesktopsmodel.cpp 11.8 KB
Newer Older
1 2 3
/****************************************************************************
**
** Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org>
4
** Copyright (C) 2009 Tony Murray <murraytony@gmail.com>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
**
** This file is part of KDE.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; see the file COPYING. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
****************************************************************************/

#include "remotedesktopsmodel.h"
26
#include "krdc_debug.h"
27

28
#include <KLocalizedString>
29 30 31 32 33 34
#include<KCoreAddons/KFormat>
#include <DNSSD/ServiceBrowser>
#include <QDateTime>
#include <QLoggingCategory>
#include <QStandardPaths>
#include <QObject>
35

36
RemoteDesktopsModel::RemoteDesktopsModel(QObject *parent, KBookmarkManager *manager)
Tony Murray's avatar
Tony Murray committed
37
        : QAbstractTableModel(parent)
38
{
39
    m_manager = manager;
40
    m_manager->setUpdate(true);
Laurent Montel's avatar
Laurent Montel committed
41
    connect(m_manager, SIGNAL(changed(QString,QString)), SLOT(bookmarksChanged()));
Tony Murray's avatar
Tony Murray committed
42
    buildModelFromBookmarkGroup(m_manager->root());
43

44 45
#ifdef BUILD_ZEROCONF
    // Add RDP and NX if they start announcing via Zeroconf:
46
    m_protocols[QLatin1String("_rfb._tcp")] = QLatin1String("vnc");
47

48
    zeroconfBrowser = new KDNSSD::ServiceBrowser(QLatin1String("_rfb._tcp"), true);
49 50
    connect(zeroconfBrowser, SIGNAL(finished()), this, SLOT(servicesChanged()));
    zeroconfBrowser->startBrowse();
51
    qCDebug(KRDC) << "Browsing for zeroconf hosts.";
52
#endif
53 54 55 56 57 58
}

RemoteDesktopsModel::~RemoteDesktopsModel()
{
}

Tony Murray's avatar
Tony Murray committed
59
int RemoteDesktopsModel::columnCount(const QModelIndex &) const
60
{
61
    return 6;  // same as count of RemoteDesktopsModel::DisplayItems enum
Tony Murray's avatar
Tony Murray committed
62
}
Tony Murray's avatar
Tony Murray committed
63

Tony Murray's avatar
Tony Murray committed
64 65 66
int RemoteDesktopsModel::rowCount(const QModelIndex &) const
{
    return remoteDesktops.size();
67 68
}

Tony Murray's avatar
Tony Murray committed
69
Qt::ItemFlags RemoteDesktopsModel::flags(const QModelIndex &index) const
70
{
Tony Murray's avatar
Tony Murray committed
71
    if (!index.isValid())
Kevin Funk's avatar
Kevin Funk committed
72
        return nullptr;
Tony Murray's avatar
Tony Murray committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    if (index.column() == RemoteDesktopsModel::Favorite) {
        return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
    }
    return Qt::ItemIsEnabled;
}

bool RemoteDesktopsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::CheckStateRole && index.column() == RemoteDesktopsModel::Favorite) {
        bool checked = (Qt::CheckState)value.toUInt() == Qt::Checked;
        remoteDesktops[index.row()].favorite = checked;

        RemoteDesktop rd = remoteDesktops.at(index.row());
        if (checked) {
            KBookmarkGroup root = m_manager->root();
88
            root.addBookmark(rd.title, QUrl(rd.url), QString());
Tony Murray's avatar
Tony Murray committed
89 90 91 92 93 94 95
            m_manager->emitChanged(root);
        } else {
            BookmarkManager::removeByUrl(m_manager, rd.url, true, rd.title);
        }
        return true;
    }
    return false;
96 97 98 99 100 101 102
}

QVariant RemoteDesktopsModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

Tony Murray's avatar
Tony Murray committed
103
    RemoteDesktop item = remoteDesktops.at(index.row());
104

105 106
    switch (role) {
    case Qt::DisplayRole:
Tony Murray's avatar
Tony Murray committed
107 108 109 110 111 112
        switch (index.column()) {
        case RemoteDesktopsModel::Favorite:
            return item.favorite;
        case RemoteDesktopsModel::Title:
            return item.title;
        case RemoteDesktopsModel::LastConnected:
113
            return QVariant(item.lastConnected);
114 115 116 117
        case RemoteDesktopsModel::VisitCount:
            return item.visits;
        case RemoteDesktopsModel::Created:
            if (item.created.isNull()) return QVariant();
118
            return QLocale().toString(item.created.toLocalTime(), QLocale::FormatType::ShortFormat);
Tony Murray's avatar
Tony Murray committed
119 120 121 122 123 124 125 126 127 128 129
        case RemoteDesktopsModel::Source:
            switch (item.source) {
            case RemoteDesktop::Bookmarks:
                return i18nc("Where each displayed link comes from", "Bookmarks");
            case RemoteDesktop::History:
                return i18nc("Where each displayed link comes from", "History");
            case RemoteDesktop::Zeroconf:
                return i18nc("Where each displayed link comes from", "Zeroconf");
            case RemoteDesktop::None:
                return i18nc("Where each displayed link comes from", "None");
            }
Albert Astals Cid's avatar
Albert Astals Cid committed
130
            // fall-through
Tony Murray's avatar
Tony Murray committed
131 132 133
        default:
            return QVariant();
        }
134

Tony Murray's avatar
Tony Murray committed
135 136 137 138
    case Qt::CheckStateRole:
        if (index.column() == RemoteDesktopsModel::Favorite)
            return item.favorite ? Qt::Checked : Qt::Unchecked;
        return QVariant();
139

140
    case Qt::ToolTipRole:
141 142 143 144 145 146 147 148 149
        switch(index.column()) {
        case RemoteDesktopsModel::Favorite:
            if (item.favorite) {
                return i18nc("Remove the selected url from the bookarks menu", "Remove the bookmark for %1.", item.title);
            } else {
                return i18nc("Add the selected url to the bookmarks menu", "Bookmark %1.", item.title);
            }
        case RemoteDesktopsModel::LastConnected:
            if (!item.lastConnected.isNull()) {
150
                return QLocale().toString(item.lastConnected.toLocalTime(), QLocale::FormatType::LongFormat);
151 152 153 154
            }
            break; // else show default tooltip
        case RemoteDesktopsModel::Created:
            if (!item.created.isNull()) {
155
                return QLocale().toString(item.lastConnected.toLocalTime(), QLocale::FormatType::LongFormat);
156 157
            }
            break; // else show default tooltip
158
        default:
159
            break;
160
        }
161
        return item.url;  //use the url for the tooltip
162

163
    case 10001: //url for dockwidget
Tony Murray's avatar
Tony Murray committed
164
        return item.url;
165

166
    case 10002: //filter
167
        return QUrl::fromPercentEncoding(QString(item.url + item.title).toUtf8()); // return both user visible title and url data, percent encoded
168

169
    case 10003: //title for dockwidget
170 171
        return item.title;

172 173 174
    default:
        return QVariant();
    }
175 176 177
}

QVariant RemoteDesktopsModel::headerData(int section, Qt::Orientation orientation,
Tony Murray's avatar
Tony Murray committed
178
        int role) const
179
{
Tony Murray's avatar
Tony Murray committed
180 181 182 183 184
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        switch (section) {
        case RemoteDesktopsModel::Favorite:
            return QVariant(); // the favorite column is to small for a header
        case RemoteDesktopsModel::Title:
185
            return i18nc("Header of the connections list, title/url for remote connection", "Remote Desktop");
Tony Murray's avatar
Tony Murray committed
186
        case RemoteDesktopsModel::LastConnected:
187 188 189 190 191
            return i18nc("Header of the connections list, the last time this connection was initiated", "Last Connected");
        case RemoteDesktopsModel::VisitCount:
            return i18nc("Header of the connections list, the number of times this connection has been visited", "Visits");
        case RemoteDesktopsModel::Created:
            return i18nc("Header of the connections list, the time when this entry was created", "Created");
Tony Murray's avatar
Tony Murray committed
192
        case RemoteDesktopsModel::Source:
193
            return i18nc("Header of the connections list, where this entry comes from", "Source");
Tony Murray's avatar
Tony Murray committed
194 195
        }
    }
196 197 198
    return QVariant();
}

Tony Murray's avatar
Tony Murray committed
199 200
// does not trigger view update, you must do this by hand after using this function
void RemoteDesktopsModel::removeAllItemsFromSources(RemoteDesktop::Sources sources)
201
{
Tony Murray's avatar
Tony Murray committed
202 203 204 205 206 207 208
    QMutableListIterator<RemoteDesktop> iter(remoteDesktops);
    while (iter.hasNext()) {
        iter.next();
        // if it matches any of the specified sources, remove it
        if ((iter.value().source & sources) > 0)
            iter.remove();
    }
209 210
}

Tony Murray's avatar
Tony Murray committed
211
void RemoteDesktopsModel::bookmarksChanged()
212
{
Tony Murray's avatar
Tony Murray committed
213 214
    removeAllItemsFromSources(RemoteDesktop::Bookmarks | RemoteDesktop::History);
    buildModelFromBookmarkGroup(m_manager->root());
215 216
    beginResetModel();
    endResetModel();
217 218
}

219
// Danger Will Roobinson, confusing code ahead!
Tony Murray's avatar
Tony Murray committed
220
void RemoteDesktopsModel::buildModelFromBookmarkGroup(const KBookmarkGroup &group)
221 222 223
{
    KBookmark bm = group.first();
    while (!bm.isNull()) {
Tony Murray's avatar
Tony Murray committed
224 225 226 227 228 229
        if (bm.isGroup()) {
            // recurse subfolders and treat it special if it is the history folder
            buildModelFromBookmarkGroup(bm.toGroup());
        } else { // not a group

            RemoteDesktop item;
Tony Murray's avatar
Tony Murray committed
230
            item.title = bm.fullText();
Tony Murray's avatar
Tony Murray committed
231
            item.url = bm.url().url();
232 233
            int index = remoteDesktops.indexOf(item); //search for this url to see if we need to update it
            bool newItem = index < 0; // do we need to create a new item?
Tony Murray's avatar
Tony Murray committed
234 235

            // we want to merge all copies of a url into one link, so if the item exists, update it
236
            if (group.metaDataItem(QLatin1String("krdc-history")) == QLatin1String("historyfolder")) {
237 238 239 240 241
                // set source and favorite (will override later if needed)
                item.source = RemoteDesktop::History;
                item.favorite = false;

                // since we are in the history folder collect statitics and add them
242 243
                QDateTime connected = QDateTime();
                QDateTime created = QDateTime();
Tony Murray's avatar
Tony Murray committed
244
                bool ok = false;
245
                // first the created datetime
246
                created.setTime_t(bm.metaDataItem(QLatin1String("time_added")).toLongLong(&ok));
247 248 249
                if (ok) (newItem ? item : remoteDesktops[index]).created = created;
                // then the last visited datetime
                ok = false;
250
                connected.setTime_t(bm.metaDataItem(QLatin1String("time_visited")).toLongLong(&ok));
251 252 253
                if (ok) (newItem ? item : remoteDesktops[index]).lastConnected = connected;
                // finally the visited count
                ok = false;
254
                int visits = bm.metaDataItem(QLatin1String("visit_count")).toInt(&ok);
255
                if (ok) (newItem ? item : remoteDesktops[index]).visits = visits;
Tony Murray's avatar
Tony Murray committed
256 257
            } else {
                if (newItem) {
258
                    // if this is a new item, just add the rest of the required data
259 260
                    item.lastConnected = QDateTime();
                    item.created = QDateTime();
261
                    item.visits = 0;
Tony Murray's avatar
Tony Murray committed
262 263 264
                    item.favorite = true;
                    item.source = RemoteDesktop::Bookmarks;
                } else {
265
                    // otherwise override these fields with the info from the bookmark
Tony Murray's avatar
Tony Murray committed
266
                    remoteDesktops[index].title = bm.fullText();
Tony Murray's avatar
Tony Murray committed
267
                    remoteDesktops[index].favorite = true;
268
                    remoteDesktops[index].source = RemoteDesktop::Bookmarks;
Tony Murray's avatar
Tony Murray committed
269 270
                }
            }
271
            // if we have a new item, add it
Tony Murray's avatar
Tony Murray committed
272 273 274 275
            if (newItem)
                remoteDesktops.append(item);
        }
        bm = group.next(bm); // next item in the group
276 277 278
    }
}

279
#ifdef BUILD_ZEROCONF
Tony Murray's avatar
Tony Murray committed
280 281 282
void RemoteDesktopsModel::servicesChanged()
{
    //redo list because it is easier than finding and removing one that disappeared
283 284
    QList<KDNSSD::RemoteService::Ptr> services = zeroconfBrowser->services();
    QUrl url;
Tony Murray's avatar
Tony Murray committed
285
    removeAllItemsFromSources(RemoteDesktop::Zeroconf);
286 287
    foreach(KDNSSD::RemoteService::Ptr service, services) {
        url.setScheme(m_protocols[service->type()].toLower());
288 289
        url.setHost(service->hostName());
        url.setPort(service->port());
290

Tony Murray's avatar
Tony Murray committed
291 292
        RemoteDesktop item;
        item.url = url.url();
293

Tony Murray's avatar
Tony Murray committed
294 295 296
        if (!remoteDesktops.contains(item)) {
            item.title = service->serviceName();
            item.source = RemoteDesktop::Zeroconf;
297
            item.created = QDateTime::currentDateTime();
Tony Murray's avatar
Tony Murray committed
298
            item.favorite = false;
299
            item.visits = 0;
Tony Murray's avatar
Tony Murray committed
300
            remoteDesktops.append(item);
301 302
        }
    }
303 304
    beginResetModel();
    endResetModel();
305 306 307
}
#endif