Warning, file /network/krdc/remotedesktopsmodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2008 Urs Wolfer <uwolfer@kde.org>
0003     SPDX-FileCopyrightText: 2009 Tony Murray <murraytony@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "remotedesktopsmodel.h"
0009 #include "krdc_debug.h"
0010 
0011 #include <KLocalizedString>
0012 #include <KFormat>
0013 #ifdef BUILD_ZEROCONF
0014 #include <kdnssd_version.h>
0015 #include <KDNSSD/ServiceBrowser>
0016 #include <KDNSSD/RemoteService>
0017 #endif
0018 #include <QLoggingCategory>
0019 #include <QStandardPaths>
0020 #include <QObject>
0021 
0022 RemoteDesktopsModel::RemoteDesktopsModel(QObject *parent, KBookmarkManager *manager)
0023         : QAbstractTableModel(parent)
0024 {
0025     m_manager = manager;
0026     m_manager->setUpdate(true);
0027     connect(m_manager, SIGNAL(changed(QString,QString)), SLOT(bookmarksChanged()));
0028     buildModelFromBookmarkGroup(m_manager->root());
0029 
0030 #ifdef BUILD_ZEROCONF
0031     // Add RDP and NX if they start announcing via Zeroconf:
0032     m_protocols[QLatin1String("_rfb._tcp")] = QLatin1String("vnc");
0033 
0034     zeroconfBrowser = new KDNSSD::ServiceBrowser(QLatin1String("_rfb._tcp"), true);
0035     connect(zeroconfBrowser, SIGNAL(finished()), this, SLOT(servicesChanged()));
0036     zeroconfBrowser->startBrowse();
0037     qCDebug(KRDC) << "Browsing for zeroconf hosts.";
0038 #endif
0039 }
0040 
0041 RemoteDesktopsModel::~RemoteDesktopsModel()
0042 {
0043 }
0044 
0045 int RemoteDesktopsModel::columnCount(const QModelIndex &) const
0046 {
0047     return 6;  // same as count of RemoteDesktopsModel::DisplayItems enum
0048 }
0049 
0050 int RemoteDesktopsModel::rowCount(const QModelIndex &) const
0051 {
0052     return remoteDesktops.size();
0053 }
0054 
0055 Qt::ItemFlags RemoteDesktopsModel::flags(const QModelIndex &index) const
0056 {
0057     if (!index.isValid())
0058         return Qt::NoItemFlags;
0059     if (index.column() == RemoteDesktopsModel::Favorite) {
0060         return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
0061     }
0062     return Qt::ItemIsEnabled;
0063 }
0064 
0065 bool RemoteDesktopsModel::setData(const QModelIndex &index, const QVariant &value, int role)
0066 {
0067     if (index.isValid() && role == Qt::CheckStateRole && index.column() == RemoteDesktopsModel::Favorite) {
0068         bool checked = (Qt::CheckState)value.toUInt() == Qt::Checked;
0069         remoteDesktops[index.row()].favorite = checked;
0070 
0071         RemoteDesktop rd = remoteDesktops.at(index.row());
0072         if (checked) {
0073             KBookmarkGroup root = m_manager->root();
0074             root.addBookmark(rd.title, QUrl(rd.url), QString());
0075             m_manager->emitChanged(root);
0076         } else {
0077             BookmarkManager::removeByUrl(m_manager, rd.url, true, rd.title);
0078         }
0079         return true;
0080     }
0081     return false;
0082 }
0083 
0084 QVariant RemoteDesktopsModel::data(const QModelIndex &index, int role) const
0085 {
0086     if (!index.isValid())
0087         return QVariant();
0088 
0089     RemoteDesktop item = remoteDesktops.at(index.row());
0090 
0091     switch (role) {
0092     case Qt::DisplayRole:
0093         switch (index.column()) {
0094         case RemoteDesktopsModel::Favorite:
0095             return item.favorite;
0096         case RemoteDesktopsModel::Title:
0097             return item.title;
0098         case RemoteDesktopsModel::LastConnected:
0099             return QVariant(item.lastConnected);
0100         case RemoteDesktopsModel::VisitCount:
0101             return item.visits;
0102         case RemoteDesktopsModel::Created:
0103             if (item.created.isNull()) return QVariant();
0104             return QLocale().toString(item.created.toLocalTime(), QLocale::FormatType::ShortFormat);
0105         case RemoteDesktopsModel::Source:
0106             switch (item.source) {
0107             case RemoteDesktop::Bookmarks:
0108                 return i18nc("Where each displayed link comes from", "Bookmarks");
0109             case RemoteDesktop::History:
0110                 return i18nc("Where each displayed link comes from", "History");
0111             case RemoteDesktop::Zeroconf:
0112                 return i18nc("Where each displayed link comes from", "Zeroconf");
0113             case RemoteDesktop::None:
0114                 return i18nc("Where each displayed link comes from", "None");
0115             }
0116             // fall-through
0117         default:
0118             return QVariant();
0119         }
0120 
0121     case Qt::CheckStateRole:
0122         if (index.column() == RemoteDesktopsModel::Favorite)
0123             return item.favorite ? Qt::Checked : Qt::Unchecked;
0124         return QVariant();
0125 
0126     case Qt::ToolTipRole:
0127         switch(index.column()) {
0128         case RemoteDesktopsModel::Favorite:
0129             if (item.favorite) {
0130                 return i18nc("Remove the selected url from the bookarks menu", "Remove the bookmark for %1.", item.title);
0131             } else {
0132                 return i18nc("Add the selected url to the bookmarks menu", "Bookmark %1.", item.title);
0133             }
0134         case RemoteDesktopsModel::LastConnected:
0135             if (!item.lastConnected.isNull()) {
0136                 return QLocale().toString(item.lastConnected.toLocalTime(), QLocale::FormatType::LongFormat);
0137             }
0138             break; // else show default tooltip
0139         case RemoteDesktopsModel::Created:
0140             if (!item.created.isNull()) {
0141                 return QLocale().toString(item.lastConnected.toLocalTime(), QLocale::FormatType::LongFormat);
0142             }
0143             break; // else show default tooltip
0144         default:
0145             break;
0146         }
0147         return item.url;  //use the url for the tooltip
0148 
0149     case 10001: //url for dockwidget
0150         return item.url;
0151 
0152     case 10002: //filter
0153         return QUrl::fromPercentEncoding(QString(item.url + item.title).toUtf8()); // return both user visible title and url data, percent encoded
0154 
0155     case 10003: //title for dockwidget
0156         return item.title;
0157 
0158     default:
0159         return QVariant();
0160     }
0161 }
0162 
0163 QVariant RemoteDesktopsModel::headerData(int section, Qt::Orientation orientation,
0164         int role) const
0165 {
0166     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
0167         switch (section) {
0168         case RemoteDesktopsModel::Favorite:
0169             return QVariant(); // the favorite column is to small for a header
0170         case RemoteDesktopsModel::Title:
0171             return i18nc("Header of the connections list, title/url for remote connection", "Remote Desktop");
0172         case RemoteDesktopsModel::LastConnected:
0173             return i18nc("Header of the connections list, the last time this connection was initiated", "Last Connected");
0174         case RemoteDesktopsModel::VisitCount:
0175             return i18nc("Header of the connections list, the number of times this connection has been visited", "Visits");
0176         case RemoteDesktopsModel::Created:
0177             return i18nc("Header of the connections list, the time when this entry was created", "Created");
0178         case RemoteDesktopsModel::Source:
0179             return i18nc("Header of the connections list, where this entry comes from", "Source");
0180         }
0181     }
0182     return QVariant();
0183 }
0184 
0185 // does not trigger view update, you must do this by hand after using this function
0186 void RemoteDesktopsModel::removeAllItemsFromSources(RemoteDesktop::Sources sources)
0187 {
0188     QMutableListIterator<RemoteDesktop> iter(remoteDesktops);
0189     while (iter.hasNext()) {
0190         iter.next();
0191         // if it matches any of the specified sources, remove it
0192         if ((iter.value().source & sources) > 0)
0193             iter.remove();
0194     }
0195 }
0196 
0197 void RemoteDesktopsModel::bookmarksChanged()
0198 {
0199     removeAllItemsFromSources(RemoteDesktop::Bookmarks | RemoteDesktop::History);
0200     buildModelFromBookmarkGroup(m_manager->root());
0201     beginResetModel();
0202     endResetModel();
0203 }
0204 
0205 // Danger Will Roobinson, confusing code ahead!
0206 void RemoteDesktopsModel::buildModelFromBookmarkGroup(const KBookmarkGroup &group)
0207 {
0208     KBookmark bm = group.first();
0209     while (!bm.isNull()) {
0210         if (bm.isGroup()) {
0211             // recurse subfolders and treat it special if it is the history folder
0212             buildModelFromBookmarkGroup(bm.toGroup());
0213         } else { // not a group
0214 
0215             RemoteDesktop item;
0216             item.title = bm.fullText();
0217             item.url = bm.url().url();
0218             int index = remoteDesktops.indexOf(item); //search for this url to see if we need to update it
0219             bool newItem = index < 0; // do we need to create a new item?
0220 
0221             // we want to merge all copies of a url into one link, so if the item exists, update it
0222             if (group.metaDataItem(QLatin1String("krdc-history")) == QLatin1String("historyfolder")) {
0223                 // set source and favorite (will override later if needed)
0224                 item.source = RemoteDesktop::History;
0225                 item.favorite = false;
0226 
0227                 // since we are in the history folder collect statistics and add them
0228                 QDateTime connected = QDateTime();
0229                 QDateTime created = QDateTime();
0230                 bool ok = false;
0231                 // first the created datetime
0232                 created = QDateTime::fromSecsSinceEpoch(bm.metaDataItem(QLatin1String("time_added")).toLongLong(&ok));
0233                 if (ok) (newItem ? item : remoteDesktops[index]).created = created;
0234                 // then the last visited datetime
0235                 ok = false;
0236                 connected = QDateTime::fromSecsSinceEpoch(bm.metaDataItem(QLatin1String("time_visited")).toLongLong(&ok));
0237                 if (ok) (newItem ? item : remoteDesktops[index]).lastConnected = connected;
0238                 // finally the visited count
0239                 ok = false;
0240                 int visits = bm.metaDataItem(QLatin1String("visit_count")).toInt(&ok);
0241                 if (ok) (newItem ? item : remoteDesktops[index]).visits = visits;
0242             } else {
0243                 if (newItem) {
0244                     // if this is a new item, just add the rest of the required data
0245                     item.lastConnected = QDateTime();
0246                     item.created = QDateTime();
0247                     item.visits = 0;
0248                     item.favorite = true;
0249                     item.source = RemoteDesktop::Bookmarks;
0250                 } else {
0251                     // otherwise override these fields with the info from the bookmark
0252                     remoteDesktops[index].title = bm.fullText();
0253                     remoteDesktops[index].favorite = true;
0254                     remoteDesktops[index].source = RemoteDesktop::Bookmarks;
0255                 }
0256             }
0257             // if we have a new item, add it
0258             if (newItem)
0259                 remoteDesktops.append(item);
0260         }
0261         bm = group.next(bm); // next item in the group
0262     }
0263 }
0264 
0265 #ifdef BUILD_ZEROCONF
0266 void RemoteDesktopsModel::servicesChanged()
0267 {
0268     //redo list because it is easier than finding and removing one that disappeared
0269     const QList<KDNSSD::RemoteService::Ptr> services = zeroconfBrowser->services();
0270     QUrl url;
0271     removeAllItemsFromSources(RemoteDesktop::Zeroconf);
0272     for (const KDNSSD::RemoteService::Ptr& service : services) {
0273         url.setScheme(m_protocols[service->type()].toLower());
0274         url.setHost(service->hostName());
0275         url.setPort(service->port());
0276 
0277         RemoteDesktop item;
0278         item.url = url.url();
0279 
0280         if (!remoteDesktops.contains(item)) {
0281             item.title = service->serviceName();
0282             item.source = RemoteDesktop::Zeroconf;
0283             item.created = QDateTime::currentDateTime();
0284             item.favorite = false;
0285             item.visits = 0;
0286             remoteDesktops.append(item);
0287         }
0288     }
0289     beginResetModel();
0290     endResetModel();
0291 }
0292 #endif
0293