diff --git a/core/smb4kbookmarkhandler_p.cpp b/core/smb4kbookmarkhandler_p.cpp index ce25f1d..799a85b 100644 --- a/core/smb4kbookmarkhandler_p.cpp +++ b/core/smb4kbookmarkhandler_p.cpp @@ -1,993 +1,969 @@ /*************************************************************************** Private classes for the bookmark handler ------------------- begin : Sun Mar 20 2011 copyright : (C) 2011-2018 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, 51 Franklin Street, Suite 500, Boston, * * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4kbookmarkhandler_p.h" #include "smb4ksettings.h" #include "smb4kbookmark.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #define TRANSLATION_DOMAIN "smb4k-core" #include #include #include Smb4KBookmarkDialog::Smb4KBookmarkDialog(const QList &bookmarks, const QStringList &groups, QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Add Bookmarks")); setupView(); loadLists(bookmarks, groups); KConfigGroup group(Smb4KSettings::self()->config(), "BookmarkDialog"); KWindowConfig::restoreWindowSize(windowHandle(), group); m_label_edit->completionObject()->setItems(group.readEntry("LabelCompletion", QStringList())); m_group_combo->completionObject()->setItems(group.readEntry("GroupCompletion", m_groups)); connect(KIconLoader::global(), SIGNAL(iconChanged(int)), SLOT(slotIconSizeChanged(int))); } Smb4KBookmarkDialog::~Smb4KBookmarkDialog() { while (!m_bookmarks.isEmpty()) { m_bookmarks.takeFirst().clear(); } } const QList &Smb4KBookmarkDialog::bookmarks() { return m_bookmarks; } void Smb4KBookmarkDialog::setupView() { QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(5); QWidget *description = new QWidget(this); QHBoxLayout *desc_layout = new QHBoxLayout(description); desc_layout->setSpacing(5); desc_layout->setMargin(0); QLabel *pixmap = new QLabel(description); QPixmap sync_pix = KDE::icon("bookmark-new").pixmap(KIconLoader::SizeHuge); pixmap->setPixmap(sync_pix); pixmap->setAlignment(Qt::AlignBottom); QLabel *label = new QLabel(i18n("All listed shares will be bookmarked. To edit the label " "or group, click the respective bookmark entry."), description); label->setWordWrap(true); label->setAlignment(Qt::AlignBottom); desc_layout->addWidget(pixmap, 0); desc_layout->addWidget(label, Qt::AlignBottom); m_widget = new QListWidget(this); m_widget->setSortingEnabled(true); m_widget->setSelectionMode(QAbstractItemView::SingleSelection); int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small); m_widget->setIconSize(QSize(icon_size, icon_size)); m_editors = new QWidget(this); m_editors->setEnabled(false); QGridLayout *editors_layout = new QGridLayout(m_editors); editors_layout->setSpacing(5); editors_layout->setMargin(0); QLabel *l_label = new QLabel(i18n("Label:"), m_editors); m_label_edit = new KLineEdit(m_editors); m_label_edit->setClearButtonEnabled(true); QLabel *g_label = new QLabel(i18n("Group:"), m_editors); m_group_combo = new KComboBox(true, m_editors); editors_layout->addWidget(l_label, 0, 0, 0); editors_layout->addWidget(m_label_edit, 0, 1, 0); editors_layout->addWidget(g_label, 1, 0, 0); editors_layout->addWidget(m_group_combo, 1, 1, 0); QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this); m_ok_button = buttonBox->addButton(QDialogButtonBox::Ok); m_cancel_button = buttonBox->addButton(QDialogButtonBox::Cancel); m_ok_button->setShortcut(Qt::CTRL|Qt::Key_Return); m_cancel_button->setShortcut(Qt::Key_Escape); m_ok_button->setDefault(true); layout->addWidget(description, 0); layout->addWidget(m_widget, 0); layout->addWidget(m_editors, 0); layout->addWidget(buttonBox, 0); setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); - connect(m_widget, SIGNAL(itemClicked(QListWidgetItem*)), - this, SLOT(slotBookmarkClicked(QListWidgetItem*))); - - connect(m_label_edit, SIGNAL(editingFinished()), - this, SLOT(slotLabelEdited())); - - connect(m_group_combo->lineEdit(), SIGNAL(editingFinished()), - this, SLOT(slotGroupEdited())); - - connect(m_ok_button, SIGNAL(clicked()), - this, SLOT(slotDialogAccepted())); - - connect(m_cancel_button, SIGNAL(clicked()), - this, SLOT(reject())); + // + // Connections + // + connect(m_widget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotBookmarkClicked(QListWidgetItem*))); + connect(m_label_edit, SIGNAL(editingFinished()), this, SLOT(slotLabelEdited())); + connect(m_group_combo->lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotGroupEdited())); + connect(m_ok_button, SIGNAL(clicked()), this, SLOT(slotDialogAccepted())); + connect(m_cancel_button, SIGNAL(clicked()), this, SLOT(reject())); } void Smb4KBookmarkDialog::loadLists(const QList &bookmarks, const QStringList &groups) { // Copy the bookmarks to the internal list and add them to // the list widget afterwards. for (const BookmarkPtr &b : bookmarks) { QListWidgetItem *item = new QListWidgetItem(b->icon(), b->displayString(), m_widget); item->setData(Qt::UserRole, static_cast(b->url())); m_bookmarks << b; } m_groups = groups; m_group_combo->addItems(m_groups); } BookmarkPtr Smb4KBookmarkDialog::findBookmark(const QUrl &url) { BookmarkPtr bookmark; for (const BookmarkPtr &b : m_bookmarks) { if (b->url() == url) { bookmark = b; break; } else { continue; } } return bookmark; } void Smb4KBookmarkDialog::slotBookmarkClicked(QListWidgetItem *bookmark_item) { if (bookmark_item) { // Enable the editor widgets if necessary if (!m_editors->isEnabled()) { m_editors->setEnabled(true); } QUrl url = bookmark_item->data(Qt::UserRole).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { m_label_edit->setText(bookmark->label()); m_group_combo->setCurrentItem(bookmark->groupName()); } else { m_label_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } else { m_label_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } void Smb4KBookmarkDialog::slotLabelEdited() { // Set the label QUrl url = m_widget->currentItem()->data(Qt::UserRole).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setLabel(m_label_edit->userText()); } // Add label to completion object KCompletion *completion = m_label_edit->completionObject(); if (!m_label_edit->userText().isEmpty()) { completion->addItem(m_label_edit->userText()); } } void Smb4KBookmarkDialog::slotGroupEdited() { // Set the group QUrl url = m_widget->currentItem()->data(Qt::UserRole).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setGroupName(m_group_combo->currentText()); } // Add the group name to the combo box if (m_group_combo->findText(m_group_combo->currentText()) == -1) { m_group_combo->addItem(m_group_combo->currentText()); } // Add group to completion object KCompletion *completion = m_group_combo->completionObject(); if (!m_group_combo->currentText().isEmpty()) { completion->addItem(m_group_combo->currentText()); } } void Smb4KBookmarkDialog::slotDialogAccepted() { KConfigGroup group(Smb4KSettings::self()->config(), "BookmarkDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); group.writeEntry("LabelCompletion", m_label_edit->completionObject()->items()); group.writeEntry("GroupCompletion", m_group_combo->completionObject()->items()); accept(); } void Smb4KBookmarkDialog::slotIconSizeChanged(int group) { switch (group) { case KIconLoader::Small: { int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small); m_widget->setIconSize(QSize(icon_size, icon_size)); break; } default: { break; } } } Smb4KBookmarkEditor::Smb4KBookmarkEditor(const QList &bookmarks, QWidget *parent) : QDialog(parent), m_bookmarks(bookmarks) { // // Set the window title // setWindowTitle(i18n("Edit Bookmarks")); // // Setup the view // setupView(); // // Load the bookmarks into the editor // loadBookmarks(); // // Set the editor's minimum width // setMinimumWidth(sizeHint().height() > sizeHint().width() ? sizeHint().height() : sizeHint().width()); // // Load some other settings // KConfigGroup group(Smb4KSettings::self()->config(), "BookmarkEditor"); KWindowConfig::restoreWindowSize(windowHandle(), group); m_label_edit->completionObject()->setItems(group.readEntry("LabelCompletion", QStringList())); m_login_edit->completionObject()->setItems(group.readEntry("LoginCompletion", QStringList())); m_ip_edit->completionObject()->setItems(group.readEntry("IPCompletion", QStringList())); m_group_combo->completionObject()->setItems(group.readEntry("GroupCompletion", m_groups)); // // Connections // connect(KIconLoader::global(), SIGNAL(iconChanged(int)), SLOT(slotIconSizeChanged(int))); } Smb4KBookmarkEditor::~Smb4KBookmarkEditor() { while (!m_bookmarks.isEmpty()) { m_bookmarks.takeFirst().clear(); } } bool Smb4KBookmarkEditor::eventFilter(QObject *obj, QEvent *e) { if (obj == m_tree_widget->viewport()) { switch (e->type()) { case QEvent::DragEnter: { QDragEnterEvent *ev = static_cast(e); if (ev->source() == m_tree_widget->viewport()) { e->accept(); } else { e->ignore(); } break; } case QEvent::DragLeave: { e->ignore(); break; } case QEvent::Drop: { QTimer::singleShot(50, this, SLOT(slotAdjust())); break; } default: { break; } } } return QDialog::eventFilter(obj, e); } void Smb4KBookmarkEditor::setupView() { QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(5); m_tree_widget = new QTreeWidget(this); m_tree_widget->setColumnCount(2); m_tree_widget->hideColumn((m_tree_widget->columnCount() - 1)); // for sorting purposes m_tree_widget->headerItem()->setHidden(true); m_tree_widget->setRootIsDecorated(true); m_tree_widget->setSelectionMode(QAbstractItemView::SingleSelection); m_tree_widget->setContextMenuPolicy(Qt::CustomContextMenu); m_tree_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); m_tree_widget->setDragDropMode(QTreeWidget::InternalMove); int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small); m_tree_widget->setIconSize(QSize(icon_size, icon_size)); m_tree_widget->viewport()->installEventFilter(this); m_add_group = new QAction(KDE::icon("bookmark-add-folder"), i18n("Add Group"), m_tree_widget); m_delete = new QAction(KDE::icon("edit-delete"), i18n("Remove"), m_tree_widget); m_clear = new QAction(KDE::icon("edit-clear"), i18n("Clear"), m_tree_widget); m_menu = new KActionMenu(m_tree_widget); m_menu->addAction(m_add_group); m_menu->addAction(m_delete); m_menu->addAction(m_clear); m_editors = new QWidget(this); m_editors->setEnabled(false); QGridLayout *editors_layout = new QGridLayout(m_editors); editors_layout->setSpacing(5); editors_layout->setMargin(0); QLabel *l_label = new QLabel(i18n("Label:"), m_editors); m_label_edit = new KLineEdit(m_editors); m_label_edit->setClearButtonEnabled(true); QLabel *lg_label = new QLabel(i18n("Login:"), m_editors); m_login_edit = new KLineEdit(m_editors); m_login_edit->setClearButtonEnabled(true); QLabel *i_label = new QLabel(i18n("IP Address:"), m_editors); m_ip_edit = new KLineEdit(m_editors); m_ip_edit->setClearButtonEnabled(true); QLabel *g_label = new QLabel(i18n("Group:"), m_editors); m_group_combo = new KComboBox(true, m_editors); m_group_combo->setDuplicatesEnabled(false); editors_layout->addWidget(l_label, 0, 0, 0); editors_layout->addWidget(m_label_edit, 0, 1, 0); editors_layout->addWidget(lg_label, 1, 0, 0); editors_layout->addWidget(m_login_edit, 1, 1, 0); editors_layout->addWidget(i_label, 2, 0, 0); editors_layout->addWidget(m_ip_edit, 2, 1, 0); editors_layout->addWidget(g_label, 3, 0, 0); editors_layout->addWidget(m_group_combo, 3, 1, 0); QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this); m_ok_button = buttonBox->addButton(QDialogButtonBox::Ok); m_cancel_button = buttonBox->addButton(QDialogButtonBox::Cancel); m_ok_button->setShortcut(Qt::CTRL|Qt::Key_Return); m_cancel_button->setShortcut(Qt::Key_Escape); m_ok_button->setDefault(true); layout->addWidget(m_tree_widget); layout->addWidget(m_editors); layout->addWidget(buttonBox); - connect(m_tree_widget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), - this, SLOT(slotItemClicked(QTreeWidgetItem*,int))); - - connect(m_tree_widget, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(slotContextMenuRequested(QPoint))); - - connect(m_label_edit, SIGNAL(editingFinished()), - this, SLOT(slotLabelEdited())); - - connect(m_ip_edit, SIGNAL(editingFinished()), - this, SLOT(slotIPEdited())); - - connect(m_login_edit, SIGNAL(editingFinished()), - this, SLOT(slotLoginEdited())); - - connect(m_group_combo->lineEdit(), SIGNAL(editingFinished()), - this, SLOT(slotGroupEdited())); - - connect(m_add_group, SIGNAL(triggered(bool)), - this, SLOT(slotAddGroupTriggered(bool))); - - connect(m_delete, SIGNAL(triggered(bool)), - this, SLOT(slotDeleteTriggered(bool))); - - connect(m_clear, SIGNAL(triggered(bool)), - this, SLOT(slotClearTriggered(bool))); - - connect(m_ok_button, SIGNAL(clicked()), - this, SLOT(slotDialogAccepted())); - - connect(m_cancel_button, SIGNAL(clicked()), - this, SLOT(slotDialogRejected())); + // + // Connections + // + connect(m_tree_widget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotItemClicked(QTreeWidgetItem*,int))); + connect(m_tree_widget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenuRequested(QPoint))); + connect(m_label_edit, SIGNAL(editingFinished()), this, SLOT(slotLabelEdited())); + connect(m_ip_edit, SIGNAL(editingFinished()), this, SLOT(slotIPEdited())); + connect(m_login_edit, SIGNAL(editingFinished()), this, SLOT(slotLoginEdited())); + connect(m_group_combo->lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotGroupEdited())); + connect(m_add_group, SIGNAL(triggered(bool)), this, SLOT(slotAddGroupTriggered(bool))); + connect(m_delete, SIGNAL(triggered(bool)), this, SLOT(slotDeleteTriggered(bool))); + connect(m_clear, SIGNAL(triggered(bool)), this, SLOT(slotClearTriggered(bool))); + connect(m_ok_button, SIGNAL(clicked()), this, SLOT(slotDialogAccepted())); + connect(m_cancel_button, SIGNAL(clicked()), this, SLOT(slotDialogRejected())); } void Smb4KBookmarkEditor::loadBookmarks() { // // Clear the tree widget and the group combo box // m_tree_widget->clear(); m_group_combo->clear(); // // Copy the groups into the internal list // m_groups.clear(); for (const BookmarkPtr &bookmark : m_bookmarks) { if (!m_groups.contains(bookmark->groupName())) { m_groups << bookmark->groupName(); } } // // Insert the groups into the tree widget // for (const QString &group : m_groups) { if (!group.isEmpty()) { QTreeWidgetItem *groupItem = new QTreeWidgetItem(QTreeWidgetItem::UserType); groupItem->setIcon(0, KDE::icon("folder-bookmark")); groupItem->setText(0, group); groupItem->setText((m_tree_widget->columnCount() - 1), QString("00_%1").arg(group)); groupItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsDropEnabled); m_tree_widget->addTopLevelItem(groupItem); } } // // Insert the bookmarks info the tree widget // for (const BookmarkPtr &bookmark : m_bookmarks) { QTreeWidgetItem *bookmarkItem = new QTreeWidgetItem(QTreeWidgetItem::UserType); bookmarkItem->setData(0, QTreeWidgetItem::UserType, static_cast(bookmark->url())); bookmarkItem->setIcon(0, bookmark->icon()); bookmarkItem->setText(0, bookmark->displayString()); bookmarkItem->setText((m_tree_widget->columnCount() - 1), QString("01_%1").arg(bookmark->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort))); bookmarkItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled); if (!bookmark->groupName().isEmpty()) { QList items = m_tree_widget->findItems(bookmark->groupName(), Qt::MatchFixedString|Qt::MatchCaseSensitive, 0); if (!items.isEmpty()) { items.first()->addChild(bookmarkItem); items.first()->setExpanded(true); } } else { m_tree_widget->addTopLevelItem(bookmarkItem); } } // // Sort // for (int i = 0; i < m_tree_widget->topLevelItemCount(); ++i) { m_tree_widget->topLevelItem(i)->sortChildren((m_tree_widget->columnCount() - 1), Qt::AscendingOrder); } m_tree_widget->sortItems((m_tree_widget->columnCount() - 1), Qt::AscendingOrder); // // Check that an empty group entry is also present. If it is not there, // add it now and insert the groups to the group combo box afterwards. // if (!m_groups.contains("") && !m_groups.contains(QString())) { m_groups << ""; } m_group_combo->addItems(m_groups); m_group_combo->setCurrentItem(""); } QList Smb4KBookmarkEditor::editedBookmarks() { return m_bookmarks; } BookmarkPtr Smb4KBookmarkEditor::findBookmark(const QUrl &url) { BookmarkPtr bookmark; for (const BookmarkPtr &b : m_bookmarks) { if (b->url() == url) { bookmark = b; break; } else { continue; } } return bookmark; } void Smb4KBookmarkEditor::slotItemClicked(QTreeWidgetItem *item, int /*col*/) { if (item) { if (m_tree_widget->indexOfTopLevelItem(item) != -1) { // This is a top-level item, i.e. it is either a bookmark without // group or a group entry. // Bookmarks have an URL stored, group folders not. if (!item->data(0, QTreeWidgetItem::UserType).toUrl().isEmpty()) { BookmarkPtr bookmark = findBookmark(item->data(0, QTreeWidgetItem::UserType).toUrl()); if (bookmark) { m_label_edit->setText(bookmark->label()); m_login_edit->setText(bookmark->login()); m_ip_edit->setText(bookmark->hostIpAddress()); m_group_combo->setCurrentItem(bookmark->groupName()); m_editors->setEnabled(true); } else { m_label_edit->clear(); m_login_edit->clear(); m_ip_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } else { m_label_edit->clear(); m_login_edit->clear(); m_ip_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } else { // This can only be a bookmark. BookmarkPtr bookmark = findBookmark(item->data(0, QTreeWidgetItem::UserType).toUrl()); if (bookmark) { m_label_edit->setText(bookmark->label()); m_login_edit->setText(bookmark->login()); m_ip_edit->setText(bookmark->hostIpAddress()); m_group_combo->setCurrentItem(bookmark->groupName()); m_editors->setEnabled(true); } else { m_label_edit->clear(); m_login_edit->clear(); m_ip_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } } else { m_label_edit->clear(); m_login_edit->clear(); m_ip_edit->clear(); m_group_combo->clearEditText(); m_editors->setEnabled(false); } } void Smb4KBookmarkEditor::slotContextMenuRequested(const QPoint &pos) { QTreeWidgetItem *item = m_tree_widget->itemAt(pos); m_delete->setEnabled((item)); m_menu->menu()->popup(m_tree_widget->viewport()->mapToGlobal(pos)); } void Smb4KBookmarkEditor::slotLabelEdited() { // Set the label QUrl url = m_tree_widget->currentItem()->data(0, QTreeWidgetItem::UserType).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setLabel(m_label_edit->userText()); } // Add label to completion object KCompletion *completion = m_label_edit->completionObject(); if (!m_label_edit->userText().isEmpty()) { completion->addItem(m_label_edit->userText()); } } void Smb4KBookmarkEditor::slotLoginEdited() { // Set the login QUrl url = m_tree_widget->currentItem()->data(0, QTreeWidgetItem::UserType).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setLogin(m_login_edit->userText()); } // Add login to completion object KCompletion *completion = m_login_edit->completionObject(); if (!m_login_edit->userText().isEmpty()) { completion->addItem(m_login_edit->userText()); } } void Smb4KBookmarkEditor::slotIPEdited() { // Set the ip address QUrl url = m_tree_widget->currentItem()->data(0, QTreeWidgetItem::UserType).toUrl(); BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setHostIpAddress(m_ip_edit->userText()); } // Add login to completion object KCompletion *completion = m_ip_edit->completionObject(); if (!m_ip_edit->userText().isEmpty()) { completion->addItem(m_ip_edit->userText()); } } void Smb4KBookmarkEditor::slotGroupEdited() { // // Get the URL of the current item. // QUrl url = m_tree_widget->currentItem()->data(0, QTreeWidgetItem::UserType).toUrl(); // // Return here, if the current item is a group // if (url.isEmpty()) { return; } // // Set the group name to the bookmark // BookmarkPtr bookmark = findBookmark(url); if (bookmark) { bookmark->setGroupName(m_group_combo->currentText()); } // // Reload the bookmarks (The current item is cleared by this!) // loadBookmarks(); // // Reset the current item // QTreeWidgetItemIterator it(m_tree_widget); while (*it) { if ((*it)->data(0, QTreeWidgetItem::UserType).toUrl() == url) { m_tree_widget->setCurrentItem(*it); slotItemClicked(*it, 0); break; } ++it; } // // Add the group to the completion object // KCompletion *completion = m_group_combo->completionObject(); if (!m_group_combo->currentText().isEmpty()) { completion->addItem(m_group_combo->currentText()); } } void Smb4KBookmarkEditor::slotAddGroupTriggered(bool /*checked*/) { bool ok = false; QString group_name = QInputDialog::getText(this, i18n("Add Group"), i18n("Group name:"), QLineEdit::Normal, QString(), &ok); if (ok && !group_name.isEmpty() && m_tree_widget->findItems(group_name, Qt::MatchFixedString|Qt::MatchCaseSensitive, 0).isEmpty()) { // Create a new group item and add it to the widget QTreeWidgetItem *group = new QTreeWidgetItem(QTreeWidgetItem::UserType); group->setIcon(0, KDE::icon("folder-bookmark")); group->setText(0, group_name); group->setText((m_tree_widget->columnCount() - 1), QString("00_%1").arg(group_name)); group->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsDropEnabled) ; m_tree_widget->addTopLevelItem(group); m_tree_widget->sortItems((m_tree_widget->columnCount() - 1), Qt::AscendingOrder); // Add the group to the combo box m_group_combo->addItem(group_name); m_group_combo->completionObject()->addItem(group_name); } } void Smb4KBookmarkEditor::slotDeleteTriggered(bool /*checked*/) { // // Remove the bookmarks from the view and the internal list // QList selected = m_tree_widget->selectedItems(); while (!selected.isEmpty()) { QTreeWidgetItem *item = selected.takeFirst(); QUrl url = item->data(0, QTreeWidgetItem::UserType).toUrl(); QMutableListIterator it(m_bookmarks); while (it.hasNext()) { BookmarkPtr bookmark = it.next(); if (bookmark->url() == url) { it.remove(); break; } } delete item; } } void Smb4KBookmarkEditor::slotClearTriggered(bool /*checked*/) { m_tree_widget->clear(); m_bookmarks.clear(); m_groups.clear(); } void Smb4KBookmarkEditor::slotDialogAccepted() { // // Write the dialog properties to the config file // KConfigGroup group(Smb4KSettings::self()->config(), "BookmarkEditor"); KWindowConfig::saveWindowSize(windowHandle(), group); group.writeEntry("LabelCompletion", m_label_edit->completionObject()->items()); group.writeEntry("LoginCompletion", m_login_edit->completionObject()->items()); group.writeEntry("IPCompletion", m_ip_edit->completionObject()->items()); group.writeEntry("GroupCompletion", m_group_combo->completionObject()->items()); // // Accept the dialog // accept(); } void Smb4KBookmarkEditor::slotDialogRejected() { // // Reject the dialog // reject(); } void Smb4KBookmarkEditor::slotIconSizeChanged(int group) { switch (group) { case KIconLoader::Small: { int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small); m_tree_widget->setIconSize(QSize(icon_size, icon_size)); break; } default: { break; } } } void Smb4KBookmarkEditor::slotAdjust() { // Do the necessary adjustments: QTreeWidgetItemIterator it(m_tree_widget); while (*it) { if (!(*it)->parent()) { if ((*it)->data(0, QTreeWidgetItem::UserType).toUrl().isEmpty()) { if ((*it)->childCount() == 0) { delete *it; } } else { BookmarkPtr bookmark = findBookmark((*it)->data(0, QTreeWidgetItem::UserType).toUrl()); if (bookmark) { bookmark->setGroupName(""); } } } else { BookmarkPtr bookmark = findBookmark((*it)->data(0, QTreeWidgetItem::UserType).toUrl()); if (bookmark) { bookmark->setGroupName((*it)->parent()->text(0)); } } ++it; } } diff --git a/core/smb4kclient.cpp b/core/smb4kclient.cpp index 951c9a4..fd5db43 100644 --- a/core/smb4kclient.cpp +++ b/core/smb4kclient.cpp @@ -1,1035 +1,1035 @@ /*************************************************************************** This class provides the interface to the libsmbclient library. ------------------- begin : Sa Oct 20 2018 copyright : (C) 2018-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4kclient.h" #include "smb4kclient_p.h" #include "smb4khardwareinterface.h" #include "smb4ksettings.h" #include "smb4kcustomoptionsmanager.h" #include "smb4kcustomoptions.h" #include "smb4kbasicnetworkitem.h" #include "smb4kglobal.h" #include "smb4khomesshareshandler.h" #include "smb4kwalletmanager.h" #include "smb4knotification.h" // Qt includes #include #include #include #include using namespace Smb4KGlobal; Q_GLOBAL_STATIC(Smb4KClientStatic, p); Smb4KClient::Smb4KClient(QObject* parent) : KCompositeJob(parent), d(new Smb4KClientPrivate) { // // Connections // connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit())); } Smb4KClient::~Smb4KClient() { } Smb4KClient *Smb4KClient::self() { return &p->instance; } void Smb4KClient::start() { // // Check the network configurations // Smb4KHardwareInterface::self()->updateNetworkConfig(); // // Connect to Smb4KHardwareInterface to be able to get the response // connect(Smb4KHardwareInterface::self(), SIGNAL(networkConfigUpdated()), this, SLOT(slotStartJobs())); } bool Smb4KClient::isRunning() { return hasSubjobs(); } void Smb4KClient::abort() { QListIterator it(subjobs()); while (it.hasNext()) { it.next()->kill(KJob::EmitResult); } } void Smb4KClient::lookupDomains() { // // Send Wakeup-On-LAN packages // if (Smb4KSettings::enableWakeOnLAN()) { QList wakeOnLanEntries = Smb4KCustomOptionsManager::self()->wakeOnLanEntries(); if (!wakeOnLanEntries.isEmpty()) { NetworkItemPtr item = NetworkItemPtr(new Smb4KBasicNetworkItem()); emit aboutToStart(item, WakeUp); QUdpSocket *socket = new QUdpSocket(this); for (int i = 0; i < wakeOnLanEntries.size(); ++i) { if (wakeOnLanEntries.at(i)->wolSendBeforeNetworkScan()) { QHostAddress addr; if (wakeOnLanEntries.at(i)->hasIpAddress()) { addr.setAddress(wakeOnLanEntries.at(i)->ipAddress()); } else { addr.setAddress("255.255.255.255"); } // Construct magic sequence QByteArray sequence; // 6 times 0xFF for (int j = 0; j < 6; ++j) { sequence.append(QChar(0xFF).toLatin1()); } // 16 times the MAC address QStringList parts = wakeOnLanEntries.at(i)->macAddress().split(':', QString::SkipEmptyParts); for (int j = 0; j < 16; ++j) { for (int k = 0; k < parts.size(); ++k) { sequence.append(QChar(QString("0x%1").arg(parts.at(k)).toInt(0, 16)).toLatin1()); } } socket->writeDatagram(sequence, addr, 9); } } delete socket; // Wait the defined time int stop = 1000 * Smb4KSettings::wakeOnLANWaitingTime() / 250; int i = 0; while (i++ < stop) { QTest::qWait(250); } emit finished(item, WakeUp); item.clear(); } } // // Emit the aboutToStart() signal // NetworkItemPtr item = NetworkItemPtr(new Smb4KBasicNetworkItem(Network)); item->setUrl(QUrl("smb://")); emit aboutToStart(item, LookupDomains); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(item); job->setProcess(LookupDomains); // // Clear the pointer // item.clear(); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupDomainMembers(const WorkgroupPtr &workgroup) { // // Emit the aboutToStart() signal // emit aboutToStart(workgroup, LookupDomainMembers); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(workgroup); job->setProcess(LookupDomainMembers); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupShares(const HostPtr &host) { // // Emit the aboutToStart() signal // emit aboutToStart(host, LookupShares); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(host); job->setProcess(LookupShares); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupFiles(const NetworkItemPtr &item) { // // Check that the network item has the correct type and process it. // if (item->type() == Share || item->type() == Directory) { // // Emit the aboutToStart() signal // emit aboutToStart(item, LookupFiles); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(item); job->setProcess(LookupFiles); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } } void Smb4KClient::printFile(const SharePtr& share, const KFileItem& fileItem, int copies) { // // Emit the aboutToStart() signal // emit aboutToStart(share, PrintFile); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(share); job->setPrintFileItem(fileItem); job->setPrintCopies(copies); job->setProcess(PrintFile); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::search(const QString& item) { // // Create empty basic network item // NetworkItemPtr networkItem = NetworkItemPtr(new Smb4KBasicNetworkItem()); // // Emit the aboutToStart() signal // emit aboutToStart(networkItem, NetworkSearch); // // Before doing the search, lookup all domains, servers and shares in the // network neighborhood. // lookupDomains(); while(isRunning()) { QTest::qWait(50); } for (const WorkgroupPtr &workgroup : workgroupsList()) { lookupDomainMembers(workgroup); while(isRunning()) { QTest::qWait(50); } } for (const HostPtr &host : hostsList()) { lookupShares(host); while(isRunning()) { QTest::qWait(50); } } // // Do the actual search // QList results; for (const SharePtr &share : sharesList()) { if (share->shareName().contains(item, Qt::CaseInsensitive)) { results << share; } } // // Emit the search results // emit searchResults(results); // // Emit the finished() signal // emit finished(networkItem, NetworkSearch); } void Smb4KClient::openPreviewDialog(const SharePtr &share) { // // Printer share check // if (share->isPrinter()) { return; } // // 'homes' share check // if (share->isHomesShare()) { Smb4KHomesSharesHandler::self()->specifyUser(share, true); } // // Start the preview dialog // // First, check if a preview dialog has already been set up for this share // and reuse it, if possible. // QPointer dlg = 0; for (Smb4KPreviewDialog *p : d->previewDialogs) { if (share == p->share()) { dlg = p; } } // // If there was no preview dialog present, create a new one // if (!dlg) { dlg = new Smb4KPreviewDialog(share, QApplication::activeWindow()); d->previewDialogs << dlg; // // Connections // connect(dlg, SIGNAL(requestPreview(NetworkItemPtr)), this, SLOT(slotStartNetworkQuery(NetworkItemPtr))); - connect(dlg, SIGNAL(aboutToClose(Smb4KPreviewDialog *)), this, SLOT(slotPreviewDialogClosed(Smb4KPreviewDialog *))); + connect(dlg, SIGNAL(aboutToClose(Smb4KPreviewDialog*)), this, SLOT(slotPreviewDialogClosed(Smb4KPreviewDialog*))); connect(dlg, SIGNAL(requestAbort()), this, SLOT(slotAbort())); connect(this, SIGNAL(files(QList)), dlg, SLOT(slotPreviewResults(QList))); connect(this, SIGNAL(aboutToStart(NetworkItemPtr,int)), dlg, SLOT(slotAboutToStart(NetworkItemPtr,int))); connect(this, SIGNAL(finished(NetworkItemPtr,int)), dlg, SLOT(slotFinished(NetworkItemPtr,int))); } // // Show the preview dialog // if (!dlg->isVisible()) { dlg->setVisible(true); } } void Smb4KClient::openPrintDialog(const SharePtr& share) { // // Printer share check // if (!share->isPrinter()) { return; } // // Start the print dialog // // First, check if a print dialog has already been set up for this share // and reuse it, if possible. // QPointer dlg = 0; for (Smb4KPrintDialog *p : d->printDialogs) { if (share == p->share()) { dlg = p; } } // // If there was no print dialog present, create a new one // if (!dlg) { Smb4KWalletManager::self()->readAuthInfo(share); dlg = new Smb4KPrintDialog(share, QApplication::activeWindow()); d->printDialogs << dlg; - connect(dlg, SIGNAL(printFile(SharePtr, KFileItem, int)), this, SLOT(slotStartPrinting(SharePtr, KFileItem, int))); - connect(dlg, SIGNAL(aboutToClose(Smb4KPrintDialog *)), this, SLOT(slotPrintDialogClosed(Smb4KPrintDialog *))); + connect(dlg, SIGNAL(printFile(SharePtr,KFileItem,int)), this, SLOT(slotStartPrinting(SharePtr,KFileItem,int))); + connect(dlg, SIGNAL(aboutToClose(Smb4KPrintDialog*)), this, SLOT(slotPrintDialogClosed(Smb4KPrintDialog*))); } // // Show the preview dialog // if (!dlg->isVisible()) { dlg->setVisible(true); } } void Smb4KClient::processErrors(Smb4KClientJob *job) { switch (job->error()) { case Smb4KClientJob::AccessDeniedError: { switch (job->networkItem()->type()) { case Host: { if (Smb4KWalletManager::self()->showPasswordDialog(job->networkItem())) { lookupShares(job->networkItem().staticCast()); } break; } case Share: { if (Smb4KWalletManager::self()->showPasswordDialog(job->networkItem())) { if (job->process() == Smb4KGlobal::PrintFile) { printFile(job->networkItem().staticCast(), job->printFileItem(), job->printCopies()); } else { lookupFiles(job->networkItem().staticCast()); } } break; } case Directory: case File: { FilePtr file = job->networkItem().staticCast(); SharePtr share = SharePtr(new Smb4KShare()); share->setWorkgroupName(file->workgroupName()); share->setHostName(file->hostName()); share->setShareName(file->shareName()); share->setLogin(file->login()); share->setPassword(file->password()); if (Smb4KWalletManager::self()->showPasswordDialog(share)) { file->setLogin(share->login()); file->setPassword(share->password()); lookupFiles(file); } break; } default: { qDebug() << "Authentication error. URL:" << job->networkItem()->url(); break; } } break; } default: { Smb4KNotification::networkCommunicationFailed(job->errorText()); break; } } } void Smb4KClient::processWorkgroups(Smb4KClientJob *job) { // // Remove obsolete workgroups and their members // QListIterator wIt(workgroupsList()); while (wIt.hasNext()) { WorkgroupPtr workgroup = wIt.next(); bool found = false; for (const WorkgroupPtr &w : job->workgroups()) { if (w->workgroupName() == workgroup->workgroupName()) { found = true; break; } else { continue; } } if (!found) { QList obsoleteHosts = workgroupMembers(workgroup); QListIterator hIt(obsoleteHosts); while (hIt.hasNext()) { removeHost(hIt.next()); } removeWorkgroup(workgroup); } } // // Add new workgroups and update existing ones. // for (const WorkgroupPtr &workgroup : job->workgroups()) { if (!findWorkgroup(workgroup->workgroupName())) { addWorkgroup(workgroup); // Since this is a new workgroup, no master browser is present. HostPtr masterBrowser = HostPtr(new Smb4KHost()); masterBrowser->setWorkgroupName(workgroup->workgroupName()); masterBrowser->setHostName(workgroup->masterBrowserName()); masterBrowser->setIpAddress(workgroup->masterBrowserIpAddress()); masterBrowser->setIsMasterBrowser(true); addHost(masterBrowser); } else { updateWorkgroup(workgroup); // Check if the master browser changed QList members = workgroupMembers(workgroup); for (const HostPtr &host : members) { if (workgroup->masterBrowserName() == host->hostName()) { host->setIsMasterBrowser(true); if (!host->hasIpAddress() && workgroup->hasMasterBrowserIpAddress()) { host->setIpAddress(workgroup->masterBrowserIpAddress()); } } else { host->setIsMasterBrowser(false); } } } } emit workgroups(); } void Smb4KClient::processHosts(Smb4KClientJob *job) { // // Get the workgroup pointer // WorkgroupPtr workgroup = job->networkItem().staticCast(); // // Remove obsolete workgroup members // QList members = workgroupMembers(workgroup); QListIterator hIt(members); while (hIt.hasNext()) { HostPtr host = hIt.next(); bool found = false; for (const HostPtr &h : job->hosts()) { if (h->workgroupName() == host->workgroupName() && h->hostName() == host->hostName()) { found = true; break; } else { continue; } } if (!found) { QList obsoleteShares = sharedResources(host); QListIterator sIt(obsoleteShares); while (sIt.hasNext()) { removeShare(sIt.next()); } removeHost(host); } } // // Add new hosts and update existing ones // for (const HostPtr &host : job->hosts()) { if (host->hostName() == workgroup->masterBrowserName()) { host->setIsMasterBrowser(true); } else { host->setIsMasterBrowser(false); } if (!findHost(host->hostName(), host->workgroupName())) { addHost(host); } else { updateHost(host); } } emit hosts(workgroup); } void Smb4KClient::processShares(Smb4KClientJob *job) { // // Get the host pointer // HostPtr host = job->networkItem().staticCast(); // // Remove obsolete shares // QList sharedRes = sharedResources(host); QListIterator sIt(sharedRes); while (sIt.hasNext()) { SharePtr share = sIt.next(); bool found = false; for (const SharePtr &s : job->shares()) { if (s->workgroupName() == share->workgroupName() && s->url().matches(share->url(), QUrl::RemoveUserInfo|QUrl::RemovePort)) { found = true; break; } else { continue; } } if (!found || (share->isHidden() && !Smb4KSettings::detectHiddenShares()) || (share->isPrinter() && !Smb4KSettings::detectPrinterShares())) { removeShare(share); } } // // Add new shares and update existing ones // for (const SharePtr &share : job->shares()) { // // Process only those shares that the user wants to see // if (share->isHidden() && !Smb4KSettings::detectHiddenShares()) { continue; } if (share->isPrinter() && !Smb4KSettings::detectPrinterShares()) { continue; } // // Add or update the shares // if (!findShare(share->url(), share->workgroupName())) { addShare(share); } else { updateShare(share); } } emit shares(host); } void Smb4KClient::processFiles(Smb4KClientJob *job) { QList list; for (const FilePtr &f : job->files()) { if (f->isHidden() && !Smb4KSettings::previewHiddenItems()) { continue; } list << f; } emit files(list); } void Smb4KClient::slotStartJobs() { if (Smb4KHardwareInterface::self()->isOnline()) { // // Disconnect from Smb4KHardwareInterface::networkConfigUpdated() signal, // otherwise we get unwanted periodic scanning. // disconnect(Smb4KHardwareInterface::self(), SIGNAL(networkConfigUpdated()), this, SLOT(slotStartJobs())); // // Lookup domains as the first step // lookupDomains(); } } void Smb4KClient::slotResult(KJob *job) { // // Get the client job // Smb4KClientJob *clientJob = qobject_cast(job); // // Define a network item pointer and the process value for the // finished() signal. // NetworkItemPtr item = clientJob->networkItem(); Smb4KGlobal::Process process = clientJob->process(); // // Get the result from the query and process it // if (clientJob) { if (clientJob->error() == 0) { switch (clientJob->networkItem()->type()) { case Network: { // Process the discovered workgroups processWorkgroups(clientJob); break; } case Workgroup: { // Process the discovered workgroup members processHosts(clientJob); break; } case Host: { // Process the discovered shares processShares(clientJob); break; } case Share: case Directory: { // Process the discoveres files and directories processFiles(clientJob); break; } default: { break; } } } else { processErrors(clientJob); } } // // Remove the job // removeSubjob(job); // // Emit the finished signal // finished(item, process); // // Clear the network item pointer // item.clear(); // // Restore the cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::restoreOverrideCursor(); } } void Smb4KClient::slotAboutToQuit() { abort(); } void Smb4KClient::slotStartNetworkQuery(NetworkItemPtr item) { // // Look up files // lookupFiles(item); } void Smb4KClient::slotPreviewDialogClosed(Smb4KPreviewDialog *dialog) { // // Remove the preview dialog from the list // if (dialog) { // Find the dialog in the list and take it from the list. // It will automatically be deleted on close, so there is // no need to delete the dialog here. int i = d->previewDialogs.indexOf(dialog); d->previewDialogs.takeAt(i); } } void Smb4KClient::slotAbort() { abort(); } void Smb4KClient::slotStartPrinting(const SharePtr& printer, const KFileItem& fileItem, int copies) { // // Start printing // printFile(printer, fileItem, copies); } void Smb4KClient::slotPrintDialogClosed(Smb4KPrintDialog* dialog) { // // Remove the print dialog from the list // if (dialog) { // Find the dialog in the list and take it from the list. // It will automatically be deleted on close, so there is // no need to delete the dialog here. int i = d->printDialogs.indexOf(dialog); d->printDialogs.takeAt(i); } } diff --git a/core/smb4kclient_p.cpp b/core/smb4kclient_p.cpp index b6c0d29..93105fb 100644 --- a/core/smb4kclient_p.cpp +++ b/core/smb4kclient_p.cpp @@ -1,2042 +1,2042 @@ /*************************************************************************** Private classes for the SMB client ------------------- begin : So Oct 21 2018 copyright : (C) 2018-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4kclient_p.h" #include "smb4ksettings.h" #include "smb4kwalletmanager.h" #include "smb4kcustomoptions.h" #include "smb4kcustomoptionsmanager.h" #include "smb4knotification.h" // System includes #include // #include #include // #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #define SMBC_DEBUG 0 using namespace Smb4KGlobal; // // Authentication function for libsmbclient // static void get_auth_data_with_context_fn(SMBCCTX *context, const char *server, const char *share, char *workgroup, int maxLenWorkgroup, char *username, int maxLenUsername, char *password, int maxLenPassword) { if (context != nullptr) { Smb4KClientJob *job = static_cast(smbc_getOptionUserData(context)); if (job) { job->get_auth_data_fn(server, share, workgroup, maxLenWorkgroup, username, maxLenUsername, password, maxLenPassword); } } } // // Client job // Smb4KClientJob::Smb4KClientJob(QObject* parent) : KJob(parent), m_process(Smb4KGlobal::NoProcess) { } Smb4KClientJob::~Smb4KClientJob() { // // Clear the list of workgroups // while (!m_workgroups.isEmpty()) { m_workgroups.takeFirst().clear(); } // // Clear the list of hosts // while (!m_hosts.isEmpty()) { m_hosts.takeFirst().clear(); } // // Clear the list of shares // while (!m_shares.isEmpty()) { m_shares.takeFirst().clear(); } // // Clear the list of files and directories // while (!m_files.isEmpty()) { m_files.takeFirst().clear(); } } void Smb4KClientJob::start() { QTimer::singleShot(50, this, SLOT(slotStartJob())); } void Smb4KClientJob::setNetworkItem(NetworkItemPtr item) { m_item = item; } NetworkItemPtr Smb4KClientJob::networkItem() const { return m_item; } void Smb4KClientJob::setProcess(Smb4KGlobal::Process process) { m_process = process; } Smb4KGlobal::Process Smb4KClientJob::process() const { return m_process; } void Smb4KClientJob::setPrintFileItem(const KFileItem& item) { m_fileItem = item; } KFileItem Smb4KClientJob::printFileItem() const { return m_fileItem; } void Smb4KClientJob::setPrintCopies(int copies) { m_copies = copies; } int Smb4KClientJob::printCopies() const { return m_copies; } void Smb4KClientJob::get_auth_data_fn(const char* server, const char* /*share*/, char* workgroup, int /*maxLenWorkgroup*/, char* username, int maxLenUsername, char* password, int maxLenPassword) { // // Authentication // switch (m_item->type()) { case Network: { // // No authentication needed // break; } case Workgroup: { // // Only request authentication data, if the master browsers require // authentication data. // if (Smb4KSettings::masterBrowsersRequireAuth()) { if (QString::fromUtf8(server).toUpper() != QString::fromUtf8(workgroup).toUpper()) { // // This is the master browser. Create a host object for it. // HostPtr h = HostPtr(new Smb4KHost()); h->setWorkgroupName(QString::fromUtf8(workgroup)); h->setHostName(QString::fromUtf8(server)); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(h); // // Copy the authentication data // qstrncpy(username, h->login().toUtf8().data(), maxLenUsername); qstrncpy(password, h->password().toUtf8().data(), maxLenPassword); } } break; } case Host: { // // The host object // HostPtr h = m_item.staticCast(); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(h); // // Copy the authentication data // qstrncpy(username, h->login().toUtf8().data(), maxLenUsername); qstrncpy(password, h->password().toUtf8().data(), maxLenPassword); break; } case Share: { // // The share object // SharePtr s = m_item.staticCast(); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(s); // // Copy the authentication data // qstrncpy(username, s->login().toUtf8().data(), maxLenUsername); qstrncpy(password, s->password().toUtf8().data(), maxLenPassword); break; } case Directory: { // // The file object // FilePtr f = m_item.staticCast(); // // Create a share object // SharePtr s = SharePtr(new Smb4KShare()); s->setWorkgroupName(f->workgroupName()); s->setHostName(f->hostName()); s->setShareName(f->shareName()); s->setLogin(f->login()); s->setPassword(f->password()); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(s); // // Copy the authentication data // qstrncpy(username, s->login().toUtf8().data(), maxLenUsername); qstrncpy(password, s->password().toUtf8().data(), maxLenPassword); break; } default: { break; } } } QList Smb4KClientJob::workgroups() { return m_workgroups; } QList Smb4KClientJob::hosts() { return m_hosts; } QList Smb4KClientJob::shares() { return m_shares; } QList Smb4KClientJob::files() { return m_files; } QString Smb4KClientJob::workgroup() { QString workgroup; switch (m_item->type()) { case Network: { break; } case Workgroup: { workgroup = m_item->url().host().toUpper(); break; } case Host: { workgroup = m_item.staticCast()->workgroupName(); break; } case Share: { workgroup = m_item.staticCast()->workgroupName(); break; } case Directory: case File: { workgroup = m_item.staticCast()->workgroupName(); break; } default: { break; } } return workgroup; } void Smb4KClientJob::doLookups() { // // Read the given URL // int dirfd; struct smbc_dirent *dirp = nullptr; dirfd = smbc_opendir(m_item->url().toString().toUtf8().data()); if (dirfd < 0) { int errorCode = errno; switch (errorCode) { case ENOMEM: { setError(OutOfMemoryError); setErrorText(i18n("Out of memory")); break; } case EACCES: { setError(AccessDeniedError); setErrorText(i18n("Permission denied")); break; } case EINVAL: { setError(InvalidUrlError); setErrorText(i18n("An invalid URL was passed")); break; } case ENOENT: { setError(NonExistentUrlError); setErrorText(i18n("The URL does not exist")); break; } case ENOTDIR: { setError(NoDirectoryError); setErrorText(i18n("Name is not a directory")); break; } case EPERM: { setError(NotPermittedError); // Is the error message correct? setErrorText(i18n("Operation not permitted")); break; } case ENODEV: { setError(NotFoundError); setErrorText(i18n("The workgroup or server could not be found")); break; } default: { setError(UnknownError); setErrorText(i18n("Unknown error")); } } emitResult(); return; } else { // // Get the entries of the "directory" // while ((dirp = smbc_readdir(dirfd)) != nullptr) { switch (dirp->smbc_type) { case SMBC_WORKGROUP: { // // Create a workgroup pointer // WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); // // Set the workgroup name // QString workgroupName = QString::fromUtf8(dirp->name); workgroup->setWorkgroupName(workgroupName); // // Set the master browser // QString masterBrowserName = QString::fromUtf8(dirp->comment); workgroup->setMasterBrowserName(masterBrowserName); // // Lookup IP address // QHostAddress address = lookupIpAddress(masterBrowserName); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip the // workgroup and delete the pointer. // if (!address.isNull()) { workgroup->setMasterBrowserIpAddress(address); m_workgroups << workgroup; } else { workgroup.clear(); } break; } case SMBC_SERVER: { // // Create a host pointer // HostPtr host = HostPtr(new Smb4KHost()); // // Set the workgroup name // host->setWorkgroupName(m_item->url().host()); // // Set the host name // QString hostName = QString::fromUtf8(dirp->name); host->setHostName(hostName); // // Set the comment // QString comment = QString::fromUtf8(dirp->comment); host->setComment(comment); // // Lookup IP address // QHostAddress address = lookupIpAddress(hostName); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { host->setIpAddress(address); m_hosts << host; } else { host.clear(); } break; } case SMBC_FILE_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(dirp->name)); // // Set the comment // share->setComment(QString::fromUtf8(dirp->comment)); // // Set share type // share->setShareType(FileShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_PRINTER_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(dirp->name)); // // Set the comment // share->setComment(QString::fromUtf8(dirp->comment)); // // Set share type // share->setShareType(PrinterShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_IPC_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(dirp->name)); // // Set the comment // share->setComment(QString::fromUtf8(dirp->comment)); // // Set share type // share->setShareType(IpcShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_DIR: { // // Do not process '.' and '..' directories // QString name = QString::fromUtf8(dirp->name); if (name != "." && name != "..") { // // Create the URL for the discovered item // QUrl u = m_item->url(); u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(dirp->name)); // // We do not stat directories. Directly create the directory object // FilePtr dir = FilePtr(new Smb4KFile(u, Directory)); // // Set the workgroup name // dir->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the authentication data // dir->setLogin(m_item->url().userName()); dir->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { dir->setHostIpAddress(address); m_files << dir; } else { dir.clear(); } } break; } case SMBC_FILE: { // // Create the URL for the discovered item // QUrl u = m_item->url(); u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(dirp->name)); // // Create the directory object // FilePtr dir = FilePtr(new Smb4KFile(u, File)); // // Set the workgroup name // dir->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Stat the file // // FIXME // // Set the authentication data // dir->setLogin(m_item->url().userName()); dir->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { dir->setHostIpAddress(address); m_files << dir; } else { dir.clear(); } break; } case SMBC_LINK: { qDebug() << "Processing links is not implemented."; qDebug() << dirp->name; qDebug() << dirp->comment; break; } default: { qDebug() << "Need to process network item " << dirp->name; break; } } } smbc_closedir(dirfd); } } void Smb4KClientJob::doPrinting() { // // The URL that is to be printed // QUrl fileUrl; // // Set the temporary directory // QTemporaryDir tempDir; // // Check if we can directly print the file // if (m_fileItem.mimetype() == "application/postscript" || m_fileItem.mimetype() == "application/pdf" || m_fileItem.mimetype().startsWith(QLatin1String("image"))) { // // Set the URL to the incoming file // fileUrl = m_fileItem.url(); } else if (m_fileItem.mimetype() == "application/x-shellscript" || m_fileItem.mimetype().startsWith(QLatin1String("text")) || m_fileItem.mimetype().startsWith(QLatin1String("message"))) { // // Set a printer object // QPrinter printer(QPrinter::HighResolution); printer.setCreator("Smb4K"); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(QString("%1/smb4k_print.pdf").arg(tempDir.path())); // // Open the file that is to be printed and read it // QStringList contents; QFile file(m_fileItem.url().path()); if (file.open(QFile::ReadOnly|QFile::Text)) { QTextStream ts(&file); while (!ts.atEnd()) { contents << ts.readLine(); } } else { return; } // // Convert the file to PDF // QTextDocument doc; if (m_fileItem.mimetype().endsWith(QLatin1String("html"))) { doc.setHtml(contents.join(" ")); } else { doc.setPlainText(contents.join("\n")); } doc.print(&printer); // // Set the URL to the converted file // fileUrl.setUrl(printer.outputFileName()); fileUrl.setScheme("file"); } else { Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype()); return; } // // Get the open function for the printer // smbc_open_print_job_fn openPrinter = smbc_getFunctionOpenPrintJob(m_context); if (!openPrinter) { setError(OpenPrintJobError); setErrorText(i18n("The print job could not be set up (step 1)")); emitResult(); return; } // // Open the printer for printing // SMBCFILE *printer = openPrinter(m_context, m_item->url().toString().toUtf8().data()); if (!printer) { int errorCode = errno; if (errorCode == EACCES) { setError(AccessDeniedError); setErrorText(i18n("Permission denied")); } else { setError(OpenPrintJobError); setErrorText(i18n("The print job could not be set up (step 2)")); } emitResult(); return; } // // Open the file // QFile file(fileUrl.path()); if (!file.open(QFile::ReadOnly)) { setError(FileAccessError); setErrorText(i18n("The file %1 could not be read", fileUrl.path())); emitResult(); return; } // // Write X copies of the file to the printer // char buffer[4096]; qint64 bytes = 0; int copy = 0; while (copy < m_copies) { while ((bytes = file.read(buffer, sizeof(buffer))) > 0) { smbc_write_fn writeFile = smbc_getFunctionWrite(m_context); if (writeFile(m_context, printer, buffer, bytes) < 0) { setError(PrintFileError); setErrorText(i18n("The file %1 could not be printed to %2", fileUrl.path(), m_item.staticCast()->displayString())); smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); closePrinter(m_context, printer); } } copy++; } // // Close the printer // smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); closePrinter(m_context, printer); } QHostAddress Smb4KClientJob::lookupIpAddress(const QString& name) { // // The IP address object // QHostAddress ipAddress; // If the IP address is not to be determined for the local machine, we can use QHostInfo to // determine it. Otherwise we need to use QNetworkInterface for it. if (name.toUpper() == QHostInfo::localHostName().toUpper() || name.toUpper() == globalSambaOptions()["netbios name"].toUpper() || name.toUpper() == Smb4KSettings::netBIOSName().toUpper()) { // FIXME: Do we need to honor 'interfaces' here? QList addresses = QNetworkInterface::allAddresses(); // Get the IP address for the host. For the time being, prefer the // IPv4 address over the IPv6 address. for (const QHostAddress &addr : addresses) { // We only use global addresses. #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) if (addr.isGlobal()) #else if (!addr.isLoopback() && !addr.isMulticast()) #endif { if (addr.protocol() == QAbstractSocket::IPv4Protocol) { ipAddress = addr; break; } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { // FIXME: Use the right address here. ipAddress = addr; } } } } else { // Get the IP address QHostInfo hostInfo = QHostInfo::fromName(name); if (hostInfo.error() == QHostInfo::NoError) { // Get the IP address for the host. For the time being, prefer the // IPv4 address over the IPv6 address. for (const QHostAddress &addr : hostInfo.addresses()) { // We only use global addresses. #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) if (addr.isGlobal()) #else if (!addr.isLoopback() && !addr.isMulticast()) #endif { if (addr.protocol() == QAbstractSocket::IPv4Protocol) { ipAddress = addr; break; } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { // FIXME: Use the right address here. ipAddress = addr; } } } } } return ipAddress; } void Smb4KClientJob::slotStartJob() { // // Allocate new context // m_context = smbc_new_context(); if (!m_context) { int errorCode = errno; switch (errorCode) { case ENOMEM: { setError(OutOfMemoryError); setErrorText(i18n("Out of memory")); break; } default: { setError(UnknownError); setErrorText(i18n("Unknown error")); break; } } emitResult(); return; } // // Get the custom options // OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(m_item); // // Set debug level // smbc_setDebug(m_context, SMBC_DEBUG); // // Set the NetBIOS name and the workgroup to make connections // switch (m_item->type()) { case Network: { // // We do not know about the servers and the domains/workgroups // present. So, do not set anything and use the default. // break; } case Workgroup: { // // Set the NetBIOS name of the master browser and the workgroup to be queried // WorkgroupPtr workgroup = m_item.staticCast(); smbc_setNetbiosName(m_context, workgroup->masterBrowserName().toUtf8().data()); smbc_setWorkgroup(m_context, workgroup->workgroupName().toUtf8().data()); break; } case Host: { // // Set both the NetBIOS name of the server and the workgroup to be queried // HostPtr host = m_item.staticCast(); smbc_setNetbiosName(m_context, host->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, host->workgroupName().toUtf8().data()); break; } case Share: { // // Set both the NetBIOS name of the server and the workgroup to be queried // SharePtr share = m_item.staticCast(); smbc_setNetbiosName(m_context, share->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data()); break; } case Directory: { // // Set both the NetBIOS name of the server and the workgroup to be queried // FilePtr file = m_item.staticCast(); smbc_setNetbiosName(m_context, file->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, file->workgroupName().toUtf8().data()); break; } default: { break; } } // // Set the user for making the connection // if (!m_item->url().userName().isEmpty()) { smbc_setUser(m_context, m_item->url().userName().toUtf8().data()); } // // Set the port // if (options) { if (options->useSmbPort()) { smbc_setPort(m_context, options->smbPort()); } else { smbc_setPort(m_context, 0 /* use the default */); } } else { if (Smb4KSettings::useRemoteSmbPort()) { smbc_setPort(m_context, Smb4KSettings::remoteSmbPort()); } else { smbc_setPort(m_context, 0 /* use the default */); } } // // Set the user data (this class) // smbc_setOptionUserData(m_context, this); // // Set number of master browsers to be used // if (Smb4KSettings::largeNetworkNeighborhood()) { smbc_setOptionBrowseMaxLmbCount(m_context, 3); } else { smbc_setOptionBrowseMaxLmbCount(m_context, 0 /* all master browsers */); } // // Set the encryption level // if (Smb4KSettings::useEncryptionLevel()) { switch (Smb4KSettings::encryptionLevel()) { case Smb4KSettings::EnumEncryptionLevel::None: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_NONE); break; } case Smb4KSettings::EnumEncryptionLevel::Request: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUEST); break; } case Smb4KSettings::EnumEncryptionLevel::Require: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUIRE); break; } default: { break; } } } // // Set the usage of anonymous login // smbc_setOptionNoAutoAnonymousLogin(m_context, false); // // Set the usage of the winbind ccache // smbc_setOptionUseCCache(m_context, Smb4KSettings::useWinbindCCache()); // // Set usage of Kerberos // if (options) { smbc_setOptionUseKerberos(m_context, options->useKerberos()); } else { smbc_setOptionUseKerberos(m_context, Smb4KSettings::useKerberos()); } smbc_setOptionFallbackAfterKerberos(m_context, 1); // // Set the channel for debug output // smbc_setOptionDebugToStderr(m_context, 1); // // Set auth callback function // smbc_setFunctionAuthDataWithContext(m_context, get_auth_data_with_context_fn); // // Initialize context with the previously defined options // if (!smbc_init_context(m_context)) { int errorCode = errno; switch (errorCode) { case ENOMEM: { setError(OutOfMemoryError); setErrorText(i18n("Out of memory")); break; } case EBADF: { setError(NullContextError); setErrorText(i18n("NULL context given")); break; } case ENOENT: { setError(SmbConfError); setErrorText(i18n("The smb.conf file would not load")); break; } default: { setError(UnknownError); setErrorText(i18n("Unknown error")); } } smbc_free_context(m_context, 0); emitResult(); return; } // // Set the new context // (void)smbc_set_context(m_context); // // Process the given URL according to the passed process // switch (m_process) { case LookupDomains: case LookupDomainMembers: case LookupShares: case LookupFiles: { doLookups(); break; } case PrintFile: { doPrinting(); break; } default: { break; } } // // Free the context // smbc_free_context(m_context, 0); // // Emit the result // emitResult(); } Smb4KPreviewDialog::Smb4KPreviewDialog(const SharePtr& share, QWidget* parent) : QDialog(parent), m_share(share) { // // Dialog title // setWindowTitle(i18n("Preview of %1", share->displayString())); // // Attributes // setAttribute(Qt::WA_DeleteOnClose, true); // // Layout // QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); // // The list widget // QListWidget *listWidget = new QListWidget(this); listWidget->setSelectionMode(QAbstractItemView::SingleSelection); - connect(listWidget, SIGNAL(itemActivated(QListWidgetItem *)), SLOT(slotItemActivated(QListWidgetItem *))); + connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemActivated(QListWidgetItem*))); layout->addWidget(listWidget, 0); // // Toolbar // Use QToolBar here with the settings suggested by the note provided in the 'Detailed Description' // section of KToolBar (https://api.kde.org/frameworks/kxmlgui/html/classKToolBar.html) // QToolBar *toolBar = new QToolBar(this); toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle); toolBar->setProperty("otherToolbar", true); // // Reload / cancel action // KDualAction *reloadAction = new KDualAction(toolBar); reloadAction->setObjectName("reload_action"); reloadAction->setInactiveText(i18n("Reload")); reloadAction->setInactiveIcon(KDE::icon("view-refresh")); reloadAction->setActiveText(i18n("Abort")); reloadAction->setActiveIcon(KDE::icon("process-stop")); reloadAction->setActive(false); reloadAction->setAutoToggle(false); connect(reloadAction, SIGNAL(toggled(bool)), this, SLOT(slotReloadActionTriggered())); toolBar->addAction(reloadAction); // // Up action // QAction *upAction =toolBar->addAction(KDE::icon("go-up"), i18n("Up"), this, SLOT(slotUpActionTriggered())); upAction->setObjectName("up_action"); upAction->setEnabled(false); toolBar->addSeparator(); // // URL combo box // KUrlComboBox *urlCombo = new KUrlComboBox(KUrlComboBox::Directories, toolBar); urlCombo->setEditable(false); toolBar->addWidget(urlCombo); connect(urlCombo, SIGNAL(urlActivated(QUrl)), this, SLOT(slotUrlActivated(QUrl))); layout->addWidget(toolBar, 0); // // Dialog button box // QDialogButtonBox *buttonBox = new QDialogButtonBox(this); buttonBox->setOrientation(Qt::Horizontal); QPushButton *closeButton = buttonBox->addButton(QDialogButtonBox::Close); connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClosingDialog())); layout->addWidget(buttonBox, 0); // // Set the minimum width // setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); // // Set the dialog size // create(); KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog"); KWindowConfig::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); // workaround for QTBUG-40584 // // Start the preview // m_currentItem = m_share; QTimer::singleShot(0, this, SLOT(slotInitializePreview())); } Smb4KPreviewDialog::~Smb4KPreviewDialog() { // // Clear the share // m_share.clear(); // // Clear the current item // m_currentItem.clear(); // // Clear the listing // while (!m_listing.isEmpty()) { m_listing.takeFirst().clear(); } } SharePtr Smb4KPreviewDialog::share() const { return m_share; } void Smb4KPreviewDialog::slotClosingDialog() { // // Save the dialog size // KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Close the dialog // accept(); } void Smb4KPreviewDialog::slotReloadActionTriggered() { KDualAction *reloadAction = findChild(); if (reloadAction->isActive()) { emit requestAbort(); } else { emit requestPreview(m_currentItem); } } void Smb4KPreviewDialog::slotUpActionTriggered() { // // Get the new URL // QUrl u = KIO::upUrl(m_currentItem->url()); // // Create a new network item object, if necessary and set the new current // item. Also, disable the "Up" action, if necessary. // if (m_share->url().matches(u, QUrl::StripTrailingSlash)) { findChild("up_action")->setEnabled(false); m_currentItem = m_share; } else if (m_share->url().path().length() < u.path().length()) { FilePtr file = FilePtr(new Smb4KFile(u, Directory)); file->setWorkgroupName(m_share->workgroupName()); m_currentItem = file; } else { return; } // // Emit the requestPreview() signal // emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotUrlActivated(const QUrl &url) { // // Get the full authentication information. This is needed, since the combo // box only returns sanitized URLs, i.e. without password, etc. // QUrl u = url; u.setUserName(m_share->login()); u.setPassword(m_share->password()); // // Create a new network item object, if necessary and set the new current // item. // if (m_share->url().matches(u, QUrl::StripTrailingSlash)) { m_currentItem = m_share; } else { FilePtr file = FilePtr(new Smb4KFile(u, Directory)); file->setWorkgroupName(m_share->workgroupName()); m_currentItem = file; } // // Emit the requestPreview() signal // emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotItemActivated(QListWidgetItem *item) { // // Only process the item if it represents a directory // if (item && item->type() == Directory) { // // Find the file item, make it the current one and emit the requestPreview() // signal. // for (const FilePtr &f : m_listing) { if (item->data(Qt::UserRole).toUrl().matches(f->url(), QUrl::None)) { m_currentItem = f; emit requestPreview(m_currentItem); break; } } } } void Smb4KPreviewDialog::slotInitializePreview() { emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotPreviewResults(const QList &list) { // // Only process data the belongs to this dialog // if (m_share->workgroupName() == list.first()->workgroupName() && m_share->hostName() == list.first()->hostName() && list.first()->url().path().startsWith(m_share->url().path())) { // // Clear the internal listing // while (!m_listing.isEmpty()) { m_listing.takeFirst().clear(); } // // Copy the list into the private variable // m_listing = list; // // Get the list widget // QListWidget *listWidget = findChild(); // // Clear the list widget // listWidget->clear(); // // Insert the new listing // if (listWidget) { for (const FilePtr &f : list) { QListWidgetItem *item = new QListWidgetItem(f->icon(), f->name(), listWidget, f->isDirectory() ? Directory : File); item->setData(Qt::UserRole, f->url()); } } // // Sort the list widget // listWidget->sortItems(); // // Add the URL to the combo box and show it. Omit duplicates. // KUrlComboBox *urlCombo = findChild(); QStringList urls = urlCombo->urls(); urls << m_currentItem->url().toString(); urlCombo->setUrls(urls); urlCombo->setUrl(m_currentItem->url()); // // Enable / disable the "Up" action // findChild("up_action")->setEnabled(!m_share->url().matches(m_currentItem->url(), QUrl::StripTrailingSlash)); } } void Smb4KPreviewDialog::slotAboutToStart(const NetworkItemPtr &item, int type) { if (type == LookupFiles) { switch (item->type()) { case Share: { SharePtr s = item.staticCast(); if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(true); } break; } case Directory: { FilePtr f = item.staticCast(); if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(true); } break; } default: { break; } } } } void Smb4KPreviewDialog::slotFinished(const NetworkItemPtr &item, int type) { if (type == LookupFiles) { switch (item->type()) { case Share: { SharePtr s = item.staticCast(); if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(false); } break; } case Directory: { FilePtr f = item.staticCast(); if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(false); } break; } default: { break; } } } } Smb4KPrintDialog::Smb4KPrintDialog(const SharePtr& share, QWidget* parent) : QDialog(parent), m_share(share) { // // Dialog title // setWindowTitle(i18n("Print File")); // // Attributes // setAttribute(Qt::WA_DeleteOnClose, true); // // Layout // QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); // // Information group box // QGroupBox *informationBox = new QGroupBox(i18n("Information"), this); QGridLayout *informationBoxLayout = new QGridLayout(informationBox); // Printer name QLabel *printerNameLabel = new QLabel(i18n("Printer:"), informationBox); QLabel *printerName = new QLabel(share->displayString(), informationBox); informationBoxLayout->addWidget(printerNameLabel, 0, 0, 0); informationBoxLayout->addWidget(printerName, 0, 1, 0); // IP address QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), informationBox); QLabel *ipAddress = new QLabel(share->hostIpAddress(), informationBox); informationBoxLayout->addWidget(ipAddressLabel, 1, 0, 0); informationBoxLayout->addWidget(ipAddress, 1, 1, 0); // Workgroup QLabel *workgroupNameLabel = new QLabel(i18n("Domain:"), informationBox); QLabel *workgroupName = new QLabel(share->workgroupName(), informationBox); informationBoxLayout->addWidget(workgroupNameLabel, 2, 0, 0); informationBoxLayout->addWidget(workgroupName, 2, 1, 0); layout->addWidget(informationBox); // // File and settings group box // QGroupBox *fileBox = new QGroupBox(i18n("File and Settings"), this); QGridLayout *fileBoxLayout = new QGridLayout(fileBox); // File QLabel *fileLabel = new QLabel(i18n("File:"), fileBox); KUrlRequester *file = new KUrlRequester(fileBox); file->setMode(KFile::File|KFile::LocalOnly|KFile::ExistingOnly); file->setUrl(QUrl::fromLocalFile(QDir::homePath())); file->setWhatsThis(i18n("This is the file you want to print on the remote printer. " "Currently only a few mimetypes are supported such as PDF, Postscript, plain text, and " "images. If the file's mimetype is not supported, you need to convert it.")); connect(file, SIGNAL(textChanged(QString)), this, SLOT(slotUrlChanged())); fileBoxLayout->addWidget(fileLabel, 0, 0, 0); fileBoxLayout->addWidget(file, 0, 1, 0); // Copies QLabel *copiesLabel = new QLabel(i18n("Copies:"), fileBox); QSpinBox *copies = new QSpinBox(fileBox); copies->setValue(1); copies->setMinimum(1); copies->setWhatsThis(i18n("This is the number of copies you want to print.")); fileBoxLayout->addWidget(copiesLabel, 1, 0, 0); fileBoxLayout->addWidget(copies, 1, 1, 0); layout->addWidget(fileBox); // // Buttons // QDialogButtonBox *buttonBox = new QDialogButtonBox(this); QPushButton *printButton = buttonBox->addButton(i18n("Print"), QDialogButtonBox::ActionRole); printButton->setObjectName("print_button"); printButton->setShortcut(Qt::CTRL|Qt::Key_P); connect(printButton, SIGNAL(clicked(bool)), this, SLOT(slotPrintButtonClicked())); QPushButton *cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel); cancelButton->setObjectName("cancel_button"); cancelButton->setShortcut(Qt::Key_Escape); cancelButton->setDefault(true); connect(cancelButton, SIGNAL(clicked(bool)), this, SLOT(slotCancelButtonClicked())); layout->addWidget(buttonBox); // // Set the minimum width // setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); // // Set the dialog size // create(); KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog"); KWindowConfig::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); // workaround for QTBUG-40584 // // Set the buttons // slotUrlChanged(); } Smb4KPrintDialog::~Smb4KPrintDialog() { } SharePtr Smb4KPrintDialog::share() const { return m_share; } KFileItem Smb4KPrintDialog::fileItem() const { return m_fileItem; } void Smb4KPrintDialog::slotUrlChanged() { // // Take the focus from the URL requester and give it to the dialog's // button box // QDialogButtonBox *buttonBox = findChild(); buttonBox->setFocus(); // // Get the URL from the URL requester // KUrlRequester *file = findChild(); KFileItem fileItem = KFileItem(file->url()); // // Apply the settings to the buttons of the dialog's button box // QPushButton *printButton = findChild("print_button"); printButton->setEnabled(fileItem.url().isValid() && fileItem.isFile()); printButton->setDefault(fileItem.url().isValid() && fileItem.isFile()); QPushButton *cancelButton = findChild("cancel_button"); cancelButton->setDefault(!fileItem.url().isValid() || !fileItem.isFile()); } void Smb4KPrintDialog::slotPrintButtonClicked() { // // Get the file item that is to be printed // KUrlRequester *file = findChild(); m_fileItem = KFileItem(file->url()); if (m_fileItem.url().isValid()) { // // Check if the mime type is supported or if the file can be // converted into a supported mimetype // if (m_fileItem.mimetype() != "application/postscript" && m_fileItem.mimetype() != "application/pdf" && m_fileItem.mimetype() != "application/x-shellscript" && !m_fileItem.mimetype().startsWith(QLatin1String("text")) && !m_fileItem.mimetype().startsWith(QLatin1String("message")) && !m_fileItem.mimetype().startsWith(QLatin1String("image"))) { Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype()); return; } // // Save the window size // KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); // // Emit the printFile() signal // QSpinBox *copies = findChild(); emit printFile(m_share, m_fileItem, copies->value()); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Close the print dialog // accept(); } } void Smb4KPrintDialog::slotCancelButtonClicked() { // // Abort the printing // Smb4KClient::self()->abort(); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Reject the dialog // reject(); } diff --git a/core/smb4khomesshareshandler.cpp b/core/smb4khomesshareshandler.cpp index 9372f6e..a27e0cb 100644 --- a/core/smb4khomesshareshandler.cpp +++ b/core/smb4khomesshareshandler.cpp @@ -1,500 +1,500 @@ /*************************************************************************** This class handles the homes shares ------------------- begin : Do Aug 10 2006 copyright : (C) 2006-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335 USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4khomesshareshandler.h" #include "smb4khomesshareshandler_p.h" #include "smb4kshare.h" #include "smb4ksettings.h" #include "smb4kauthinfo.h" #include "smb4knotification.h" #include "smb4kprofilemanager.h" // Qt includes #include #include #include #include #include #include // KDE includes #define TRANSLATION_DOMAIN "smb4k-core" #include Q_GLOBAL_STATIC(Smb4KHomesSharesHandlerStatic, p); Smb4KHomesSharesHandler::Smb4KHomesSharesHandler(QObject *parent) : QObject(parent), d(new Smb4KHomesSharesHandlerPrivate) { // First we need the directory. QString path = dataLocation(); QDir dir; if (!dir.exists(path)) { dir.mkpath(path); } d->homesUsers = readUserNames(false); + // // Connections - connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), - this, SLOT(slotAboutToQuit())); - connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), - this, SLOT(slotActiveProfileChanged(QString))); + // + connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit())); + connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), this, SLOT(slotActiveProfileChanged(QString))); } Smb4KHomesSharesHandler::~Smb4KHomesSharesHandler() { while (!d->homesUsers.isEmpty()) { delete d->homesUsers.takeFirst(); } } Smb4KHomesSharesHandler *Smb4KHomesSharesHandler::self() { return &p->instance; } bool Smb4KHomesSharesHandler::specifyUser(const SharePtr &share, bool overwrite) { Q_ASSERT(share); bool success = false; // Avoid that the dialog is opened although the homes // user name has already been defined. if (share->isHomesShare() && (share->homeUrl().isEmpty() || overwrite)) { QStringList users = findHomesUsers(share); QPointer dlg = new Smb4KHomesUserDialog(share, QApplication::activeWindow()); dlg->setUserNames(users); if (dlg->exec() == QDialog::Accepted) { QString login = dlg->login(); users = dlg->userNames(); addHomesUsers(share, users); if (!login.isEmpty()) { // If the login names do not match, clear the password. if (!share->login().isEmpty() && QString::compare(share->login(), login) != 0) { share->setPassword(QString()); } // Set the login name. share->setLogin(login); success = true; } writeUserNames(d->homesUsers); } delete dlg; } else { // The user name has already been set. success = true; } return success; } QStringList Smb4KHomesSharesHandler::homesUsers(const SharePtr &share) { Q_ASSERT(share); QStringList users = findHomesUsers(share); return users; } const QList Smb4KHomesSharesHandler::readUserNames(bool allUsers) { QList list; // Locate the XML file. QFile xmlFile(dataLocation()+QDir::separator()+"homes_shares.xml"); if (xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QXmlStreamReader xmlReader(&xmlFile); while (!xmlReader.atEnd()) { xmlReader.readNext(); if (xmlReader.isStartElement()) { if (xmlReader.name() == "homes_shares" && xmlReader.attributes().value("version") != "1.0") { xmlReader.raiseError(i18n("%1 is not a version 1.0 file.", xmlFile.fileName())); break; } else { if (xmlReader.name() == "homes") { QString profile = xmlReader.attributes().value("profile").toString(); // FIXME: Remove the last check in the if statement with Smb4K > 2.0. // It was introduced for migration, because the default profile // (e.g. use of no profiles) was not empty but named "Default"... if (allUsers || QString::compare(profile, Smb4KProfileManager::self()->activeProfile(), Qt::CaseSensitive) == 0 || (!Smb4KProfileManager::self()->useProfiles() && QString::compare(profile, "Default", Qt::CaseSensitive) == 0)) { Smb4KHomesUsers *users = new Smb4KHomesUsers(); users->setProfile(profile); users->setShareName(xmlReader.name().toString()); while (!(xmlReader.isEndElement() && xmlReader.name() == "homes")) { xmlReader.readNext(); if (xmlReader.isStartElement()) { if (xmlReader.name() == "host") { users->setHostName(xmlReader.readElementText()); } else if (xmlReader.name() == "workgroup") { users->setWorkgroupName(xmlReader.readElementText()); } else if (xmlReader.name() == "ip") { users->setHostIP(xmlReader.readElementText()); } else if (xmlReader.name() == "users") { QStringList u; while (!(xmlReader.isEndElement() && xmlReader.name() == "users")) { xmlReader.readNext(); if (xmlReader.isStartElement() && xmlReader.name() == "user") { u << xmlReader.readElementText(); } } users->setUsers(u); } continue; } else { continue; } } list << users; } else { continue; } } else { continue; } } } else { continue; } } xmlFile.close(); if (xmlReader.hasError()) { Smb4KNotification::readingFileFailed(xmlFile, xmlReader.errorString()); } } else { if (xmlFile.exists()) { Smb4KNotification::openingFileFailed(xmlFile); } } return list; } void Smb4KHomesSharesHandler::writeUserNames(const QList &list, bool listOnly) { QList allUsers; if (!listOnly) { // First read all entries. Then remove all, that belong to // the currently active profile. allUsers = readUserNames(true); QMutableListIterator it(allUsers); while (it.hasNext()) { Smb4KHomesUsers *users = it.next(); if (QString::compare(users->profile(), Smb4KProfileManager::self()->activeProfile()) == 0) { it.remove(); } } } for (Smb4KHomesUsers *users : list) { allUsers << new Smb4KHomesUsers(*users); } QFile xmlFile(dataLocation()+QDir::separator()+"homes_shares.xml"); if (!allUsers.isEmpty()) { if (xmlFile.open(QIODevice::WriteOnly|QIODevice::Text)) { QXmlStreamWriter xmlWriter(&xmlFile); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("homes_shares"); xmlWriter.writeAttribute("version", "1.0"); for (Smb4KHomesUsers *users : allUsers) { xmlWriter.writeStartElement("homes"); // FIXME: Remove this block with Smb4K > 2.0 and use the commented line below. // This block was introduced for migration, because the default profile // (i.e. use of no profiles) was not empty but named "Default"... if (!Smb4KProfileManager::self()->useProfiles()) { xmlWriter.writeAttribute("profile", Smb4KSettings::self()->activeProfile()); } else { xmlWriter.writeAttribute("profile", users->profile()); } // xmlWriter.writeAttribute("profile", users->profile()); xmlWriter.writeTextElement("host", users->hostName()); xmlWriter.writeTextElement("workgroup", users->workgroupName()); xmlWriter.writeTextElement("ip", users->hostIP()); xmlWriter.writeStartElement("users"); for (const QString &user : users->users()) { xmlWriter.writeTextElement("user", user); } xmlWriter.writeEndElement(); xmlWriter.writeEndElement(); } xmlWriter.writeEndDocument(); xmlFile.close(); } else { Smb4KNotification::openingFileFailed(xmlFile); } } else { xmlFile.remove(); } while (!allUsers.isEmpty()) { delete allUsers.takeFirst(); } } const QStringList Smb4KHomesSharesHandler::findHomesUsers(const SharePtr &share) { Q_ASSERT(share); QStringList users; if (!d->homesUsers.isEmpty()) { for (int i = 0; i < d->homesUsers.size(); ++i) { if (QString::compare(share->hostName(), d->homesUsers.at(i)->hostName(), Qt::CaseInsensitive) == 0 && QString::compare(share->shareName(), d->homesUsers.at(i)->shareName(), Qt::CaseInsensitive) == 0 && ((d->homesUsers.at(i)->workgroupName().isEmpty() || share->workgroupName().isEmpty()) || QString::compare(share->workgroupName(), d->homesUsers.at(i)->workgroupName(), Qt::CaseInsensitive) == 0)) { users = d->homesUsers.at(i)->users(); break; } else { continue; } } } return users; } void Smb4KHomesSharesHandler::addHomesUsers(const SharePtr &share, const QStringList &users) { Q_ASSERT(share); bool found = false; if (!d->homesUsers.isEmpty()) { for (int i = 0; i < d->homesUsers.size(); ++i) { if (QString::compare(share->hostName(), d->homesUsers.at(i)->hostName(), Qt::CaseInsensitive) == 0 && QString::compare(share->shareName(), d->homesUsers.at(i)->shareName(), Qt::CaseInsensitive) == 0 && ((d->homesUsers.at(i)->workgroupName().isEmpty() || share->workgroupName().isEmpty()) || QString::compare(share->workgroupName(), d->homesUsers.at(i)->workgroupName(), Qt::CaseInsensitive) == 0)) { d->homesUsers[i]->setUsers(users); found = true; break; } else { continue; } } } if (!found) { Smb4KHomesUsers *u = new Smb4KHomesUsers(share, users); u->setProfile(Smb4KProfileManager::self()->activeProfile()); d->homesUsers << u; } } void Smb4KHomesSharesHandler::migrateProfile(const QString& from, const QString& to) { // Read all entries for later conversion. QList allUsers = readUserNames(true); // Replace the old profile name with the new one. for (int i = 0; i < allUsers.size(); ++i) { if (QString::compare(allUsers.at(i)->profile(), from, Qt::CaseSensitive) == 0) { allUsers[i]->setProfile(to); } } // Write the new list to the file. writeUserNames(allUsers, true); // Profile settings changed, so invoke the slot. slotActiveProfileChanged(Smb4KProfileManager::self()->activeProfile()); // Clear the temporary lists of bookmarks and groups. while (!allUsers.isEmpty()) { delete allUsers.takeFirst(); } } void Smb4KHomesSharesHandler::removeProfile(const QString& name) { // Read all entries for later removal. QList allUsers = readUserNames(true); QMutableListIterator it(allUsers); while (it.hasNext()) { Smb4KHomesUsers *user = it.next(); if (QString::compare(user->profile(), name, Qt::CaseSensitive) == 0) { it.remove(); } } // Write the new list to the file. writeUserNames(allUsers, true); // Profile settings changed, so invoke the slot. slotActiveProfileChanged(Smb4KProfileManager::self()->activeProfile()); // Clear the temporary list of homes users. while (!allUsers.isEmpty()) { delete allUsers.takeFirst(); } } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KHomesSharesHandler::slotAboutToQuit() { writeUserNames(d->homesUsers); } void Smb4KHomesSharesHandler::slotActiveProfileChanged(const QString& /*activeProfile*/) { // Clear the list of homes users. while (!d->homesUsers.isEmpty()) { delete d->homesUsers.takeFirst(); } // Reload the list of homes users. d->homesUsers = readUserNames(false); } diff --git a/core/smb4kmounter.cpp b/core/smb4kmounter.cpp index 03a3ac5..50c276a 100644 --- a/core/smb4kmounter.cpp +++ b/core/smb4kmounter.cpp @@ -1,2470 +1,2472 @@ /*************************************************************************** The core class that mounts the shares. ------------------- begin : Die Jun 10 2003 copyright : (C) 2003-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // Application specific includes #include "smb4kmounter.h" #include "smb4kmounter_p.h" #include "smb4kauthinfo.h" #include "smb4kshare.h" #include "smb4ksettings.h" #include "smb4khomesshareshandler.h" #include "smb4kwalletmanager.h" #include "smb4kprocess.h" #include "smb4knotification.h" #include "smb4kbookmarkhandler.h" #include "smb4kcustomoptionsmanager.h" #include "smb4kcustomoptions.h" #include "smb4kbookmark.h" #include "smb4kprofilemanager.h" #include "smb4khardwareinterface.h" #if defined(Q_OS_LINUX) #include "smb4kmountsettings_linux.h" #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) #include "smb4kmountsettings_bsd.h" #endif // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #define TRANSLATION_DOMAIN "smb4k-core" #include #include #include #include #include #include #include #include #include using namespace Smb4KGlobal; #define TIMEOUT 50 Q_GLOBAL_STATIC(Smb4KMounterStatic, p); Smb4KMounter::Smb4KMounter(QObject *parent) : KCompositeJob(parent), d(new Smb4KMounterPrivate) { setAutoDelete(false); d->timerId = -1; d->remountTimeout = 0; d->remountAttempts = 0; d->checkTimeout = 0; d->newlyMounted = 0; d->newlyUnmounted = 0; d->dialog = 0; d->firstImportDone = false; d->mountShares = false; d->unmountShares = false; d->activeProfile = Smb4KProfileManager::self()->activeProfile(); d->detectAllShares = Smb4KMountSettings::detectAllShares(); + // // Connections + // connect(Smb4KHardwareInterface::self(), SIGNAL(onlineStateChanged(bool)), this, SLOT(slotOnlineStateChanged(bool))); connect(Smb4KHardwareInterface::self(), SIGNAL(networkShareAdded()), this, SLOT(slotTriggerImport())); connect(Smb4KHardwareInterface::self(), SIGNAL(networkShareRemoved()), this, SLOT(slotTriggerImport())); connect(Smb4KProfileManager::self(), SIGNAL(migratedProfile(QString,QString)), this, SLOT(slotProfileMigrated(QString,QString))); connect(Smb4KProfileManager::self(), SIGNAL(aboutToChangeProfile()), this, SLOT(slotAboutToChangeProfile())); connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), this, SLOT(slotActiveProfileChanged(QString))); connect(Smb4KMountSettings::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged())); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),this, SLOT(slotAboutToQuit())); } Smb4KMounter::~Smb4KMounter() { while (!d->importedShares.isEmpty()) { d->importedShares.takeFirst().clear(); } while (!d->retries.isEmpty()) { d->retries.takeFirst().clear(); } } Smb4KMounter *Smb4KMounter::self() { return &p->instance; } void Smb4KMounter::abort() { if (!QCoreApplication::closingDown()) { QListIterator it(subjobs()); while (it.hasNext()) { it.next()->kill(KJob::EmitResult); } } } bool Smb4KMounter::isRunning() { return hasSubjobs(); } void Smb4KMounter::triggerRemounts(bool fill_list) { if (Smb4KMountSettings::remountShares() /* one-time remounts */ || !Smb4KCustomOptionsManager::self()->sharesToRemount().isEmpty() /* permanent remounts */) { if (fill_list) { // // Get the shares that are to be remounted // QList list = Smb4KCustomOptionsManager::self()->sharesToRemount(); if (!list.isEmpty()) { // // Check which shares actually need to be remounted // for (const OptionsPtr &opt : list) { QList mountedShares = findShareByUrl(opt->url()); if (!mountedShares.isEmpty()) { bool mount = true; for (const SharePtr &s : mountedShares) { if (!s->isForeign()) { mount = false; break; } else { continue; } } if (mount) { SharePtr share = SharePtr(new Smb4KShare()); share->setUrl(opt->url()); share->setWorkgroupName(opt->workgroupName()); share->setHostIpAddress(opt->ipAddress()); if (share->url().isValid() && !share->url().isEmpty()) { d->remounts << share; } } } else { SharePtr share = SharePtr(new Smb4KShare()); share->setUrl(opt->url()); share->setWorkgroupName(opt->workgroupName()); share->setHostIpAddress(opt->ipAddress()); if (share->url().isValid() && !share->url().isEmpty()) { d->remounts << share; } } } } } if (!d->remounts.isEmpty()) { mountShares(d->remounts); } d->remountAttempts++; } } void Smb4KMounter::import(bool checkInaccessible) { // // Immediately return here if we are still processing imported shares // if (!d->importedShares.isEmpty()) { return; } // // Get the mountpoints that are present on the system // KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::BasicInfoNeeded|KMountPoint::NeedMountOptions); // Now determine all mountpoints that have the SMBFS or the CIFS // filesystem. for (const QExplicitlySharedDataPointer &mountPoint : mountPoints) { if (QString::compare(mountPoint->mountType(), "cifs") == 0 || QString::compare(mountPoint->mountType(), "smbfs") == 0) { // Create new share and set the mountpoint and the filesystem SharePtr share = SharePtr(new Smb4KShare()); share->setUrl(mountPoint->mountedFrom()); share->setPath(mountPoint->mountPoint()); share->setMounted(true); // Get all mount options for (const QString &option : mountPoint->mountOptions()) { if (option.startsWith(QLatin1String("domain=")) || option.startsWith(QLatin1String("workgroup="))) { share->setWorkgroupName(option.section('=', 1, 1).trimmed()); } else if (option.startsWith(QLatin1String("addr="))) { share->setHostIpAddress(option.section('=', 1, 1).trimmed()); } else if (option.startsWith(QLatin1String("username=")) || option.startsWith(QLatin1String("user="))) { share->setLogin(option.section('=', 1, 1).trimmed()); } } // Work around empty usernames if (share->login().isEmpty()) { share->setLogin("guest"); } d->importedShares << share; } } // // Check which shares were unmounted. Remove all obsolete mountpoints, emit // the unmounted() signal on each of the unmounted shares and remove them // from the global list. // NOTE: The unmount() signal is emitted *BEFORE* the share is removed // from the global list! You need to account for that in your application. // QList unmountedShares; bool found = false; for (const SharePtr &mountedShare : mountedSharesList()) { for (const SharePtr &importedShare : d->importedShares) { // Check the mountpoint, since that one is unique. We will only use // Smb4KShare::path(), so that we do not run into trouble if a share // is inaccessible. if (QString::compare(mountedShare->path(), importedShare->path()) == 0) { found = true; break; } } if (!found) { // Remove the mountpoint if the share is not a foreign one if (!mountedShare->isForeign()) { QDir dir; dir.cd(mountedShare->canonicalPath()); dir.rmdir(dir.canonicalPath()); if (dir.cdUp()) { dir.rmdir(dir.canonicalPath()); } } mountedShare->setMounted(false); unmountedShares << mountedShare; } found = false; } if (!unmountedShares.isEmpty()) { d->newlyUnmounted += unmountedShares.size(); if (!d->mountShares && !d->unmountShares) { if (d->newlyUnmounted == 1) { // Copy the share SharePtr unmountedShare = unmountedShares.first(); // Remove the share from the global list and notify the program and user removeMountedShare(unmountedShares.first()); emit unmounted(unmountedShare); Smb4KNotification::shareUnmounted(unmountedShare); unmountedShare.clear(); } else { for (const SharePtr &share : unmountedShares) { // Copy the share SharePtr unmountedShare = share; // Remove the share from the global list and notify the program removeMountedShare(share); emit unmounted(unmountedShare); unmountedShare.clear(); } // Notify the user Smb4KNotification::sharesUnmounted(d->newlyUnmounted); } d->newlyUnmounted = 0; } else { for (const SharePtr &share : unmountedShares) { // Copy the share SharePtr unmountedShare = share; // Remove the share from the global list and notify the program removeMountedShare(share); emit unmounted(unmountedShare); unmountedShare.clear(); } } emit mountedSharesListChanged(); } else { d->newlyUnmounted = 0; } // // Now stat the imported shares to get information about them. // Do not use Smb4KShare::canonicalPath() here, otherwise we might // get lock-ups with inaccessible shares. // if (Smb4KHardwareInterface::self()->isOnline()) { QMutableListIterator it(d->importedShares); while (it.hasNext()) { SharePtr share = it.next(); SharePtr mountedShare = findShareByPath(share->path()); if (mountedShare) { if (mountedShare->isInaccessible() && !checkInaccessible) { it.remove(); continue; } } QUrl url = QUrl::fromLocalFile(share->path()); KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo); job->setDetails(0); connect(job, SIGNAL(result(KJob*)), this, SLOT(slotStatResult(KJob*))); // Do not use addSubJob(), because that would confuse isRunning(), etc. job->start(); } // // Set d->firstImportDone here only for the case that no mounted shares // could be found. In all other cases d->firstImportDone will be set in // slotStatResult(). // if (!d->firstImportDone && d->importedShares.isEmpty()) { d->firstImportDone = true; } } } void Smb4KMounter::mountShare(const SharePtr &share) { Q_ASSERT(share); if (share) { // // Check that the URL is valid // if (!share->url().isValid()) { Smb4KNotification::invalidURLPassed(); return; } // // Check if the share has already been mounted. If it is already present, // do not process it and return. // QUrl url; if (share->isHomesShare()) { if (!Smb4KHomesSharesHandler::self()->specifyUser(share, true)) { return; } url = share->homeUrl(); } else { url = share->url(); } QList mountedShares = findShareByUrl(url); bool isMounted = false; for (const SharePtr &s : mountedShares) { if (!s->isForeign()) { isMounted = true; break; } } if (isMounted) { return; } // // Wake-On-LAN: Wake up the host before mounting // if (Smb4KSettings::enableWakeOnLAN()) { OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(KIO::upUrl(share->url())); if (options && options->wolSendBeforeMount()) { emit aboutToStart(WakeUp); QUdpSocket *socket = new QUdpSocket(this); QHostAddress addr; // Use the host's IP address directly from the share object. if (share->hasHostIpAddress()) { addr.setAddress(share->hostIpAddress()); } else { addr.setAddress("255.255.255.255"); } // Construct magic sequence QByteArray sequence; // 6 times 0xFF for (int j = 0; j < 6; ++j) { sequence.append(QChar(0xFF).toLatin1()); } // 16 times the MAC address QStringList parts = options->macAddress().split(':', QString::SkipEmptyParts); for (int j = 0; j < 16; ++j) { for (int k = 0; k < parts.size(); ++k) { sequence.append(QChar(QString("0x%1").arg(parts.at(k)).toInt(0, 16)).toLatin1()); } } socket->writeDatagram(sequence, addr, 9); delete socket; // Wait the defined time int stop = 1000 * Smb4KSettings::wakeOnLANWaitingTime() / 250; int i = 0; while (i++ < stop) { QTest::qWait(250); } emit finished(WakeUp); } } // // Create the mountpoint // QString mountpoint; mountpoint += Smb4KMountSettings::mountPrefix().path(); mountpoint += QDir::separator(); mountpoint += (Smb4KMountSettings::forceLowerCaseSubdirs() ? share->hostName().toLower() : share->hostName()); mountpoint += QDir::separator(); if (!share->isHomesShare()) { mountpoint += (Smb4KMountSettings::forceLowerCaseSubdirs() ? share->shareName().toLower() : share->shareName()); } else { mountpoint += (Smb4KMountSettings::forceLowerCaseSubdirs() ? share->login().toLower() : share->login()); } // Get the permissions that should be used for creating the // mount prefix and all its subdirectories. // Please note that the actual permissions of the mount points // are determined by the mount utility. QFile::Permissions permissions; QUrl parentDirectory; if (QFile::exists(Smb4KMountSettings::mountPrefix().path())) { parentDirectory = Smb4KMountSettings::mountPrefix(); } else { QUrl u = Smb4KMountSettings::mountPrefix(); parentDirectory = KIO::upUrl(u); } QFile f(parentDirectory.path()); permissions = f.permissions(); QDir dir(mountpoint); if (!dir.mkpath(dir.path())) { share->setPath(""); Smb4KNotification::mkdirFailed(dir); return; } else { QUrl u = QUrl::fromLocalFile(dir.path()); while (!parentDirectory.matches(u, QUrl::StripTrailingSlash)) { QFile(u.path()).setPermissions(permissions); u = KIO::upUrl(u); } } share->setPath(QDir::cleanPath(mountpoint)); // // Get the authentication information // Smb4KWalletManager::self()->readAuthInfo(share); // // Mount arguments // QVariantMap args; if (!fillMountActionArgs(share, args)) { return; } // // Emit the aboutToStart() signal // emit aboutToStart(MountShare); // // Create the mount action // KAuth::Action mountAction("org.kde.smb4k.mounthelper.mount"); mountAction.setHelperId("org.kde.smb4k.mounthelper"); mountAction.setArguments(args); KAuth::ExecuteJob *job = mountAction.execute(); // // Modify the cursor, if necessary. // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job // addSubjob(job); // // Start the job and process the returned result. // bool success = job->exec(); if (success) { int errorCode = job->error(); if (errorCode == 0) { // Get the error message QString errorMsg = job->data()["mh_error_message"].toString(); if (!errorMsg.isEmpty()) { #if defined(Q_OS_LINUX) if (errorMsg.contains("mount error 13") || errorMsg.contains("mount error(13)") /* authentication error */) { if (Smb4KWalletManager::self()->showPasswordDialog(share)) { d->retries << share; } } else if (errorMsg.contains("Unable to find suitable address.")) { // Swallow this } else { Smb4KNotification::mountingFailed(share, errorMsg); } #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) if (errorMsg.contains("Authentication error") || errorMsg.contains("Permission denied")) { if (Smb4KWalletManager::self()->showPasswordDialog(share)) { d->retries << share; } } else { Smb4KNotification::mountingFailed(share, errorMsg); } #else qWarning() << "Smb4KMounter::slotMountJobFinished(): Error handling not implemented!"; Smb4KNotification::mountingFailed(share.data(), errorMsg); #endif } } else { Smb4KNotification::actionFailed(errorCode); } } else { // FIXME: Report that the action could not be started } // // Remove the job from the job list // removeSubjob(job); // // Reset the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::restoreOverrideCursor(); } // // Emit the finished() signal // emit finished(MountShare); } } void Smb4KMounter::mountShares(const QList &shares) { d->mountShares = true; for (const SharePtr &share : shares) { mountShare(share); } d->mountShares = false; } void Smb4KMounter::unmountShare(const SharePtr &share, bool silent) { Q_ASSERT(share); if (share) { // // Check that the URL is valid. // if (!share->url().isValid()) { Smb4KNotification::invalidURLPassed(); return; } // // Handle foreign shares according to the settings // if (share->isForeign()) { if (!Smb4KMountSettings::unmountForeignShares()) { if (!silent) { Smb4KNotification::unmountingNotAllowed(share); } return; } else { if (!silent) { if (KMessageBox::warningYesNo(QApplication::activeWindow(), i18n("

The share %1 is mounted to
%2 and owned by user %3.

" "

Do you really want to unmount it?

", share->displayString(), share->path(), share->user().loginName()), i18n("Foreign Share")) == KMessageBox::No) { return; } } else { // Without the confirmation of the user, we are not // unmounting a foreign share! return; } } } // // Force the unmounting of the share either if the system went offline // or if the user chose to forcibly unmount inaccessible shares (Linux only). // bool force = false; if (Smb4KHardwareInterface::self()->isOnline()) { #if defined(Q_OS_LINUX) if (share->isInaccessible()) { force = Smb4KMountSettings::forceUnmountInaccessible(); } #endif } else { force = true; } // // Unmount arguments // QVariantMap args; if (!fillUnmountActionArgs(share, force, silent, args)) { return; } // // Emit the aboutToStart() signal // emit aboutToStart(UnmountShare); // // Create the unmount action // KAuth::Action unmountAction("org.kde.smb4k.mounthelper.unmount"); unmountAction.setHelperId("org.kde.smb4k.mounthelper"); unmountAction.setArguments(args); KAuth::ExecuteJob *job = unmountAction.execute(); // // Modify the cursor, if necessary. // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job // addSubjob(job); // // Start the job and process the returned result. // bool success = job->exec(); if (success) { int errorCode = job->error(); if (errorCode == 0) { // Get the error message QString errorMsg = job->data()["mh_error_message"].toString(); if (!errorMsg.isEmpty()) { // No error handling needed, just report the error message. Smb4KNotification::unmountingFailed(share, errorMsg); } } else { Smb4KNotification::actionFailed(errorCode); } } else { // FIXME: Report that the action could not be started } // // Remove the job from the job list // removeSubjob(job); // // Reset the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::restoreOverrideCursor(); } // // Emit the finished() signal // emit finished(UnmountShare); } } void Smb4KMounter::unmountShares(const QList &shares, bool silent) { #if defined(Q_OS_LINUX) // // Under Linux, we have to take an approach that is a bit awkward in this function. // Since the import function is invoked via Smb4KHardwareInterface::networkShareRemoved() // before mountShare() returns, no unmount of multiple shares will ever be reported // when d->unmountShares is set to FALSE *after* the loop ended. To make the reporting // work correctly, we need to set d->unmountShares to FALSE before the last unmount // is started. // d->unmountShares = true; int number = shares.size(); for (const SharePtr &share : shares) { number--; d->unmountShares = (number != 0); unmountShare(share, silent); } #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) // // Since under FreeBSD the emission of Smb4KHardwareInterface::networkShareRemoved() is // triggered by a timer, we can use a nice approach here. // d->unmountShares = true; for (const SharePtr &share : shares) { unmountShare(share, silent); } d->unmountShares = false; #endif } void Smb4KMounter::unmountAllShares(bool silent) { unmountShares(mountedSharesList(), silent); } void Smb4KMounter::openMountDialog() { if (!d->dialog) { SharePtr share = SharePtr(new Smb4KShare()); d->dialog = new Smb4KMountDialog(share, QApplication::activeWindow()); if (d->dialog->exec() == QDialog::Accepted && d->dialog->validUserInput()) { // Pass the share to mountShare(). mountShare(share); // Bookmark the share if the user wants this. if (d->dialog->bookmarkShare()) { Smb4KBookmarkHandler::self()->addBookmark(share); } } delete d->dialog; d->dialog = 0; share.clear(); } } void Smb4KMounter::start() { // // Check the network configurations // Smb4KHardwareInterface::self()->updateNetworkConfig(); // // Connect to Smb4KHardwareInterface to be able to get the response // connect(Smb4KHardwareInterface::self(), SIGNAL(networkConfigUpdated()), this, SLOT(slotStartJobs())); } void Smb4KMounter::saveSharesForRemount() { // // Save the shares for remount // for (const SharePtr &share : mountedSharesList()) { if (!share->isForeign()) { Smb4KCustomOptionsManager::self()->addRemount(share, false); } else { Smb4KCustomOptionsManager::self()->removeRemount(share, false); } } // // Also save each failed remount and remove it from the list // while (!d->remounts.isEmpty()) { SharePtr share = d->remounts.takeFirst(); Smb4KCustomOptionsManager::self()->addRemount(share, false); share.clear(); } } void Smb4KMounter::timerEvent(QTimerEvent *) { // Try to remount those shares that could not be mounted // before. Do this only if there are no subjobs, because we // do not want to get crashes because a share was invalidated // during processing the shares. if ((Smb4KMountSettings::remountShares() || !Smb4KCustomOptionsManager::self()->sharesToRemount().isEmpty()) && Smb4KMountSettings::remountAttempts() > d->remountAttempts) { if (d->firstImportDone && !isRunning()) { if (d->remountAttempts == 0) { triggerRemounts(true); } else if (!d->remounts.isEmpty() && d->remountTimeout >= (60000 * Smb4KMountSettings::remountInterval())) { triggerRemounts(false); d->remountTimeout = -TIMEOUT; } } d->remountTimeout += TIMEOUT; } // Retry mounting those shares that failed. This is also only // done when there are no subjobs. if (!d->retries.isEmpty() && !hasSubjobs()) { mountShares(d->retries); while (!d->retries.isEmpty()) { d->retries.takeFirst().clear(); } } // // Check the size, accessibility, etc. of the shares // // FIXME: Hopefully we can replace this with a recursive QFileSystemWatcher // approach in the future. However, using the existing QFileSystemWatcher // and a QDirIterator to add all the subdirectories of a share to the watcher // seems to be too resource consuming... // if (d->checkTimeout >= 2500 && !isRunning() && d->importedShares.isEmpty()) { for (const SharePtr &share : mountedSharesList()) { check(share); emit updated(share); } d->checkTimeout = 0; } else { d->checkTimeout += TIMEOUT; } } #if defined(Q_OS_LINUX) // // Linux arguments // bool Smb4KMounter::fillMountActionArgs(const SharePtr &share, QVariantMap& map) { // // Find the mount executable // const QString mount = findMountExecutable(); if (!mount.isEmpty()) { map.insert("mh_command", mount); } else { Smb4KNotification::commandNotFound("mount.cifs"); return false; } // // Global and custom options // QMap globalOptions = globalSambaOptions(); OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(share); // // Pass the remote file system port to the URL // if (options) { if (options->useFileSystemPort()) { share->setPort(options->fileSystemPort()); } } else { if (Smb4KMountSettings::useRemoteFileSystemPort()) { share->setPort(Smb4KMountSettings::remoteFileSystemPort()); } } // // List of arguments passed via "-o ..." to the mount command // QStringList argumentsList; // // Workgroup or domain // if (!share->workgroupName().trimmed().isEmpty()) { argumentsList << QString("domain=%1").arg(KShell::quoteArg(share->workgroupName())); } // // Host IP address // if (share->hasHostIpAddress()) { argumentsList << QString("ip=%1").arg(share->hostIpAddress()); } // // User name (login) // if (!share->login().isEmpty()) { argumentsList << QString("username=%1").arg(share->login()); } else { argumentsList << "guest"; } // // Client's and server's NetBIOS name // // According to the manual page, this is only needed when port 139 // is used. So, we only pass the NetBIOS name in that case. // if (options) { if (options->useFileSystemPort() && options->fileSystemPort() == 139) { // The client's NetBIOS name if (!Smb4KSettings::netBIOSName().isEmpty()) { argumentsList << QString("netbiosname=%1").arg(KShell::quoteArg(Smb4KSettings::netBIOSName())); } else if (!globalOptions["netbios name"].isEmpty()) { argumentsList << QString("netbiosname=%1").arg(KShell::quoteArg(globalOptions["netbios name"])); } // The server's NetBIOS name argumentsList << QString("servernetbiosname=%1").arg(KShell::quoteArg(share->hostName())); } } else { if (Smb4KMountSettings::useRemoteFileSystemPort() && Smb4KMountSettings::remoteFileSystemPort() == 139) { // The client's NetBIOS name if (!Smb4KSettings::netBIOSName().isEmpty()) { argumentsList << QString("netbiosname=%1").arg(KShell::quoteArg(Smb4KSettings::netBIOSName())); } else if (!globalOptions["netbios name"].isEmpty()) { argumentsList << QString("netbiosname=%1").arg(KShell::quoteArg(globalOptions["netbios name"])); } // The server's NetBIOS name argumentsList << QString("servernetbiosname=%1").arg(KShell::quoteArg(share->hostName())); } } // // CIFS Unix extensions support // // This sets the uid, gid, file_mode and dir_mode arguments, if necessary. // if (options) { if (!options->cifsUnixExtensionsSupport()) { // User id if (options->useUser()) { argumentsList << QString("uid=%1").arg(options->user().userId().nativeId()); } // Group id if (options->useGroup()) { argumentsList << QString("gid=%1").arg(options->group().groupId().nativeId()); } // File mode if (options->useFileMode()) { argumentsList << QString("file_mode=%1").arg(options->fileMode()); } // Directory mode if (options->useDirectoryMode()) { argumentsList << QString("dir_mode=%1").arg(options->directoryMode()); } } } else { if (!Smb4KMountSettings::cifsUnixExtensionsSupport()) { // User id if (Smb4KMountSettings::useUserId()) { argumentsList << QString("uid=%1").arg((K_UID)Smb4KMountSettings::userId().toInt()); } // Group id if (Smb4KMountSettings::useGroupId()) { argumentsList << QString("gid=%1").arg((K_GID)Smb4KMountSettings::groupId().toInt()); } // File mode if (Smb4KMountSettings::useFileMode()) { argumentsList << QString("file_mode=%1").arg(Smb4KMountSettings::fileMode()); } // Directory mode if (Smb4KMountSettings::useDirectoryMode()) { argumentsList << QString("dir_mode=%1").arg(Smb4KMountSettings::directoryMode()); } } } // // Force user id // // FIXME: The manual page is not clear about this: Is this option only useful when the uid=... // argument is given? If so, this should be moved into the 'User id' code block above. // if (Smb4KMountSettings::forceUID()) { argumentsList << "forceuid"; } // // Force group id // // FIXME: The manual page is not clear about this: Is this option only useful when the gid=... // argument is given? If so, this should be moved into the 'Group id' code block above. // if (Smb4KMountSettings::forceGID()) { argumentsList << "forcegid"; } // // Client character set // if (Smb4KMountSettings::useClientCharset()) { switch (Smb4KMountSettings::clientCharset()) { case Smb4KMountSettings::EnumClientCharset::default_charset: { if (!globalOptions["unix charset"].isEmpty()) { argumentsList << QString("iocharset=%1").arg(globalOptions["unix charset"].toLower()); } break; } default: { argumentsList << QString("iocharset=%1").arg(Smb4KMountSettings::self()->clientCharsetItem()->choices().value(Smb4KMountSettings::clientCharset()).label); break; } } } // // File system port // if (options) { if (options->useFileSystemPort()) { argumentsList << QString("port=%1").arg(options->fileSystemPort()); } } else { if (Smb4KMountSettings::useRemoteFileSystemPort()) { argumentsList << QString("port=%1").arg(Smb4KMountSettings::remoteFileSystemPort()); } } // // Write access // if (options) { if (options->useWriteAccess()) { switch (options->writeAccess()) { case Smb4KMountSettings::EnumWriteAccess::ReadWrite: { argumentsList << "rw"; break; } case Smb4KMountSettings::EnumWriteAccess::ReadOnly: { argumentsList << "ro"; break; } default: { break; } } } } else { if (Smb4KMountSettings::useWriteAccess()) { switch (Smb4KMountSettings::writeAccess()) { case Smb4KMountSettings::EnumWriteAccess::ReadWrite: { argumentsList << "rw"; break; } case Smb4KMountSettings::EnumWriteAccess::ReadOnly: { argumentsList << "ro"; break; } default: { break; } } } } // // Permission checks // if (Smb4KMountSettings::permissionChecks()) { argumentsList << "perm"; } else { argumentsList << "noperm"; } // // Client controls ids // if (Smb4KMountSettings::clientControlsIDs()) { argumentsList << "setuids"; } else { argumentsList << "nosetuids"; } // // Server inode numbers // if (Smb4KMountSettings::serverInodeNumbers()) { argumentsList << "serverino"; } else { argumentsList << "noserverino"; } // // Cache mode // if (Smb4KMountSettings::useCacheMode()) { switch (Smb4KMountSettings::cacheMode()) { case Smb4KMountSettings::EnumCacheMode::None: { argumentsList << "cache=none"; break; } case Smb4KMountSettings::EnumCacheMode::Strict: { argumentsList << "cache=strict"; break; } case Smb4KMountSettings::EnumCacheMode::Loose: { argumentsList << "cache=loose"; break; } default: { break; } } } // // Translate reserved characters // if (Smb4KMountSettings::translateReservedChars()) { argumentsList << "mapchars"; } else { argumentsList << "nomapchars"; } // // Locking // if (Smb4KMountSettings::noLocking()) { argumentsList << "nolock"; } // // Security mode // if (options) { if (options->useSecurityMode()) { switch (options->securityMode()) { case Smb4KMountSettings::EnumSecurityMode::None: { argumentsList << "sec=none"; break; } case Smb4KMountSettings::EnumSecurityMode::Krb5: { argumentsList << "sec=krb5"; argumentsList << QString("cruid=%1").arg(KUser(KUser::UseRealUserID).userId().nativeId()); break; } case Smb4KMountSettings::EnumSecurityMode::Krb5i: { argumentsList << "sec=krb5i"; argumentsList << QString("cruid=%1").arg(KUser(KUser::UseRealUserID).userId().nativeId()); break; } case Smb4KMountSettings::EnumSecurityMode::Ntlm: { argumentsList << "sec=ntlm"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmi: { argumentsList << "sec=ntlmi"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmv2: { argumentsList << "sec=ntlmv2"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmv2i: { argumentsList << "sec=ntlmv2i"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmssp: { argumentsList << "sec=ntlmssp"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmsspi: { argumentsList << "sec=ntlmsspi"; break; } default: { // Smb4KSettings::EnumSecurityMode::Default, break; } } } } else { if (Smb4KMountSettings::useSecurityMode()) { switch (Smb4KMountSettings::securityMode()) { case Smb4KMountSettings::EnumSecurityMode::None: { argumentsList << "sec=none"; break; } case Smb4KMountSettings::EnumSecurityMode::Krb5: { argumentsList << "sec=krb5"; argumentsList << QString("cruid=%1").arg(KUser(KUser::UseRealUserID).userId().nativeId()); break; } case Smb4KMountSettings::EnumSecurityMode::Krb5i: { argumentsList << "sec=krb5i"; argumentsList << QString("cruid=%1").arg(KUser(KUser::UseRealUserID).userId().nativeId()); break; } case Smb4KMountSettings::EnumSecurityMode::Ntlm: { argumentsList << "sec=ntlm"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmi: { argumentsList << "sec=ntlmi"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmv2: { argumentsList << "sec=ntlmv2"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmv2i: { argumentsList << "sec=ntlmv2i"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmssp: { argumentsList << "sec=ntlmssp"; break; } case Smb4KMountSettings::EnumSecurityMode::Ntlmsspi: { argumentsList << "sec=ntlmsspi"; break; } default: { // Smb4KSettings::EnumSecurityMode::Default, break; } } } } // // SMB protocol version // if (Smb4KMountSettings::useSmbProtocolVersion()) { switch (Smb4KMountSettings::smbProtocolVersion()) { case Smb4KMountSettings::EnumSmbProtocolVersion::OnePointZero: { argumentsList << "vers=1.0"; break; } case Smb4KMountSettings::EnumSmbProtocolVersion::TwoPointZero: { argumentsList << "vers=2.0"; break; } case Smb4KMountSettings::EnumSmbProtocolVersion::TwoPointOne: { argumentsList << "vers=2.1"; break; } case Smb4KMountSettings::EnumSmbProtocolVersion::ThreePointZero: { argumentsList << "vers=3.0"; break; } case Smb4KMountSettings::EnumSmbProtocolVersion::ThreePointOnePointOne: { argumentsList << "vers=3.1.1"; break; } default: { break; } } } // // Mount options provided by the user // if (!Smb4KMountSettings::customCIFSOptions().isEmpty()) { // SECURITY: Only pass those arguments to mount.cifs that do not pose // a potential security risk and that have not already been defined. // // This is, among others, the proper fix to the security issue reported // by Heiner Markert (aka CVE-2014-2581). QStringList whitelist = whitelistedMountArguments(); QStringList list = Smb4KMountSettings::customCIFSOptions().split(',', QString::SkipEmptyParts); QMutableStringListIterator it(list); while (it.hasNext()) { QString arg = it.next().section("=", 0, 0); if (!whitelist.contains(arg)) { it.remove(); } argumentsList += list; } } // // Insert the mount options into the map // QStringList mh_options; mh_options << "-o"; mh_options << argumentsList.join(","); map.insert("mh_options", mh_options); // // Insert the mountpoint into the map // map.insert("mh_mountpoint", share->canonicalPath()); // // Insert information about the share and its URL into the map // if (!share->isHomesShare()) { map.insert("mh_url", share->url()); } else { map.insert("mh_url", share->homeUrl()); map.insert("mh_homes_url", share->url()); } map.insert("mh_workgroup", share->workgroupName()); map.insert("mh_ip", share->hostIpAddress()); // // Location of the Kerberos ticket // // The path to the Kerberos ticket is stored - if it exists - in the // KRB5CCNAME environment variable. By default, the ticket is located // at /tmp/krb5cc_[uid]. So, if the environment variable does not exist, // but the cache file is there, try to use it. // if (QProcessEnvironment::systemEnvironment().contains("KRB5CCNAME")) { map.insert("mh_krb5ticket", QProcessEnvironment::systemEnvironment().value("KRB5CCNAME", "")); } else { QString ticket = QString("/tmp/krb5cc_%1").arg(KUser(KUser::UseRealUserID).userId().nativeId()); if (QFile::exists(ticket)) { map.insert("mh_krb5ticket", "FILE:"+ticket); } } return true; } #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) // // FreeBSD and NetBSD arguments // bool Smb4KMounter::fillMountActionArgs(const SharePtr &share, QVariantMap& map) { // // Find the mount executable // const QString mount = findMountExecutable(); if (!mount.isEmpty()) { map.insert("mh_command", mount); } else { Smb4KNotification::commandNotFound("mount_smbfs"); return false; } // // Global and custom options // QMap globalOptions = globalSambaOptions(); OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(share); // // List of arguments // QStringList argumentsList; // // Workgroup // if (!share->workgroupName().isEmpty()) { argumentsList << "-W"; argumentsList << KShell::quoteArg(share->workgroupName()); } // // IP address // if (!share->hostIpAddress().isEmpty()) { argumentsList << "-I"; argumentsList << share->hostIpAddress(); } // // User Id // if (options) { if (options->useUser()) { argumentsList << "-u"; argumentsList << QString("%1").arg(options->user().userId().nativeId()); } } else { if (Smb4KMountSettings::useUserId()) { argumentsList << "-u"; argumentsList << QString("%1").arg((K_UID)Smb4KMountSettings::userId().toInt()); } } // // Group Id // if (options) { if (options->useGroup()) { argumentsList << "-g"; argumentsList << QString("%1").arg(options->group().groupId().nativeId()); } } else { if (Smb4KMountSettings::useGroupId()) { argumentsList << "-g"; argumentsList << QString("%1").arg((K_GID)Smb4KMountSettings::groupId().toInt()); } } if (Smb4KMountSettings::useCharacterSets()) { // Client character set QString clientCharset, serverCharset; switch (Smb4KMountSettings::clientCharset()) { case Smb4KMountSettings::EnumClientCharset::default_charset: { clientCharset = globalOptions["unix charset"].toLower(); // maybe empty break; } default: { clientCharset = Smb4KMountSettings::self()->clientCharsetItem()->choices().value(Smb4KMountSettings::clientCharset()).label; break; } } // Server character set switch (Smb4KMountSettings::serverCodepage()) { case Smb4KMountSettings::EnumServerCodepage::default_codepage: { serverCharset = globalOptions["dos charset"].toLower(); // maybe empty break; } default: { serverCharset = Smb4KMountSettings::self()->serverCodepageItem()->choices().value(Smb4KMountSettings::serverCodepage()).label; break; } } if (!clientCharset.isEmpty() && !serverCharset.isEmpty()) { argumentsList << "-E"; argumentsList << QString("%1:%2").arg(clientCharset, serverCharset); } } // // File mode // if (options) { if (options->useFileMode()) { argumentsList << "-f"; argumentsList << options->fileMode(); } } else { if (Smb4KMountSettings::useFileMode()) { argumentsList << "-f"; argumentsList << Smb4KMountSettings::fileMode(); } } // // Directory mode // if (options) { if (options->useDirectoryMode()) { argumentsList << "-d"; argumentsList << options->directoryMode(); } } else { if (Smb4KMountSettings::useDirectoryMode()) { argumentsList << "-d"; argumentsList << Smb4KMountSettings::directoryMode(); } } // // User name (login) // if (!share->login().isEmpty()) { argumentsList << "-U"; argumentsList << share->login(); } else { argumentsList << "-N"; } // // Insert the mount options into the map // map.insert("mh_options", argumentsList); // // Insert the mountpoint into the map // map.insert("mh_mountpoint", share->canonicalPath()); // // Insert information about the share and its URL into the map // if (!share->isHomesShare()) { map.insert("mh_url", share->url()); } else { map.insert("mh_url", share->homeUrl()); map.insert("mh_homes_url", share->url()); } map.insert("mh_workgroup", share->workgroupName()); map.insert("mh_ip", share->hostIpAddress()); return true; } #else // // Dummy // bool Smb4KMounter::fillMountActionArgs(const SharePtr &, QVariantMap&) { qWarning() << "Smb4KMounter::fillMountActionArgs() is not implemented!"; qWarning() << "Mounting under this operating system is not supported..."; return false; } #endif #if defined(Q_OS_LINUX) // // Linux arguments // bool Smb4KMounter::fillUnmountActionArgs(const SharePtr &share, bool force, bool silent, QVariantMap &map) { // // The umount program // const QString umount = findUmountExecutable(); if (umount.isEmpty() && !silent) { Smb4KNotification::commandNotFound("umount"); return false; } // // The options // QStringList options; if (force) { options << "-l"; // lazy unmount } // // Insert data into the map // map.insert("mh_command", umount); map.insert("mh_url", share->url()); if (Smb4KHardwareInterface::self()->isOnline()) { map.insert("mh_mountpoint", share->canonicalPath()); } else { map.insert("mh_mountpoint", share->path()); } map.insert("mh_options", options); return true; } #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) // // FreeBSD and NetBSD arguments // bool Smb4KMounter::fillUnmountActionArgs(const SharePtr &share, bool force, bool silent, QVariantMap &map) { // // The umount program // const QString umount = findUmountExecutable(); if (umount.isEmpty() && !silent) { Smb4KNotification::commandNotFound("umount"); return false; } // // The options // QStringList options; if (force) { options << "-f"; } // // Insert data into the map // map.insert("mh_command", umount); map.insert("mh_url", share->url()); if (Smb4KHardwareInterface::self()->isOnline()) { map.insert("mh_mountpoint", share->canonicalPath()); } else { map.insert("mh_mountpoint", share->path()); } map.insert("mh_options", options); return true; } #else // // Dummy // bool Smb4KMounter::fillUnmountActionArgs(const SharePtr &, bool, bool, QVariantMap &) { qWarning() << "Smb4KMounter::fillUnmountActionArgs() is not implemented!"; qWarning() << "Unmounting under this operating system is not supported..."; return false; } #endif void Smb4KMounter::check(const SharePtr &share) { // Get the info about the usage, etc. KDiskFreeSpaceInfo spaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(share->path()); if (spaceInfo.isValid()) { // Accessibility share->setInaccessible(false); // Size information share->setFreeDiskSpace(spaceInfo.available()); share->setTotalDiskSpace(spaceInfo.size()); share->setUsedDiskSpace(spaceInfo.used()); // Get the owner an group, if possible. QFileInfo fileInfo(share->path()); fileInfo.setCaching(false); if (fileInfo.exists()) { share->setUser(KUser(static_cast(fileInfo.ownerId()))); share->setGroup(KUserGroup(static_cast(fileInfo.groupId()))); share->setInaccessible(!(fileInfo.isDir() && fileInfo.isExecutable())); } else { share->setInaccessible(true); share->setFreeDiskSpace(0); share->setTotalDiskSpace(0); share->setUsedDiskSpace(0); share->setUser(KUser(KUser::UseRealUserID)); share->setGroup(KUserGroup(KUser::UseRealUserID)); } } else { share->setInaccessible(true); share->setFreeDiskSpace(0); share->setTotalDiskSpace(0); share->setUsedDiskSpace(0); share->setUser(KUser(KUser::UseRealUserID)); share->setGroup(KUserGroup(KUser::UseRealUserID)); } } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KMounter::slotStartJobs() { // // Disconnect from Smb4KHardwareInterface. // disconnect(Smb4KHardwareInterface::self(), SIGNAL(networkConfigUpdated()), this, SLOT(slotStartJobs())); // // Start the import of shares // if (Smb4KHardwareInterface::self()->isOnline()) { // // Import the mounted shares // if (!d->firstImportDone) { import(true); } // // Start the timer // if (d->timerId == -1) { d->timerId = startTimer(TIMEOUT); } } } void Smb4KMounter::slotAboutToQuit() { // // Abort any actions // abort(); // // Check if the user wants to remount shares and save the // shares for remount if so. // if (Smb4KMountSettings::remountShares()) { saveSharesForRemount(); } // // Unmount the shares if the user chose to do so. // if (Smb4KMountSettings::unmountSharesOnExit()) { unmountAllShares(true); } // // Clean up the mount prefix. // KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::BasicInfoNeeded|KMountPoint::NeedMountOptions); QDir dir; dir.cd(Smb4KMountSettings::mountPrefix().path()); QStringList hostDirs = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::NoSort); QStringList mountpoints; for (const QString &hostDir : hostDirs) { dir.cd(hostDir); QStringList shareDirs = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::NoSort); for (const QString &shareDir : shareDirs) { dir.cd(shareDir); mountpoints << dir.absolutePath(); dir.cdUp(); } dir.cdUp(); } // Remove those mountpoints where a share is actually mounted. for (const QExplicitlySharedDataPointer &mountPoint : mountPoints) { mountpoints.removeOne(mountPoint->mountPoint()); } // Remove the empty mountpoints. for (const QString &mp : mountpoints) { dir.cd(mp); dir.rmdir(dir.canonicalPath()); if (dir.cdUp()) { dir.rmdir(dir.canonicalPath()); } } } void Smb4KMounter::slotOnlineStateChanged(bool online) { if (online) { // Remount shares after the network became available (again) // If the computer awakes from a sleep state, there might still be // an unmount job in the queue. So, wait until all jobs have been // performed before starting to remount the shares. while (isRunning()) { QTest::qWait(TIMEOUT); } triggerRemounts(true); } else { // Abort all running mount jobs abort(); // Mark all mounted shares as inaccessible for (const SharePtr &share : mountedSharesList()) { share->setInaccessible(true); } // Save the shares for automatic remounting saveSharesForRemount(); // Unmount all shares unmountAllShares(true); } } void Smb4KMounter::slotStatResult(KJob *job) { Q_ASSERT(job); // // Stat job // KIO::StatJob *statJob = static_cast(job); // // Get the mountpoint // QString mountpoint = statJob->url().toDisplayString(QUrl::PreferLocalFile); // // Find the imported share // SharePtr importedShare; for (int i = 0; i < d->importedShares.size(); ++i) { if (QString::compare(d->importedShares.at(i)->path(), mountpoint) == 0) { importedShare = d->importedShares.takeAt(i); break; } else { continue; } } // // If the share should have vanished in the meantime, return here. // if (!importedShare) { return; } // // Add the size, user and group information // if (statJob->error() == 0 /* no error */) { check(importedShare); } else { importedShare->setInaccessible(true); importedShare->setFreeDiskSpace(0); importedShare->setTotalDiskSpace(0); importedShare->setUsedDiskSpace(0); importedShare->setUser(KUser(KUser::UseRealUserID)); importedShare->setGroup(KUserGroup(KUser::UseRealUserID)); } // // Is this a mount done by the user or by someone else? // Make an educated guess... // if ((importedShare->user().userId() == KUser(KUser::UseRealUserID).userId() && importedShare->group().groupId() == KUserGroup(KUser::UseRealUserID).groupId()) || importedShare->path().startsWith(Smb4KMountSettings::mountPrefix().path()) || importedShare->path().startsWith(QDir::homePath()) || importedShare->canonicalPath().startsWith(QDir(Smb4KMountSettings::mountPrefix().path()).canonicalPath()) || importedShare->canonicalPath().startsWith(QDir::home().canonicalPath())) { // Same UID and GID importedShare->setForeign(false); } else { importedShare->setForeign(true); } // // Search for a previously added mounted share and try to update it. If this fails, // add the share to the global list. // if (!importedShare->isForeign() || Smb4KMountSettings::detectAllShares()) { if (updateMountedShare(importedShare)) { SharePtr updatedShare = findShareByPath(importedShare->path()); if (updatedShare) { emit updated(updatedShare); } importedShare.clear(); } else { if (addMountedShare(importedShare)) { // Remove the share from the list of shares that are to be remounted QMutableListIterator s(d->remounts); while (s.hasNext()) { SharePtr remount = s.next(); if (!importedShare->isForeign() && QString::compare(remount->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), importedShare->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0) { Smb4KCustomOptionsManager::self()->removeRemount(remount); s.remove(); break; } else { continue; } } // Tell the program and the user that the share was mounted. Also, reset the // counter of newly mounted shares, if necessary. d->newlyMounted += 1; emit mounted(importedShare); if (d->importedShares.isEmpty() && !d->mountShares && !d->unmountShares) { if (d->firstImportDone) { if (d->newlyMounted == 1) { Smb4KNotification::shareMounted(importedShare); } else { Smb4KNotification::sharesMounted(d->newlyMounted); } } d->newlyMounted = 0; } emit mountedSharesListChanged(); } else { importedShare.clear(); } } } else { importedShare.clear(); } if (!d->firstImportDone && d->importedShares.isEmpty()) { d->firstImportDone = true; } } void Smb4KMounter::slotAboutToChangeProfile() { // // Save those shares that are to be remounted // if (Smb4KMountSettings::remountShares()) { saveSharesForRemount(); } } void Smb4KMounter::slotActiveProfileChanged(const QString &newProfile) { if (d->activeProfile != newProfile) { // Stop the timer. killTimer(d->timerId); abort(); // Clear all remounts. while (!d->remounts.isEmpty()) { d->remounts.takeFirst().clear(); } // Clear all retries. while (!d->retries.isEmpty()) { d->retries.takeFirst().clear(); } // Unmount all shares unmountAllShares(true); // Reset some variables. d->remountTimeout = 0; d->remountAttempts = 0; d->firstImportDone = false; d->activeProfile = newProfile; // Restart the timer d->timerId = startTimer(TIMEOUT); } } void Smb4KMounter::slotProfileMigrated(const QString& from, const QString& to) { if (QString::compare(from, d->activeProfile, Qt::CaseSensitive) == 0) { d->activeProfile = to; } } void Smb4KMounter::slotTriggerImport() { // Wait until there are no jobs anymore while(isRunning()) { QTest::qWait(TIMEOUT); } // Initialize an import import(true); } void Smb4KMounter::slotConfigChanged() { if (d->detectAllShares != Smb4KMountSettings::detectAllShares()) { slotTriggerImport(); d->detectAllShares = Smb4KMountSettings::detectAllShares(); } } diff --git a/core/smb4kmounter_p.cpp b/core/smb4kmounter_p.cpp index e7d1355..7489eef 100644 --- a/core/smb4kmounter_p.cpp +++ b/core/smb4kmounter_p.cpp @@ -1,282 +1,273 @@ /*************************************************************************** This file contains private helper classes for the Smb4KMounter class. ------------------- begin : Do Jul 19 2007 copyright : (C) 2007-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4kmounter_p.h" #include "smb4ksettings.h" #include "smb4knotification.h" #include "smb4khomesshareshandler.h" #include "smb4kglobal.h" #include "smb4kcustomoptions.h" #include "smb4kcustomoptionsmanager.h" // Qt includes #include #include #include #include #include #include // KDE includes #define TRANSLATION_DOMAIN "smb4k-core" #include #include #include using namespace Smb4KGlobal; Smb4KMountDialog::Smb4KMountDialog(const SharePtr &share, QWidget *parent) : QDialog(parent), m_share(share), m_valid(true) { setWindowTitle(i18n("Mount Share")); setupView(); setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); KConfigGroup group(Smb4KSettings::self()->config(), "MountDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); m_share_input->completionObject()->setItems(group.readEntry("ShareNameCompletion", QStringList())); m_ip_input->completionObject()->setItems(group.readEntry("IPAddressCompletion", QStringList())); m_workgroup_input->completionObject()->setItems(group.readEntry("WorkgroupCompletion", QStringList())); } Smb4KMountDialog::~Smb4KMountDialog() { } void Smb4KMountDialog::setupView() { QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(5); QWidget *description = new QWidget(this); QHBoxLayout *desc_layout = new QHBoxLayout(description); desc_layout->setSpacing(5); QLabel *pixmap = new QLabel(description); QPixmap mount_pix = KDE::icon("view-form", QStringList("emblem-mounted")).pixmap(KIconLoader::SizeHuge); pixmap->setPixmap(mount_pix); pixmap->setAlignment(Qt::AlignBottom); QLabel *label = new QLabel(i18n("Enter the location and optionally the IP address and workgroup to mount a share."), description); label->setWordWrap(true); label->setAlignment(Qt::AlignBottom); desc_layout->addWidget(pixmap, 0); desc_layout->addWidget(label, Qt::AlignBottom); QWidget *edit_widget = new QWidget(this); QGridLayout *edit_layout = new QGridLayout(edit_widget); layout->setSpacing(5); QLabel *shareLabel = new QLabel(i18n("Location:"), edit_widget); m_share_input = new KLineEdit(edit_widget); m_share_input->setWhatsThis(i18n("The location of the share is provided by the Uniform Resource Locator (URL). It generally has the following syntax: " "[smb:]//[USER:PASSWORD@]HOST:PORT/SHARE. The username, password and port are optional. You should omit to enter the password here, because it is shown in cleartext.")); // m_share_input->setToolTip(i18n("The URL of the share")); m_share_input->setCompletionMode(KCompletion::CompletionPopupAuto); m_share_input->setClearButtonEnabled(true); m_share_input->setMinimumWidth(200); m_share_input->setFocus(); QLabel *addressLabel = new QLabel(i18n("IP Address:"), edit_widget); m_ip_input = new KLineEdit(edit_widget); m_ip_input->setWhatsThis(i18n("The Internet Protocol (IP) address identifies the " "host in the network and indicates where it is. It has two valid formats, the one " "known as IP version 4 (e.g. 192.168.2.11) and the version 6 format " "(e.g. 2001:0db8:85a3:08d3:1319:8a2e:0370:7334).")); // m_ip_input->setToolTip(i18n("The IP address of the host where the share is located")); m_ip_input->setCompletionMode(KCompletion::CompletionPopupAuto); m_ip_input->setClearButtonEnabled(true); m_ip_input->setMinimumWidth(200); QLabel *workgroupLabel = new QLabel(i18n("Workgroup:"), edit_widget); m_workgroup_input = new KLineEdit(edit_widget); m_workgroup_input->setWhatsThis(i18n("The workgroup or domain identifies the " "peer-to-peer computer network the host is located in.")); // m_workgroup_input->setToolTip(i18n("The workgroup where the host is located")); m_workgroup_input->setCompletionMode(KCompletion::CompletionPopupAuto); m_workgroup_input->setClearButtonEnabled(true); m_workgroup_input->setMinimumWidth(200); edit_layout->addWidget(shareLabel, 0, 0, 0); edit_layout->addWidget(m_share_input, 0, 1, 0); edit_layout->addWidget(addressLabel, 1, 0, 0); edit_layout->addWidget(m_ip_input, 1, 1, 0); edit_layout->addWidget(workgroupLabel, 2, 0, 0); edit_layout->addWidget(m_workgroup_input, 2, 1, 0); m_bookmark = new QCheckBox(i18n("Add this share to the bookmarks"), this); m_bookmark->setWhatsThis(i18n("If you tick this checkbox, the share will be bookmarked " "and you can access it e.g. through the \"Bookmarks\" menu entry in the main window.")); // m_bookmark->setToolTip(i18n("Add this share to the bookmarks")); QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this); m_ok_button = buttonBox->addButton(QDialogButtonBox::Ok); m_cancel_button = buttonBox->addButton(QDialogButtonBox::Cancel); m_ok_button->setShortcut(Qt::CTRL|Qt::Key_Return); m_cancel_button->setShortcut(Qt::Key_Escape); layout->addWidget(description, Qt::AlignBottom); layout->addWidget(edit_widget, 0); layout->addWidget(m_bookmark, 0); layout->addWidget(buttonBox, 0); slotChangeInputValue(m_share_input->text()); + // // Connections - connect(m_share_input, SIGNAL(textChanged(QString)) , - this, SLOT(slotChangeInputValue(QString))); - - connect(m_share_input, SIGNAL(editingFinished()), - this, SLOT(slotShareNameEntered())); - - connect(m_ip_input, SIGNAL(editingFinished()), - this, SLOT(slotIPEntered())); - - connect(m_workgroup_input, SIGNAL(editingFinished()), - this, SLOT(slotWorkgroupEntered())); - - connect(m_ok_button, SIGNAL(clicked()), - this, SLOT(slotOkClicked())); - - connect(m_cancel_button, SIGNAL(clicked()), - this, SLOT(slotCancelClicked())); + // + connect(m_share_input, SIGNAL(textChanged(QString)), this, SLOT(slotChangeInputValue(QString))); + connect(m_share_input, SIGNAL(editingFinished()), this, SLOT(slotShareNameEntered())); + connect(m_ip_input, SIGNAL(editingFinished()), this, SLOT(slotIPEntered())); + connect(m_workgroup_input, SIGNAL(editingFinished()), this, SLOT(slotWorkgroupEntered())); + connect(m_ok_button, SIGNAL(clicked()), this, SLOT(slotOkClicked())); + connect(m_cancel_button, SIGNAL(clicked()), this, SLOT(slotCancelClicked())); } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KMountDialog::slotChangeInputValue(const QString& _test) { m_ok_button->setEnabled(!_test.isEmpty()); } void Smb4KMountDialog::slotOkClicked() { if (!m_share_input->text().trimmed().isEmpty()) { // // Get the URL // QString userInput = m_share_input->text().trimmed(); // // Take care of a Windows-like UNC addresses // if (userInput.startsWith(QLatin1String("\\"))) { userInput.replace("\\", "/"); } // // Set the URL and adjust the scheme // QUrl smbUrl = QUrl::fromUserInput(userInput); smbUrl.setScheme("smb"); // // Set the URL of the share // if (smbUrl.isValid() && !smbUrl.host().isEmpty() && !smbUrl.path().isEmpty() && !smbUrl.path().endsWith(QLatin1String("/"))) { m_share->setUrl(smbUrl); m_share->setWorkgroupName(m_workgroup_input->text().trimmed()); m_share->setHostIpAddress(m_ip_input->text().trimmed()); } else { Smb4KNotification::invalidURLPassed(); m_valid = false; } } KConfigGroup group(Smb4KSettings::self()->config(), "MountDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); group.writeEntry("ShareNameCompletion", m_share_input->completionObject()->items()); group.writeEntry("IPAddressCompletion", m_ip_input->completionObject()->items()); group.writeEntry("WorkgroupCompletion", m_workgroup_input->completionObject()->items()); accept(); } void Smb4KMountDialog::slotCancelClicked() { Smb4KMounter::self()->abort(); reject(); } void Smb4KMountDialog::slotShareNameEntered() { KCompletion *completion = m_share_input->completionObject(); QUrl url(m_share_input->userText()); url.setScheme("smb"); if (url.isValid() && !url.isEmpty()) { completion->addItem(m_share_input->userText()); } } void Smb4KMountDialog::slotIPEntered() { KCompletion *completion = m_ip_input->completionObject(); if (!m_ip_input->userText().isEmpty()) { completion->addItem(m_ip_input->userText()); } } void Smb4KMountDialog::slotWorkgroupEntered() { KCompletion *completion = m_workgroup_input->completionObject(); if (!m_workgroup_input->userText().isEmpty()) { completion->addItem(m_workgroup_input->userText()); } } diff --git a/smb4k/smb4knetworkbrowser.cpp b/smb4k/smb4knetworkbrowser.cpp index a78719f..2f49600 100644 --- a/smb4k/smb4knetworkbrowser.cpp +++ b/smb4k/smb4knetworkbrowser.cpp @@ -1,386 +1,381 @@ /*************************************************************************** smb4knetworkbrowser - The network browser widget of Smb4K. ------------------- begin : Mo Jan 8 2007 copyright : (C) 2007-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4knetworkbrowser.h" #include "smb4knetworkbrowseritem.h" #include "smb4ktooltip.h" #include "core/smb4ksettings.h" #include "core/smb4kglobal.h" #include "core/smb4kshare.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include using namespace Smb4KGlobal; Smb4KNetworkBrowser::Smb4KNetworkBrowser(QWidget *parent) : QTreeWidget(parent) { setRootIsDecorated(true); setAllColumnsShowFocus(false); setMouseTracking(true); setSelectionMode(ExtendedSelection); setContextMenuPolicy(Qt::CustomContextMenu); m_tooltip_item = 0; m_mouse_inside = false; QStringList header_labels; header_labels.append(i18n("Network")); header_labels.append(i18n("Type")); header_labels.append(i18n("IP Address")); header_labels.append(i18n("Comment")); setHeaderLabels(header_labels); header()->setSectionResizeMode(QHeaderView::ResizeToContents); - // Add some connections: - connect(this, SIGNAL(itemActivated(QTreeWidgetItem*,int)), - this, SLOT(slotItemActivated(QTreeWidgetItem*,int))); - - connect(this, SIGNAL(itemEntered(QTreeWidgetItem*,int)), - this, SLOT(slotItemEntered(QTreeWidgetItem*,int))); - - connect(this, SIGNAL(viewportEntered()), - this, SLOT(slotViewportEntered())); - - connect(this, SIGNAL(itemSelectionChanged()), - this, SLOT(slotItemSelectionChanged())); + // + // Connections + // + connect(this, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(slotItemActivated(QTreeWidgetItem*,int))); + connect(this, SIGNAL(itemEntered(QTreeWidgetItem*,int)), this, SLOT(slotItemEntered(QTreeWidgetItem*,int))); + connect(this, SIGNAL(viewportEntered()), this, SLOT(slotViewportEntered())); + connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged())); } Smb4KNetworkBrowser::~Smb4KNetworkBrowser() { } bool Smb4KNetworkBrowser::event(QEvent *e) { switch (e->type()) { case QEvent::ToolTip: { // Intercept the tool tip event and show our own tool tip. QPoint pos = viewport()->mapFromGlobal(cursor().pos()); Smb4KNetworkBrowserItem *item = static_cast(itemAt(pos)); if (item) { if (Smb4KSettings::showNetworkItemToolTip()) { int ind = 0; switch (item->type()) { case Host: { ind = 2; break; } case Share: { ind = 3; break; } default: { ind = 1; break; } } // Check that the tooltip is not over the root decoration. // If it is, hide it. if (pos.x() <= ind * indentation()) { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } else { m_tooltip_item = item; emit aboutToShowToolTip(m_tooltip_item); m_tooltip_item->tooltip()->show(cursor().pos()); } } else { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } } else { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } break; } default: { break; } } return QTreeWidget::event(e); } void Smb4KNetworkBrowser::mouseMoveEvent(QMouseEvent *e) { // Find the item over which the user moved the mouse: Smb4KNetworkBrowserItem *item = static_cast(itemAt(e->pos())); if (item) { emit itemEntered(item, columnAt(e->pos().x())); // Hide tool tip if the items diverge. if (m_tooltip_item && m_tooltip_item->tooltip()->networkItem() != item->networkItem()) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } else { // Hide the tool tip if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } QTreeWidget::mouseMoveEvent(e); } void Smb4KNetworkBrowser::leaveEvent(QEvent *e) { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } m_mouse_inside = false; QTreeWidget::leaveEvent(e); } void Smb4KNetworkBrowser::enterEvent(QEvent *e) { m_mouse_inside = true; QTreeWidget::enterEvent(e); } void Smb4KNetworkBrowser::mousePressEvent(QMouseEvent *e) { // Hide the current tool tip so that it is not in the way. if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } // Get the item that is under the mouse. If there is no // item, unselect the current item. QTreeWidgetItem *item = itemAt(e->pos()); if (!item && currentItem()) { currentItem()->setSelected(false); setCurrentItem(0); emit itemPressed(currentItem(), -1); } QTreeWidget::mousePressEvent(e); } void Smb4KNetworkBrowser::focusOutEvent(QFocusEvent *e) { QTreeWidget::focusOutEvent(e); } void Smb4KNetworkBrowser::wheelEvent(QWheelEvent *e) { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } QTreeWidget::wheelEvent(e); } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KNetworkBrowser::slotItemEntered(QTreeWidgetItem *item, int /*column*/) { Smb4KNetworkBrowserItem *browser_item = static_cast(item); if (m_tooltip_item && m_tooltip_item != browser_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } void Smb4KNetworkBrowser::slotViewportEntered() { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } } void Smb4KNetworkBrowser::slotItemActivated(QTreeWidgetItem *item, int /*column*/) { if (m_tooltip_item) { emit aboutToHideToolTip(m_tooltip_item); m_tooltip_item->tooltip()->hide(); m_tooltip_item = 0; } // Only do something if there are no keyboard modifiers pressed // and there is only one item selected. if (QApplication::keyboardModifiers() == Qt::NoModifier && selectedItems().size() == 1) { if (item) { switch (item->type()) { case Workgroup: case Host: { if (!item->isExpanded()) { expandItem(item); } else { collapseItem(item); } break; } default: { break; } } } } } void Smb4KNetworkBrowser::slotItemSelectionChanged() { if (selectedItems().size() > 1) { // If multiple items are selected, only allow shares // to stay selected. for (int i = 0; i < selectedItems().size(); ++i) { Smb4KNetworkBrowserItem *item = static_cast(selectedItems()[i]); if (item) { switch (item->networkItem()->type()) { case Workgroup: case Host: { item->setSelected(false); break; } case Share: { if (item->shareItem()->isPrinter()) { item->setSelected(false); } break; } default: { break; } } } } } } diff --git a/smb4k/smb4knetworkbrowserdockwidget.cpp b/smb4k/smb4knetworkbrowserdockwidget.cpp index a54b619..32801e6 100644 --- a/smb4k/smb4knetworkbrowserdockwidget.cpp +++ b/smb4k/smb4knetworkbrowserdockwidget.cpp @@ -1,1449 +1,1449 @@ /*************************************************************************** The network neighborhood browser dock widget ------------------- begin : Sat Apr 28 2018 copyright : (C) 2018-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4knetworkbrowserdockwidget.h" #include "smb4knetworkbrowseritem.h" #include "core/smb4kmounter.h" #include "core/smb4kworkgroup.h" #include "core/smb4khost.h" #include "core/smb4kshare.h" #include "core/smb4ksettings.h" #include "core/smb4kbookmarkhandler.h" #include "core/smb4kwalletmanager.h" #include "core/smb4kcustomoptionsmanager.h" #include "core/smb4kclient.h" // Qt includes #include #include #include #include #include // KDE includes #include #include #include #include using namespace Smb4KGlobal; Smb4KNetworkBrowserDockWidget::Smb4KNetworkBrowserDockWidget(const QString& title, QWidget* parent) : QDockWidget(title, parent) { // // The network browser widget // QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainWidgetLayout = new QVBoxLayout(mainWidget); mainWidgetLayout->setMargin(0); mainWidgetLayout->setSpacing(5); m_networkBrowser = new Smb4KNetworkBrowser(mainWidget); m_searchToolBar = new Smb4KNetworkSearchToolBar(mainWidget); m_searchToolBar->setVisible(false); mainWidgetLayout->addWidget(m_networkBrowser); mainWidgetLayout->addWidget(m_searchToolBar); setWidget(mainWidget); // // The action collection // m_actionCollection = new KActionCollection(this); // // The context menu // m_contextMenu = new KActionMenu(this); // // Search underway? // m_searchRunning = false; // // Set up the actions // setupActions(); // // Load the settings // loadSettings(); // // Connections // connect(m_networkBrowser, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenuRequested(QPoint))); connect(m_networkBrowser, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(slotItemActivated(QTreeWidgetItem*,int))); connect(m_networkBrowser, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged())); connect(m_searchToolBar, SIGNAL(close()), this, SLOT(slotHideSearchToolBar())); connect(m_searchToolBar, SIGNAL(search(QString)), this, SLOT(slotPerformSearch(QString))); connect(m_searchToolBar, SIGNAL(abort()), this, SLOT(slotStopSearch())); connect(m_searchToolBar, SIGNAL(jumpToResult(QString)), this, SLOT(slotJumpToResult(QString))); connect(m_searchToolBar, SIGNAL(clearSearchResults()), this, SLOT(slotClearSearchResults())); - connect(Smb4KClient::self(), SIGNAL(aboutToStart(NetworkItemPtr, int)), this, SLOT(slotClientAboutToStart(NetworkItemPtr, int))); - connect(Smb4KClient::self(), SIGNAL(finished(NetworkItemPtr, int)), this, SLOT(slotClientFinished(NetworkItemPtr,int))); + connect(Smb4KClient::self(), SIGNAL(aboutToStart(NetworkItemPtr,int)), this, SLOT(slotClientAboutToStart(NetworkItemPtr,int))); + connect(Smb4KClient::self(), SIGNAL(finished(NetworkItemPtr,int)), this, SLOT(slotClientFinished(NetworkItemPtr,int))); connect(Smb4KClient::self(), SIGNAL(workgroups()), this, SLOT(slotWorkgroups())); connect(Smb4KClient::self(), SIGNAL(hosts(WorkgroupPtr)), this, SLOT(slotWorkgroupMembers(WorkgroupPtr))); connect(Smb4KClient::self(), SIGNAL(shares(HostPtr)), this, SLOT(slotShares(HostPtr))); connect(Smb4KClient::self(), SIGNAL(searchResults(QList)), this, SLOT(slotSearchResults(QList))); connect(Smb4KMounter::self(), SIGNAL(mounted(SharePtr)), this, SLOT(slotShareMounted(SharePtr))); connect(Smb4KMounter::self(), SIGNAL(unmounted(SharePtr)), this, SLOT(slotShareUnmounted(SharePtr))); connect(Smb4KMounter::self(), SIGNAL(aboutToStart(int)), this, SLOT(slotMounterAboutToStart(int))); connect(Smb4KMounter::self(), SIGNAL(finished(int)), this, SLOT(slotMounterFinished(int))); connect(KIconLoader::global(), SIGNAL(iconChanged(int)), this, SLOT(slotIconSizeChanged(int))); } Smb4KNetworkBrowserDockWidget::~Smb4KNetworkBrowserDockWidget() { } void Smb4KNetworkBrowserDockWidget::setupActions() { // // Rescan and abort dual action // KDualAction *rescanAbortAction = new KDualAction(this); rescanAbortAction->setInactiveIcon(KDE::icon("view-refresh")); rescanAbortAction->setInactiveText(i18n("Scan Netwo&rk")); rescanAbortAction->setActiveIcon(KDE::icon("process-stop")); rescanAbortAction->setActiveText(i18n("&Abort")); rescanAbortAction->setAutoToggle(false); rescanAbortAction->setEnabled(true); connect(rescanAbortAction, SIGNAL(triggered(bool)), this, SLOT(slotRescanAbortActionTriggered(bool))); m_actionCollection->addAction("rescan_abort_action", rescanAbortAction); m_actionCollection->setDefaultShortcut(rescanAbortAction, QKeySequence::Refresh); // // Search action // QAction *searchAction = new QAction(KDE::icon("search"), i18n("&Search"), this); connect(searchAction, SIGNAL(triggered(bool)), this, SLOT(slotShowSearchToolBar())); m_actionCollection->addAction("search_action", searchAction); m_actionCollection->setDefaultShortcut(searchAction, QKeySequence::Find); // // Separator // QAction *separator1 = new QAction(this); separator1->setSeparator(true); m_actionCollection->addAction("network_separator1", separator1); // // Bookmark action // QAction *bookmarkAction = new QAction(KDE::icon("bookmark-new"), i18n("Add &Bookmark"), this); bookmarkAction->setEnabled(false); connect(bookmarkAction, SIGNAL(triggered(bool)), this, SLOT(slotAddBookmark(bool))); m_actionCollection->addAction("bookmark_action", bookmarkAction); m_actionCollection->setDefaultShortcut(bookmarkAction, QKeySequence(Qt::CTRL+Qt::Key_B)); // // Mount dialog action // QAction *manualAction = new QAction(KDE::icon("view-form", QStringList("emblem-mounted")), i18n("&Open Mount Dialog"), this); manualAction->setEnabled(true); connect(manualAction, SIGNAL(triggered(bool)), this, SLOT(slotMountManually(bool))); m_actionCollection->addAction("mount_manually_action", manualAction); m_actionCollection->setDefaultShortcut(manualAction, QKeySequence(Qt::CTRL+Qt::Key_O)); // // Separator // QAction *separator2 = new QAction(this); separator2->setSeparator(true); m_actionCollection->addAction("network_separator2", separator2); // // Authentication action // QAction *authAction = new QAction(KDE::icon("dialog-password"), i18n("Au&thentication"), this); authAction->setEnabled(false); connect(authAction, SIGNAL(triggered(bool)), this, SLOT(slotAuthentication(bool))); m_actionCollection->addAction("authentication_action", authAction); m_actionCollection->setDefaultShortcut(authAction, QKeySequence(Qt::CTRL+Qt::Key_T)); // // Custom options action // QAction *customAction = new QAction(KDE::icon("preferences-system-network"), i18n("&Custom Options"), this); customAction->setEnabled(false); connect(customAction, SIGNAL(triggered(bool)), this, SLOT(slotCustomOptions(bool))); m_actionCollection->addAction("custom_action", customAction); m_actionCollection->setDefaultShortcut(customAction, QKeySequence(Qt::CTRL+Qt::Key_C)); // // Preview action // QAction *previewAction = new QAction(KDE::icon("view-list-icons"), i18n("Pre&view"), this); previewAction->setEnabled(false); connect(previewAction, SIGNAL(triggered(bool)), this, SLOT(slotPreview(bool))); m_actionCollection->addAction("preview_action", previewAction); m_actionCollection->setDefaultShortcut(previewAction, QKeySequence(Qt::CTRL+Qt::Key_V)); // // Print action // QAction *printAction = new QAction(KDE::icon("printer"), i18n("&Print File"), this); printAction->setEnabled(false); connect(printAction, SIGNAL(triggered(bool)), this, SLOT(slotPrint(bool))); m_actionCollection->addAction("print_action", printAction); m_actionCollection->setDefaultShortcut(printAction, QKeySequence(Qt::CTRL+Qt::Key_P)); // // Mount/unmount action // KDualAction *mountAction = new KDualAction(this); KGuiItem mountItem(i18n("&Mount"), KDE::icon("media-mount")); KGuiItem unmountItem(i18n("&Unmount"), KDE::icon("media-eject")); mountAction->setActiveGuiItem(mountItem); mountAction->setInactiveGuiItem(unmountItem); mountAction->setActive(true); mountAction->setAutoToggle(false); mountAction->setEnabled(false); connect(mountAction, SIGNAL(triggered(bool)), this, SLOT(slotMountActionTriggered(bool))); connect(mountAction, SIGNAL(activeChanged(bool)), this, SLOT(slotMountActionChanged(bool))); m_actionCollection->addAction("mount_action", mountAction); m_actionCollection->setDefaultShortcut(mountAction, QKeySequence(Qt::CTRL+Qt::Key_M)); // // Plug the actions into the context menu // for (QAction *a : m_actionCollection->actions()) { m_contextMenu->addAction(a); } } void Smb4KNetworkBrowserDockWidget::loadSettings() { // // Load icon size // int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); m_networkBrowser->setIconSize(QSize(iconSize, iconSize)); // // Show/hide columns // m_networkBrowser->setColumnHidden(Smb4KNetworkBrowser::IP, !Smb4KSettings::showIPAddress()); m_networkBrowser->setColumnHidden(Smb4KNetworkBrowser::Type, !Smb4KSettings::showType()); m_networkBrowser->setColumnHidden(Smb4KNetworkBrowser::Comment, !Smb4KSettings::showComment()); // // Load and apply the positions of the columns // KConfigGroup configGroup(Smb4KSettings::self()->config(), "NetworkBrowserPart"); QMap map; map.insert(configGroup.readEntry("ColumnPositionNetwork", (int)Smb4KNetworkBrowser::Network), Smb4KNetworkBrowser::Network); map.insert(configGroup.readEntry("ColumnPositionType", (int)Smb4KNetworkBrowser::Type), Smb4KNetworkBrowser::Type); map.insert(configGroup.readEntry("ColumnPositionIP", (int)Smb4KNetworkBrowser::IP), Smb4KNetworkBrowser::IP); map.insert(configGroup.readEntry("ColumnPositionComment", (int)Smb4KNetworkBrowser::Comment), Smb4KNetworkBrowser::Comment); QMap::const_iterator it = map.constBegin(); while (it != map.constEnd()) { if (it.key() != m_networkBrowser->header()->visualIndex(it.value())) { m_networkBrowser->header()->moveSection(m_networkBrowser->header()->visualIndex(it.value()), it.key()); } ++it; } // // Apply the completion strings to the search toolbar // m_searchToolBar->setCompletionStrings(configGroup.readEntry("SearchItemCompletion", QStringList())); // // Does anything has to be changed with the marked shares? // for (const SharePtr &share : mountedSharesList()) { // We do not need to use slotShareUnmounted() here, too, // because slotShareMounted() will take care of everything // we need here. slotShareMounted(share); } } void Smb4KNetworkBrowserDockWidget::saveSettings() { // // Save the position of the columns // KConfigGroup configGroup(Smb4KSettings::self()->config(), "NetworkBrowserPart"); configGroup.writeEntry("ColumnPositionNetwork", m_networkBrowser->header()->visualIndex(Smb4KNetworkBrowser::Network)); configGroup.writeEntry("ColumnPositionType", m_networkBrowser->header()->visualIndex(Smb4KNetworkBrowser::Type)); configGroup.writeEntry("ColumnPositionIP", m_networkBrowser->header()->visualIndex(Smb4KNetworkBrowser::IP)); configGroup.writeEntry("ColumnPositionComment", m_networkBrowser->header()->visualIndex(Smb4KNetworkBrowser::Comment)); // // Save the completion strings // configGroup.writeEntry("SearchItemCompletion", m_searchToolBar->completionStrings()); configGroup.sync(); } KActionCollection *Smb4KNetworkBrowserDockWidget::actionCollection() { return m_actionCollection; } void Smb4KNetworkBrowserDockWidget::slotContextMenuRequested(const QPoint& pos) { m_contextMenu->menu()->popup(m_networkBrowser->viewport()->mapToGlobal(pos)); } void Smb4KNetworkBrowserDockWidget::slotItemActivated(QTreeWidgetItem* item, int /*column*/) { // // Process the activated item // if (QApplication::keyboardModifiers() == Qt::NoModifier && m_networkBrowser->selectedItems().size() == 1) { Smb4KNetworkBrowserItem *browserItem = static_cast(item); if (browserItem) { switch (browserItem->type()) { case Workgroup: { if (browserItem->isExpanded()) { Smb4KClient::self()->lookupDomainMembers(browserItem->workgroupItem()); } break; } case Host: { if (browserItem->isExpanded()) { Smb4KClient::self()->lookupShares(browserItem->hostItem()); } break; } case Share: { if (!browserItem->shareItem()->isPrinter()) { slotMountActionTriggered(false); // boolean is ignored } else { slotPrint(false); // boolean is ignored } break; } default: { break; } } } } } void Smb4KNetworkBrowserDockWidget::slotItemSelectionChanged() { // // Get the selected item // QList items = m_networkBrowser->selectedItems(); // // Enable/disable and/or adjust the actions depending of the number // of selected items and their type // if (items.size() == 1) { Smb4KNetworkBrowserItem *browserItem = static_cast(items.first()); if (browserItem) { switch (browserItem->type()) { case Host: { // // Adjust the actions // qobject_cast(m_actionCollection->action("rescan_abort_action"))->setInactiveText(i18n("Scan Compute&r")); m_actionCollection->action("bookmark_action")->setEnabled(false); m_actionCollection->action("authentication_action")->setEnabled(true); m_actionCollection->action("custom_action")->setEnabled(true); m_actionCollection->action("preview_action")->setEnabled(false); m_actionCollection->action("print_action")->setEnabled(false); static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(false); break; } case Share: { // // Adjust the actions // qobject_cast(m_actionCollection->action("rescan_abort_action"))->setInactiveText(i18n("Scan Compute&r")); m_actionCollection->action("bookmark_action")->setEnabled(!browserItem->shareItem()->isPrinter()); m_actionCollection->action("authentication_action")->setEnabled(true); m_actionCollection->action("custom_action")->setEnabled(!browserItem->shareItem()->isPrinter()); m_actionCollection->action("preview_action")->setEnabled(!browserItem->shareItem()->isPrinter()); m_actionCollection->action("print_action")->setEnabled(browserItem->shareItem()->isPrinter()); if (!browserItem->shareItem()->isPrinter()) { if (!browserItem->shareItem()->isMounted() || (browserItem->shareItem()->isMounted() && browserItem->shareItem()->isForeign())) { static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(true); } else if (browserItem->shareItem()->isMounted() && !browserItem->shareItem()->isForeign()) { static_cast(m_actionCollection->action("mount_action"))->setActive(false); m_actionCollection->action("mount_action")->setEnabled(true); } else { static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(false); } } else { static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(true); } break; } default: { // // Adjust the actions // qobject_cast(m_actionCollection->action("rescan_abort_action"))->setInactiveText(i18n("Scan Wo&rkgroup")); m_actionCollection->action("bookmark_action")->setEnabled(false); m_actionCollection->action("authentication_action")->setEnabled(false); m_actionCollection->action("custom_action")->setEnabled(false); m_actionCollection->action("preview_action")->setEnabled(false); m_actionCollection->action("print_action")->setEnabled(false); static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(false); break; } } } } else if (items.size() > 1) { // // In this case there are only shares selected, because all other items // are automatically deselected in extended selection mode. // // For deciding which function the mount action should have, we use // the number of unmounted shares. If that is identical with the items.size(), // it will mount the items, otherwise it will unmount them. // int unmountedShares = items.size(); for (QTreeWidgetItem *item : items) { Smb4KNetworkBrowserItem *browserItem = static_cast(item); if (browserItem && browserItem->shareItem()->isMounted() && !browserItem->shareItem()->isForeign()) { // // Subtract shares mounted by the user // unmountedShares--; } } // // Adjust the actions // qobject_cast(m_actionCollection->action("rescan_abort_action"))->setInactiveText(i18n("Scan Netwo&rk")); m_actionCollection->action("bookmark_action")->setEnabled(true); m_actionCollection->action("authentication_action")->setEnabled(false); m_actionCollection->action("custom_action")->setEnabled(false); m_actionCollection->action("preview_action")->setEnabled(true); m_actionCollection->action("print_action")->setEnabled(false); static_cast(m_actionCollection->action("mount_action"))->setActive(unmountedShares == items.size()); m_actionCollection->action("mount_action")->setEnabled(true); } else { // // Adjust the actions // qobject_cast(m_actionCollection->action("rescan_abort_action"))->setInactiveText(i18n("Scan Netwo&rk")); m_actionCollection->action("bookmark_action")->setEnabled(false); m_actionCollection->action("authentication_action")->setEnabled(false); m_actionCollection->action("custom_action")->setEnabled(false); m_actionCollection->action("preview_action")->setEnabled(false); m_actionCollection->action("print_action")->setEnabled(false); static_cast(m_actionCollection->action("mount_action"))->setActive(true); m_actionCollection->action("mount_action")->setEnabled(false); } } void Smb4KNetworkBrowserDockWidget::slotClientAboutToStart(const NetworkItemPtr& /*item*/, int process) { // // Get the rescan/abort action // KDualAction *rescanAbortAction = static_cast(m_actionCollection->action("rescan_abort_action")); // // Make adjustments // if (rescanAbortAction) { rescanAbortAction->setActive(true); m_actionCollection->setDefaultShortcut(rescanAbortAction, QKeySequence::Cancel); } // // Set the active status of the search tool bar // if (process == NetworkSearch) { m_searchToolBar->setActiveState(true); } } void Smb4KNetworkBrowserDockWidget::slotClientFinished(const NetworkItemPtr& /*item*/, int process) { // // Get the rescan/abort action // KDualAction *rescanAbortAction = static_cast(m_actionCollection->action("rescan_abort_action")); // // Make adjustments // if (rescanAbortAction) { rescanAbortAction->setActive(false); m_actionCollection->setDefaultShortcut(rescanAbortAction, QKeySequence::Refresh); } // // Set the active status of the search tool bar // if (process == NetworkSearch) { m_searchToolBar->setActiveState(false); } } void Smb4KNetworkBrowserDockWidget::slotWorkgroups() { // // Process the global workgroup list // if (!workgroupsList().isEmpty()) { // // Remove obsolete workgroups and update existing ones // QTreeWidgetItemIterator itemIt(m_networkBrowser, QTreeWidgetItemIterator::All); while (*itemIt) { Smb4KNetworkBrowserItem *networkItem = static_cast(*itemIt); if (networkItem->type() == Workgroup) { WorkgroupPtr workgroup = findWorkgroup(networkItem->workgroupItem()->workgroupName()); if (workgroup) { networkItem->update(); // Update the master browser for (int i = 0; i < networkItem->childCount(); ++i) { Smb4KNetworkBrowserItem *host = static_cast(networkItem->child(i)); host->update(); } } else { delete networkItem; } } ++itemIt; } // // Add new workgroups to the tree widget // for (const WorkgroupPtr &workgroup : workgroupsList()) { QList items = m_networkBrowser->findItems(workgroup->workgroupName(), Qt::MatchFixedString, Smb4KNetworkBrowser::Network); if (items.isEmpty()) { (void) new Smb4KNetworkBrowserItem(m_networkBrowser, workgroup); } } // // Sort the items // m_networkBrowser->sortItems(Smb4KNetworkBrowser::Network, Qt::AscendingOrder); } else { // // Clear the tree widget // m_networkBrowser->clear(); } } void Smb4KNetworkBrowserDockWidget::slotWorkgroupMembers(const WorkgroupPtr& workgroup) { // // Process the list of domain members // if (workgroup) { // // Find the workgroup(s) // QList workgroups = m_networkBrowser->findItems(workgroup->workgroupName(), Qt::MatchFixedString, Smb4KNetworkBrowser::Network); QMutableListIterator it(workgroups); while (it.hasNext()) { QTreeWidgetItem *item = it.next(); if (item->type() == Workgroup) { Smb4KNetworkBrowserItem *workgroupItem = static_cast(item); QTreeWidgetItemIterator itemIt(workgroupItem); // // Remove obsolete hosts and update existing ones // while (*itemIt) { Smb4KNetworkBrowserItem *networkItem = static_cast(*itemIt); if (networkItem->type() == Host) { HostPtr host = findHost(networkItem->hostItem()->hostName(), networkItem->hostItem()->workgroupName()); if (host) { networkItem->update(); } else { delete networkItem; } } else { break; } ++itemIt; } // // Add new hosts to the workgroup item and remove obsolete workgroups if // necessary. Honor the auto-expand feature. // QList members = workgroupMembers(workgroupItem->workgroupItem()); if (!members.isEmpty()) { for (const HostPtr &host : members) { bool foundHost = false; for (int i = 0; i < workgroupItem->childCount(); ++i) { Smb4KNetworkBrowserItem *hostItem = static_cast(workgroupItem->child(i)); if (hostItem->hostItem()->hostName() == host->hostName()) { foundHost = true; break; } else { continue; } } if (!foundHost) { (void) new Smb4KNetworkBrowserItem(workgroupItem, host); } } // Auto-expand the workgroup item, if applicable if (Smb4KSettings::autoExpandNetworkItems() && !workgroupItem->isExpanded() && !m_searchRunning) { m_networkBrowser->expandItem(workgroupItem); } } else { // Delete all hosts of the workgroup (if there should still be some) and // remove the workgroup item from the view (no hosts => no workgroup) while (workgroupItem->childCount() != 0) { delete workgroupItem->takeChild(0); } delete workgroupItem; } } } // // Sort the items // m_networkBrowser->sortItems(Smb4KNetworkBrowser::Network, Qt::AscendingOrder); } } void Smb4KNetworkBrowserDockWidget::slotShares(const HostPtr& host) { // // Process the list of shares // if (host) { // // Find the host(s) // QList hosts = m_networkBrowser->findItems(host->hostName(), Qt::MatchFixedString|Qt::MatchRecursive, Smb4KNetworkBrowser::Network); QMutableListIterator it(hosts); while (it.hasNext()) { Smb4KNetworkBrowserItem *hostItem = static_cast(it.next()); if (hostItem->type() == Host && hostItem->hostItem()->workgroupName() == host->workgroupName()) { QTreeWidgetItemIterator itemIt(hostItem); // // Remove obsolete shares and update existing ones // while (*itemIt) { Smb4KNetworkBrowserItem *shareItem = static_cast(*itemIt); if (shareItem->type() == Share) { SharePtr share = findShare(shareItem->shareItem()->url(), shareItem->shareItem()->workgroupName()); if (share) { shareItem->update(); } else { delete shareItem; } } else { break; } ++itemIt; } // // Add new shares to the host item. The host will not be removed from the // view when it has no shares. Honor the auto-expand feature. // QList shares = sharedResources(host); if (!shares.isEmpty()) { for (const SharePtr &share : shares) { bool foundShare = false; for (int i = 0; i < hostItem->childCount(); ++i) { Smb4KNetworkBrowserItem *shareItem = static_cast(hostItem->child(i)); if (QString::compare(shareItem->shareItem()->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0) { foundShare = true; break; } else { continue; } } if (!foundShare) { (void) new Smb4KNetworkBrowserItem(hostItem, share); } } // Auto-expand the host item, if applicable if (Smb4KSettings::autoExpandNetworkItems() && !hostItem->isExpanded() && !m_searchRunning) { m_networkBrowser->expandItem(hostItem); } } else { // Delete all shares (if there should still be some), but leave the // host in the view. while (hostItem->childCount() != 0) { delete hostItem->takeChild(0); } } } else { continue; } } // // Sort the items // m_networkBrowser->sortItems(Smb4KNetworkBrowser::Network, Qt::AscendingOrder); } } void Smb4KNetworkBrowserDockWidget::slotRescanAbortActionTriggered(bool /*checked*/) { // // Get the Rescan/Abort action // KDualAction *rescanAbortAction = static_cast(m_actionCollection->action("rescan_abort_action")); // // Get the selected items // QList selectedItems = m_networkBrowser->selectedItems(); // // Perform actions according to the state of the action and the number of // selected items. // if (!rescanAbortAction->isActive()) { if (selectedItems.size() == 1) { Smb4KNetworkBrowserItem *browserItem = static_cast(selectedItems.first()); if (browserItem) { switch (browserItem->type()) { case Workgroup: { Smb4KClient::self()->lookupDomainMembers(browserItem->workgroupItem()); break; } case Host: { Smb4KClient::self()->lookupShares(browserItem->hostItem()); break; } case Share: { Smb4KNetworkBrowserItem *parentItem = static_cast(browserItem->parent()); Smb4KClient::self()->lookupShares(parentItem->hostItem()); break; } default: { break; } } } } else { // If several items are selected or no selected items, // only the network can be scanned. Smb4KClient::self()->lookupDomains(); } } else { // Stop all actions performed by the client if (Smb4KClient::self()->isRunning()) { Smb4KClient::self()->abort(); } } } void Smb4KNetworkBrowserDockWidget::slotAddBookmark(bool /*checked*/) { QList items = m_networkBrowser->selectedItems(); QList shares; if (!items.isEmpty()) { for (int i = 0; i < items.size(); ++i) { Smb4KNetworkBrowserItem *item = static_cast(items.at(i)); if (item && item->type() == Share && !item->shareItem()->isPrinter()) { shares << item->shareItem(); } } } else { // No selected items. Just return. return; } if (!shares.isEmpty()) { Smb4KBookmarkHandler::self()->addBookmarks(shares); } } void Smb4KNetworkBrowserDockWidget::slotMountManually(bool /*checked*/) { Smb4KMounter::self()->openMountDialog(); } void Smb4KNetworkBrowserDockWidget::slotAuthentication(bool /*checked*/) { Smb4KNetworkBrowserItem *item = static_cast(m_networkBrowser->currentItem()); if (item) { switch (item->type()) { case Host: { Smb4KWalletManager::self()->showPasswordDialog(item->hostItem()); break; } case Share: { Smb4KWalletManager::self()->showPasswordDialog(item->shareItem()); break; } default: { break; } } } } void Smb4KNetworkBrowserDockWidget::slotCustomOptions(bool /*checked*/) { Smb4KNetworkBrowserItem *item = static_cast(m_networkBrowser->currentItem()); if (item) { switch (item->type()) { case Host: { Smb4KCustomOptionsManager::self()->openCustomOptionsDialog(item->hostItem()); break; } case Share: { Smb4KCustomOptionsManager::self()->openCustomOptionsDialog(item->shareItem()); break; } default: { break; } } } } void Smb4KNetworkBrowserDockWidget::slotPreview(bool /*checked*/) { QList items = m_networkBrowser->selectedItems(); if (!items.isEmpty()) { for (int i = 0; i < items.size(); ++i) { Smb4KNetworkBrowserItem *item = static_cast(items.at(i)); if (item && item->type() == Share && !item->shareItem()->isPrinter()) { Smb4KClient::self()->openPreviewDialog(item->shareItem()); } } } } void Smb4KNetworkBrowserDockWidget::slotPrint(bool /*checked*/) { Smb4KNetworkBrowserItem *item = static_cast(m_networkBrowser->currentItem()); if (item && item->shareItem()->isPrinter()) { Smb4KClient::self()->openPrintDialog(item->shareItem()); } } void Smb4KNetworkBrowserDockWidget::slotMountActionTriggered(bool /*checked*/) { // // Get the selected items // QList selectedItems = m_networkBrowser->selectedItems(); if (selectedItems.size() > 1) { // // In the case of multiple selected network items, selectedItems() // only contains shares. Thus, we do not need to test for the type. // For deciding what the mount action is supposed to do, i.e. mount // the (remaining) selected unmounted shares or unmounting all selected // mounted shares, we use the number of unmounted shares. If that is // greater than 0, we mount all shares that need to be mounted, otherwise // we unmount all selected shares. // QList unmounted, mounted; for (QTreeWidgetItem *item : selectedItems) { Smb4KNetworkBrowserItem *browserItem = static_cast(item); if (browserItem && browserItem->shareItem()->isMounted()) { mounted << browserItem->shareItem(); } else if (browserItem && !browserItem->shareItem()->isMounted()) { unmounted << browserItem->shareItem(); } } if (!unmounted.empty()) { // Mount the (remaining) unmounted shares. Smb4KMounter::self()->mountShares(unmounted); } else { // Unmount all shares. Smb4KMounter::self()->unmountShares(mounted, m_networkBrowser); } } else { // // If only one network item is selected, we need to test for the type // of the item. Only in case of a share we need to do something. // Smb4KNetworkBrowserItem *browserItem = static_cast(selectedItems.first()); if (browserItem) { switch (browserItem->type()) { case Share: { if (!browserItem->shareItem()->isMounted()) { Smb4KMounter::self()->mountShare(browserItem->shareItem()); } else { Smb4KMounter::self()->unmountShare(browserItem->shareItem(), false); } break; } default: { break; } } } } } void Smb4KNetworkBrowserDockWidget::slotMountActionChanged(bool active) { // // Get the mount action // KDualAction *mountAction = static_cast(m_actionCollection->action("mount_action")); // // Change the shortcuts depending on the value of the 'active' argument // if (mountAction) { if (active) { m_actionCollection->setDefaultShortcut(mountAction, QKeySequence(Qt::CTRL+Qt::Key_M)); } else { m_actionCollection->setDefaultShortcut(mountAction, QKeySequence(Qt::CTRL+Qt::Key_U)); } } } void Smb4KNetworkBrowserDockWidget::slotShareMounted(const SharePtr& share) { QTreeWidgetItemIterator it(m_networkBrowser); while (*it) { Smb4KNetworkBrowserItem *item = static_cast(*it); if (item->type() == Share) { if (QString::compare(item->shareItem()->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0) { item->update(); break; } } ++it; } } void Smb4KNetworkBrowserDockWidget::slotShareUnmounted(const SharePtr& share) { QTreeWidgetItemIterator it(m_networkBrowser); while (*it) { Smb4KNetworkBrowserItem *item = static_cast(*it); if (item->type() == Share) { if (QString::compare(item->shareItem()->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0) { item->update(); break; } } ++it; } } void Smb4KNetworkBrowserDockWidget::slotMounterAboutToStart(int /*process*/) { // // Unused at the moment // } void Smb4KNetworkBrowserDockWidget::slotMounterFinished(int process) { // // Get the mount/unmount action // KDualAction *mountAction = static_cast(m_actionCollection->action("mount_action")); // // Make adjustments // if (mountAction) { switch (process) { case MountShare: { mountAction->setActive(false); break; } case UnmountShare: { mountAction->setActive(true); break; } default: { break; } } } } void Smb4KNetworkBrowserDockWidget::slotIconSizeChanged(int group) { switch (group) { case KIconLoader::Small: { int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small); m_networkBrowser->setIconSize(QSize(icon_size, icon_size)); break; } default: { break; } } } void Smb4KNetworkBrowserDockWidget::slotShowSearchToolBar() { // // Show the search toolbar // m_searchToolBar->setVisible(true); // // Set the focus to the search item input // m_searchToolBar->prepareInput(); } void Smb4KNetworkBrowserDockWidget::slotHideSearchToolBar() { // // Prevent another dock widget from stealing the focus when // the search tool bar is hidden // m_networkBrowser->setFocus(); // // Hide the search toolbar // m_searchToolBar->setVisible(false); } void Smb4KNetworkBrowserDockWidget::slotPerformSearch(const QString& item) { // // Prevent another dock widget from stealing the focus when // the search item input is disabled // m_networkBrowser->setFocus(); // // A global search is underway // m_searchRunning = true; // // Start the search // Smb4KClient::self()->search(item); } void Smb4KNetworkBrowserDockWidget::slotStopSearch() { // // Stop the network search // Smb4KClient::self()->abort(); // // A global search finished // m_searchRunning = false; } void Smb4KNetworkBrowserDockWidget::slotSearchResults(const QList& shares) { // // A global search finished // m_searchRunning = false; // // Process the search results // QTreeWidgetItemIterator it(m_networkBrowser); while (*it) { Smb4KNetworkBrowserItem *networkItem = static_cast(*it); if (networkItem->type() == Share) { for (const SharePtr &share : shares) { if (networkItem->shareItem() == share) { // // Select the search result // networkItem->setSelected(true); // // Expand the branch of the network tree where a search result // was retrieved // if (!networkItem->parent()->isExpanded()) { m_networkBrowser->expandItem(networkItem->parent()); } if (!networkItem->parent()->parent()->isExpanded()) { m_networkBrowser->expandItem(networkItem->parent()->parent()); } } } } it++; } // // Pass the search results to the search toolbar // m_searchToolBar->setSearchResults(shares); } void Smb4KNetworkBrowserDockWidget::slotJumpToResult(const QString& url) { // // Find the share item with URL url // QTreeWidgetItemIterator it(m_networkBrowser); while (*it) { Smb4KNetworkBrowserItem *networkItem = static_cast(*it); if (networkItem->type() == Share && networkItem->shareItem()->url().toString() == url) { m_networkBrowser->setCurrentItem(networkItem); break; } it++; } } void Smb4KNetworkBrowserDockWidget::slotClearSearchResults() { m_networkBrowser->clearSelection(); } diff --git a/smb4k/smb4kprofilesmenu.cpp b/smb4k/smb4kprofilesmenu.cpp index 6cc67b1..d93fe5c 100644 --- a/smb4k/smb4kprofilesmenu.cpp +++ b/smb4k/smb4kprofilesmenu.cpp @@ -1,133 +1,131 @@ /*************************************************************************** smb4kprofilesmenu - The menu for the profiles ------------------- begin : Do Aug 10 2014 copyright : (C) 2014-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4kprofilesmenu.h" #include "core/smb4ksettings.h" #include "core/smb4kprofilemanager.h" // Qt includes #include #include // KDE includes #include #include Smb4KProfilesMenu::Smb4KProfilesMenu(QObject* parent) : KSelectAction(KDE::icon("format-list-unordered"), i18n("Profiles"), parent) { QStringList profiles = Smb4KProfileManager::self()->profilesList(); slotProfilesListChanged(profiles); setToolBarMode(KSelectAction::MenuMode); + // // Connections - connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), - this, SLOT(slotActiveProfileChanged(QString))); - connect(Smb4KProfileManager::self(), SIGNAL(profilesListChanged(QStringList)), - this, SLOT(slotProfilesListChanged(QStringList))); - connect(Smb4KProfileManager::self(), SIGNAL(profileUsageChanged(bool)), - this, SLOT(slotProfileUsageChanged(bool))); - connect(this, SIGNAL(triggered(QString)), - this, SLOT(slotActionTriggered(QString))); + // + connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), this, SLOT(slotActiveProfileChanged(QString))); + connect(Smb4KProfileManager::self(), SIGNAL(profilesListChanged(QStringList)), this, SLOT(slotProfilesListChanged(QStringList))); + connect(Smb4KProfileManager::self(), SIGNAL(profileUsageChanged(bool)), this, SLOT(slotProfileUsageChanged(bool))); + connect(this, SIGNAL(triggered(QString)), this, SLOT(slotActionTriggered(QString))); } Smb4KProfilesMenu::~Smb4KProfilesMenu() { } void Smb4KProfilesMenu::refreshMenu() { // // Clear the select action // clear(); // // Get the list of profiles and add all profiles to the select action // QStringList profiles = Smb4KProfileManager::self()->profilesList(); for (const QString &profile : profiles) { QAction *action = addAction(profile); if (action) { action->setEnabled(Smb4KProfileManager::self()->useProfiles()); } } // // Enable the action if the user chose to use profiles // setEnabled(Smb4KProfileManager::self()->useProfiles()); // // Set the current action // setCurrentAction(Smb4KProfileManager::self()->activeProfile()); } void Smb4KProfilesMenu::slotActiveProfileChanged(const QString& newProfile) { setCurrentAction(newProfile); } void Smb4KProfilesMenu::slotProfilesListChanged(const QStringList& /*profiles*/) { refreshMenu(); } void Smb4KProfilesMenu::slotProfileUsageChanged(bool use) { for (QAction *action : actions()) { if (action) { action->setEnabled(use); } } setEnabled(use); } void Smb4KProfilesMenu::slotActionTriggered(const QString& name) { Smb4KProfileManager::self()->setActiveProfile(name); } diff --git a/smb4k/smb4ksharesmenu.cpp b/smb4k/smb4ksharesmenu.cpp index 20b4be1..3a61f3c 100644 --- a/smb4k/smb4ksharesmenu.cpp +++ b/smb4k/smb4ksharesmenu.cpp @@ -1,315 +1,320 @@ /*************************************************************************** smb4ksharesmenu - Shares menu ------------------- begin : Mon Sep 05 2011 copyright : (C) 2011-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4ksharesmenu.h" #include "core/smb4kshare.h" #include "core/smb4kmounter.h" #include "core/smb4kglobal.h" #include "core/smb4ksynchronizer.h" #include "core/smb4kbookmarkhandler.h" #if defined(Q_OS_LINUX) #include "smb4kmountsettings_linux.h" #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) #include "smb4kmountsettings_bsd.h" #endif // Qt includes #include #include #include #include #include #include // KDE includes #include #include using namespace Smb4KGlobal; Smb4KSharesMenu::Smb4KSharesMenu(QWidget *parentWidget, QObject *parent) : KActionMenu(KDE::icon("folder-network", QStringList("emblem-mounted")), i18n("Mounted Shares"), parent), m_parent_widget(parentWidget) { // // Set up action group for the shares menus // m_menus = new QActionGroup(menu()); // // Set up action group for the shares actions // m_actions = new QActionGroup(menu()); + // // Setup the menu + // setupMenu(); + // + // Connections + // connect(m_actions, SIGNAL(triggered(QAction*)), SLOT(slotShareAction(QAction*))); connect(Smb4KMounter::self(), SIGNAL(mountedSharesListChanged()), SLOT(slotMountedSharesListChanged())); } Smb4KSharesMenu::~Smb4KSharesMenu() { } void Smb4KSharesMenu::refreshMenu() { // // Delete all entries from the menu // while (!menu()->actions().isEmpty()) { QAction *action = menu()->actions().takeFirst(); removeAction(action); delete action; } // // Clear the rest of the menu // if (!menu()->isEmpty()) { menu()->clear(); } // // Set up the menu // setupMenu(); // // Make sure the correct menu entries are shown // menu()->update(); } void Smb4KSharesMenu::setupMenu() { // // Add the Unmount All action // QAction *unmount_all = new QAction(KDE::icon("system-run"), i18n("U&nmount All"), menu()); unmount_all->setEnabled(false); connect(unmount_all, SIGNAL(triggered(bool)), SLOT(slotUnmountAllShares())); addAction(unmount_all); // // Add a separator // addSeparator(); // // Add the share entries // QStringList displayNames; for (const SharePtr &share : mountedSharesList()) { // Do not process null pointers if (!share) { continue; } // Add the display name to the list displayNames << share->displayString(); // Create the share menu KActionMenu *shareMenu = new KActionMenu(share->displayString(), menu()); shareMenu->setIcon(share->icon()); QMap data; data["text"] = share->displayString(); shareMenu->setData(data); m_menus->addAction(shareMenu); // Add the unmount action to the menu QAction *unmount = new QAction(KDE::icon("media-eject"), i18n("Unmount"), shareMenu->menu()); QMap unmountData; unmountData["type"] = "unmount"; unmountData["mountpoint"] = share->path(); unmount->setData(unmountData); unmount->setEnabled(!share->isForeign() || Smb4KMountSettings::unmountForeignShares()); shareMenu->addAction(unmount); m_actions->addAction(unmount); // Add a separator shareMenu->addSeparator(); // Add the bookmark action to the menu QAction *addBookmark = new QAction(KDE::icon("bookmark-new"), i18n("Add Bookmark"), shareMenu->menu()); QMap bookmarkData; bookmarkData["type"] = "bookmark"; bookmarkData["mountpoint"] = share->path(); addBookmark->setData(bookmarkData); shareMenu->addAction(addBookmark); m_actions->addAction(addBookmark); // Add the synchronization action to the menu QAction *synchronize = new QAction(KDE::icon("folder-sync"), i18n("Synchronize"), shareMenu->menu()); QMap syncData; syncData["type"] = "sync"; syncData["mountpoint"] = share->path(); synchronize->setData(syncData); synchronize->setEnabled(!QStandardPaths::findExecutable("rsync").isEmpty() && !share->isInaccessible()); shareMenu->addAction(synchronize); m_actions->addAction(synchronize); // Add a separator shareMenu->addSeparator(); // Add the Open with Konsole action to the menu QAction *konsole = new QAction(KDE::icon("utilities-terminal"), i18n("Open with Konsole"), shareMenu->menu()); QMap konsoleData; konsoleData["type"] = "konsole"; konsoleData["mountpoint"] = share->path(); konsole->setData(konsoleData); konsole->setEnabled(!QStandardPaths::findExecutable("konsole").isEmpty() && !share->isInaccessible()); shareMenu->addAction(konsole); m_actions->addAction(konsole); // Add the Open with Filemanager action to the menu QAction *filemanager = new QAction(KDE::icon("system-file-manager"), i18n("Open with File Manager"), shareMenu->menu()); QMap fmData; fmData["type"] = "filemanager"; fmData["mountpoint"] = share->path(); filemanager->setData(fmData); filemanager->setEnabled(!share->isInaccessible()); shareMenu->addAction(filemanager); m_actions->addAction(filemanager); } // // Sort the display names and add the share menus to the menu // in the sorted order. // displayNames.sort(); for (const QString &name : displayNames) { for (QAction *action : m_menus->actions()) { if (action->data().toMap().value("text").toString() == name) { addAction(action); break; } } } // // Enable or disable the Unmount All action, depending on the number of // mounted shares present. // unmount_all->setEnabled(((!onlyForeignMountedShares() || Smb4KMountSettings::unmountForeignShares()) && !m_menus->actions().isEmpty())); } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KSharesMenu::slotMountedSharesListChanged() { // // Refresh the menu // refreshMenu(); } void Smb4KSharesMenu::slotUnmountAllShares() { Smb4KMounter::self()->unmountAllShares(false); } void Smb4KSharesMenu::slotShareAction(QAction *action) { // // Create a share // SharePtr share; // // Check that we have a share related action // if (action->data().toMap().contains("type")) { share = findShareByPath(action->data().toMap().value("mountpoint").toString()); } // // Now process the action // if (share) { QString type = action->data().toMap().value("type").toString(); QString mountpoint = action->data().toMap().value("mountpoint").toString(); if (type == "unmount") { Smb4KMounter::self()->unmountShare(share, false); } else if (type == "bookmark") { Smb4KBookmarkHandler::self()->addBookmark(share); } else if (type == "sync") { Smb4KSynchronizer::self()->synchronize(share); } else if (type == "konsole") { openShare(share, Smb4KGlobal::Konsole); } else if (type == "filemanager") { openShare(share, Smb4KGlobal::FileManager); } } } diff --git a/smb4k/smb4ksharesview.cpp b/smb4k/smb4ksharesview.cpp index 1ed9fce..ef14f61 100644 --- a/smb4k/smb4ksharesview.cpp +++ b/smb4k/smb4ksharesview.cpp @@ -1,400 +1,399 @@ /*************************************************************************** This is the shares view of Smb4K. ------------------- begin : Mo Dez 4 2006 copyright : (C) 2006-2019 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * 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; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // application specific includes #include "smb4ksharesview.h" #include "smb4ksharesviewitem.h" #include "smb4ktooltip.h" #include "core/smb4kshare.h" #include "core/smb4ksettings.h" // Qt includes #include #include #include #include #include // KDE includes #include Smb4KSharesView::Smb4KSharesView(QWidget *parent) : QListWidget(parent) { setMouseTracking(true); setSelectionMode(ExtendedSelection); setResizeMode(Adjust); setSortingEnabled(true); setWordWrap(true); setAcceptDrops(true); setDragEnabled(true); setDropIndicatorShown(true); setUniformItemSizes(true); setWrapping(true); setContextMenuPolicy(Qt::CustomContextMenu); m_tooltipItem = 0; m_mouseInside = false; - // Connections: - connect(this, SIGNAL(itemEntered(QListWidgetItem*)), - this, SLOT(slotItemEntered(QListWidgetItem*))); - - connect(this, SIGNAL(viewportEntered()), - this, SLOT(slotViewportEntered())); + // + // Connections + // + connect(this, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(slotItemEntered(QListWidgetItem*))); + connect(this, SIGNAL(viewportEntered()), this, SLOT(slotViewportEntered())); } Smb4KSharesView::~Smb4KSharesView() { } void Smb4KSharesView::setViewMode(QListView::ViewMode mode, int iconSize) { // // Set the view mode // QListWidget::setViewMode(mode); // // Make adjustments // switch(mode) { case IconMode: { setUniformItemSizes(true); setIconSize(QSize(iconSize, iconSize)); setSpacing(5); break; } case ListMode: { setUniformItemSizes(false); setIconSize(QSize(iconSize, iconSize)); setSpacing(0); break; } default: { break; } } // // Align the items // for (int i = 0; i < count(); ++i) { Smb4KSharesViewItem *viewItem = static_cast(item(i)); viewItem->setItemAlignment(mode); } } bool Smb4KSharesView::event(QEvent *e) { switch (e->type()) { case QEvent::ToolTip: { // Intercept the tool tip event and show our own tool tip. QPoint pos = viewport()->mapFromGlobal(cursor().pos()); Smb4KSharesViewItem *item = static_cast(itemAt(pos)); if (item) { if (Smb4KSettings::showShareToolTip()) { m_tooltipItem = item; emit aboutToShowToolTip(m_tooltipItem); m_tooltipItem->tooltip()->show(cursor().pos()); } else { if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } } } else { if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } } break; } default: { break; } } return QListWidget::event(e); } void Smb4KSharesView::leaveEvent(QEvent *e) { if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } m_mouseInside = false; QListWidget::leaveEvent(e); } void Smb4KSharesView::enterEvent(QEvent *e) { m_mouseInside = true; QListWidget::enterEvent(e); } void Smb4KSharesView::mousePressEvent(QMouseEvent *e) { // Hide the current tool tip so that it is not in the way. if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } // Get the item that is under the mouse. If there is no // item, unselect the current item. QListWidgetItem *item = itemAt(e->pos()); if (!item && !selectedItems().isEmpty()) { clearSelection(); setCurrentItem(0); emit itemPressed(currentItem()); } QListWidget::mousePressEvent(e); } void Smb4KSharesView::focusOutEvent(QFocusEvent *e) { QListWidget::focusOutEvent(e); } void Smb4KSharesView::wheelEvent(QWheelEvent *e) { if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } QListWidget::wheelEvent(e); } void Smb4KSharesView::dragEnterEvent(QDragEnterEvent *e) { if (e->mimeData()->hasUrls()) { e->accept(); } else { e->ignore(); } } void Smb4KSharesView::dragMoveEvent(QDragMoveEvent *e) { // Let the QAbstractItemView do the highlighting of the item, etc. QAbstractItemView::dragMoveEvent(e); // Now we do our thing. Smb4KSharesViewItem *item = static_cast(itemAt(e->pos())); if (item && !item->shareItem()->isInaccessible() && (item->flags() & Qt::ItemIsDropEnabled) && (e->proposedAction() & (Qt::CopyAction | Qt::MoveAction))) { QUrl url = QUrl::fromLocalFile(item->shareItem()->path()); if (e->source() == this && e->mimeData()->urls().first() == url) { e->ignore(); } else { e->accept(); } } else { e->ignore(); } } void Smb4KSharesView::dropEvent(QDropEvent *e) { // Get the item and process the drop event Smb4KSharesViewItem *item = static_cast(itemAt(e->pos())); if (item && !item->shareItem()->isInaccessible() && (e->proposedAction() & (Qt::CopyAction|Qt::MoveAction))) { QUrl url = QUrl::fromLocalFile(item->shareItem()->path()); if (e->source() == this && e->mimeData()->urls().first() == url) { e->ignore(); } else { e->acceptProposedAction(); emit acceptedDropEvent(item, e); e->accept(); } } else { e->ignore(); } } Qt::DropActions Smb4KSharesView::supportedDropActions() const { // Only allow copying and linking. return (Qt::CopyAction|Qt::LinkAction); } QMimeData *Smb4KSharesView::mimeData(const QList list) const { QMimeData *mimeData = new QMimeData(); QList urls; for (int i = 0; i < list.count(); ++i) { Smb4KSharesViewItem *item = static_cast(list.at(i)); urls << QUrl::fromLocalFile(item->shareItem()->path()); } mimeData->setUrls(urls); return mimeData; } void Smb4KSharesView::startDrag(Qt::DropActions supported) { if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } QList list = selectedItems(); if (!list.isEmpty()) { QMimeData *data = mimeData(list); if (!data) { return; } QDrag *drag = new QDrag(this); QPixmap pixmap; if (list.count() == 1) { Smb4KSharesViewItem *item = static_cast(list.first()); pixmap = item->icon().pixmap(KIconLoader::SizeMedium); } else { pixmap = KDE::icon("document-multiple").pixmap(KIconLoader::SizeMedium); } drag->setPixmap(pixmap); drag->setMimeData(data); drag->exec(supported, Qt::IgnoreAction); } } ///////////////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KSharesView::slotItemEntered(QListWidgetItem *item) { Smb4KSharesViewItem *share_item = static_cast(item); if (m_tooltipItem && m_tooltipItem != share_item) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } } void Smb4KSharesView::slotViewportEntered() { // Hide the tool tip. if (m_tooltipItem) { emit aboutToHideToolTip(m_tooltipItem); m_tooltipItem->tooltip()->hide(); m_tooltipItem = 0; } }