File indexing completed on 2023-12-10 04:59:17

0001 /*
0002  *  Mount dialog
0003  *
0004  *  SPDX-FileCopyrightText: 2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 // application specific includes
0009 #include "smb4kmountdialog.h"
0010 #include "core/smb4kbookmarkhandler.h"
0011 #include "core/smb4kglobal.h"
0012 #include "core/smb4kmounter.h"
0013 #include "core/smb4knotification.h"
0014 #include "core/smb4ksettings.h"
0015 
0016 // Qt includes
0017 #include <QDialogButtonBox>
0018 #include <QFrame>
0019 #include <QGridLayout>
0020 #include <QHostAddress>
0021 #include <QLabel>
0022 #include <QSizePolicy>
0023 #include <QVBoxLayout>
0024 #include <QWindow>
0025 
0026 // KDE includes
0027 #include <KConfigGroup>
0028 #include <KLocalizedString>
0029 #include <KWindowConfig>
0030 
0031 Smb4KMountDialog::Smb4KMountDialog(QWidget *parent)
0032     : QDialog(parent)
0033 {
0034     setWindowTitle(i18n("Mount Dialog"));
0035     setAttribute(Qt::WA_DeleteOnClose);
0036 
0037     QVBoxLayout *layout = new QVBoxLayout(this);
0038 
0039     QWidget *descriptionWidget = new QWidget(this);
0040 
0041     QHBoxLayout *descriptionWidgetLayout = new QHBoxLayout(descriptionWidget);
0042 
0043     QLabel *descriptionPixmap = new QLabel(descriptionWidget);
0044     descriptionPixmap->setPixmap(KDE::icon(QStringLiteral("media-mount")).pixmap(KIconLoader::SizeHuge));
0045     descriptionPixmap->setAlignment(Qt::AlignBottom);
0046     descriptionPixmap->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
0047 
0048     descriptionWidgetLayout->addWidget(descriptionPixmap);
0049 
0050     QLabel *descriptionText = new QLabel(this);
0051     descriptionText->setText(i18n("Enter the location and optionally the IP address and workgroup to mount a share."));
0052     descriptionText->setWordWrap(true);
0053     descriptionText->setAlignment(Qt::AlignBottom);
0054     descriptionText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
0055 
0056     descriptionWidgetLayout->addWidget(descriptionText);
0057 
0058     layout->addWidget(descriptionWidget);
0059 
0060     QWidget *inputWidget = new QWidget(this);
0061 
0062     QGridLayout *inputWidgetLayout = new QGridLayout(inputWidget);
0063     inputWidgetLayout->setContentsMargins(0, 0, 0, 0);
0064 
0065     QLabel *locationLabel = new QLabel(i18n("Location:"), inputWidget);
0066     m_locationInput = new KLineEdit(inputWidget);
0067     m_locationInput->setCompletionMode(KCompletion::CompletionPopupAuto);
0068     m_locationInput->setClearButtonEnabled(true);
0069     m_locationInput->setFocus();
0070 
0071     connect(m_locationInput, &KLineEdit::textChanged, this, &Smb4KMountDialog::slotEnableButtons);
0072     connect(m_locationInput, &KLineEdit::editingFinished, this, &Smb4KMountDialog::slotLocationEntered);
0073 
0074     QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), inputWidget);
0075     m_ipAddressInput = new KLineEdit(inputWidget);
0076     m_ipAddressInput->setCompletionMode(KCompletion::CompletionPopupAuto);
0077     m_ipAddressInput->setClearButtonEnabled(true);
0078 
0079     connect(m_ipAddressInput, &KLineEdit::editingFinished, this, &Smb4KMountDialog::slotIpAddressEntered);
0080 
0081     QLabel *workgroupLabel = new QLabel(i18n("Workgroup:"), inputWidget);
0082     m_workgroupInput = new KLineEdit(inputWidget);
0083     m_workgroupInput->setCompletionMode(KCompletion::CompletionPopupAuto);
0084     m_workgroupInput->setClearButtonEnabled(true);
0085 
0086     connect(m_workgroupInput, &KLineEdit::editingFinished, this, &Smb4KMountDialog::slotWorkgroupEntered);
0087 
0088     inputWidgetLayout->addWidget(locationLabel, 0, 0);
0089     inputWidgetLayout->addWidget(m_locationInput, 0, 1);
0090     inputWidgetLayout->addWidget(ipAddressLabel, 1, 0);
0091     inputWidgetLayout->addWidget(m_ipAddressInput, 1, 1);
0092     inputWidgetLayout->addWidget(workgroupLabel, 2, 0);
0093     inputWidgetLayout->addWidget(m_workgroupInput, 2, 1);
0094 
0095     layout->addWidget(inputWidget);
0096 
0097     m_bookmarkWidget = new QWidget(this);
0098     m_bookmarkWidget->setVisible(false);
0099 
0100     QVBoxLayout *bookmarkWidgetLayout = new QVBoxLayout(m_bookmarkWidget);
0101     bookmarkWidgetLayout->setContentsMargins(0, 0, 0, 0);
0102 
0103     QFrame *horizontalLine = new QFrame(m_bookmarkWidget);
0104     horizontalLine->setFrameShape(QFrame::HLine);
0105 
0106     m_bookmarkShare = new QCheckBox(i18n("Bookmark this share"), m_bookmarkWidget);
0107 
0108     connect(m_bookmarkShare, &QCheckBox::clicked, this, &Smb4KMountDialog::slotEnableBookmarkInputWidget);
0109 
0110     m_bookmarkInputWidget = new QWidget(m_bookmarkWidget);
0111     m_bookmarkInputWidget->setEnabled(false);
0112 
0113     QGridLayout *bookmarkInputWidgetLayout = new QGridLayout(m_bookmarkInputWidget);
0114     bookmarkInputWidgetLayout->setContentsMargins(0, 0, 0, 0);
0115 
0116     QLabel *bookmarkLabelLabel = new QLabel(i18n("Label:"), m_bookmarkInputWidget);
0117     m_bookmarkLabelInput = new KLineEdit(m_bookmarkInputWidget);
0118     m_bookmarkLabelInput->setCompletionMode(KCompletion::CompletionPopupAuto);
0119     m_bookmarkLabelInput->setClearButtonEnabled(true);
0120 
0121     connect(m_bookmarkLabelInput, &KLineEdit::editingFinished, this, &Smb4KMountDialog::slotLabelEntered);
0122 
0123     QLabel *bookmarkCategoryLabel = new QLabel(i18n("Category:"), m_bookmarkInputWidget);
0124     m_bookmarkCategoryInput = new KComboBox(m_bookmarkInputWidget);
0125     m_bookmarkCategoryInput->setEditable(true);
0126     m_bookmarkCategoryInput->setCompletionMode(KCompletion::CompletionPopupAuto);
0127     m_bookmarkCategoryInput->lineEdit()->setClearButtonEnabled(true);
0128 
0129     connect(m_bookmarkCategoryInput->lineEdit(), &QLineEdit::editingFinished, this, &Smb4KMountDialog::slotCategoryEntered);
0130 
0131     bookmarkInputWidgetLayout->addWidget(bookmarkLabelLabel, 0, 0);
0132     bookmarkInputWidgetLayout->addWidget(m_bookmarkLabelInput, 0, 1);
0133     bookmarkInputWidgetLayout->addWidget(bookmarkCategoryLabel, 1, 0);
0134     bookmarkInputWidgetLayout->addWidget(m_bookmarkCategoryInput, 1, 1);
0135 
0136     bookmarkWidgetLayout->addWidget(horizontalLine);
0137     bookmarkWidgetLayout->addWidget(m_bookmarkShare);
0138     bookmarkWidgetLayout->addWidget(m_bookmarkInputWidget);
0139 
0140     layout->addWidget(m_bookmarkWidget);
0141 
0142     QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
0143     m_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
0144     m_cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel);
0145     m_bookmarkButton = buttonBox->addButton(i18nc("Bookmark a share in the mount dialog.", "Bookmark >>"), QDialogButtonBox::ActionRole);
0146 
0147     m_okButton->setEnabled(false);
0148     m_bookmarkButton->setEnabled(false);
0149 
0150     connect(m_okButton, &QPushButton::clicked, this, &Smb4KMountDialog::slotAccepted);
0151     connect(m_cancelButton, &QPushButton::clicked, this, &Smb4KMountDialog::slotRejected);
0152     connect(m_bookmarkButton, &QPushButton::clicked, this, &Smb4KMountDialog::slotBookmarkButtonClicked);
0153 
0154     layout->addWidget(buttonBox);
0155 
0156     setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350);
0157 
0158     create();
0159 
0160     KConfigGroup dialogGroup(Smb4KSettings::self()->config(), "MountDialog");
0161     QSize dialogSize;
0162 
0163     if (dialogGroup.exists()) {
0164         KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup);
0165         dialogSize = windowHandle()->size();
0166     } else {
0167         dialogSize = sizeHint();
0168     }
0169 
0170     resize(dialogSize); // workaround for QTBUG-40584
0171 
0172     KConfigGroup completionGroup(Smb4KSettings::self()->config(), "CompletionItems");
0173 
0174     if (completionGroup.exists()) {
0175         m_locationInput->completionObject()->setItems(completionGroup.readEntry("LocationCompletion", QStringList()));
0176         m_ipAddressInput->completionObject()->setItems(completionGroup.readEntry("IpAddressCompletion", QStringList()));
0177         m_workgroupInput->completionObject()->setItems(completionGroup.readEntry("WorkgroupCompletion", QStringList()));
0178         m_bookmarkLabelInput->completionObject()->setItems(completionGroup.readEntry("LabelCompletion", QStringList()));
0179         m_bookmarkCategoryInput->completionObject()->setItems(completionGroup.readEntry("CategoryCompletion", Smb4KBookmarkHandler::self()->categoryList()));
0180     }
0181 }
0182 
0183 Smb4KMountDialog::~Smb4KMountDialog()
0184 {
0185 }
0186 
0187 bool Smb4KMountDialog::isValidLocation(const QString &text)
0188 {
0189     QString userInput = text;
0190 
0191     if (userInput.startsWith(QStringLiteral("\\"))) {
0192         userInput.replace(QStringLiteral("\\"), QStringLiteral("/"));
0193     }
0194 
0195     QUrl url = QUrl::fromUserInput(userInput).adjusted(QUrl::StripTrailingSlash);
0196     url.setScheme(QStringLiteral("smb"));
0197 
0198     return (url.isValid() && !url.host().isEmpty() && !url.path().isEmpty() && url.path().length() != 1);
0199 }
0200 
0201 void Smb4KMountDialog::adjustDialogSize()
0202 {
0203     ensurePolished();
0204     layout()->activate();
0205 
0206     QSize dialogSize;
0207     dialogSize.setWidth(width());
0208     dialogSize.setHeight(height() - m_bookmarkWidget->height() - layout()->contentsMargins().bottom() - layout()->contentsMargins().top());
0209 
0210     resize(dialogSize);
0211 }
0212 
0213 void Smb4KMountDialog::slotEnableButtons(const QString &text)
0214 {
0215     bool enable = isValidLocation(text);
0216     m_okButton->setEnabled(enable);
0217     m_bookmarkButton->setEnabled(enable);
0218 }
0219 
0220 void Smb4KMountDialog::slotBookmarkButtonClicked()
0221 {
0222     m_bookmarkWidget->setVisible(!m_bookmarkWidget->isVisible());
0223 
0224     if (!m_bookmarkWidget->isVisible()) {
0225         adjustDialogSize();
0226     }
0227 }
0228 
0229 void Smb4KMountDialog::slotEnableBookmarkInputWidget()
0230 {
0231     m_bookmarkInputWidget->setEnabled(m_bookmarkShare->isChecked());
0232 }
0233 
0234 void Smb4KMountDialog::slotLocationEntered()
0235 {
0236     QString userInputUrl = m_locationInput->userText().trimmed();
0237 
0238     if (userInputUrl.startsWith(QStringLiteral("\\"))) {
0239         userInputUrl.replace(QStringLiteral("\\"), QStringLiteral("/"));
0240     }
0241 
0242     QUrl url = QUrl::fromUserInput(userInputUrl).adjusted(QUrl::StripTrailingSlash);
0243     url.setScheme(QStringLiteral("smb"));
0244 
0245     if (isValidLocation(userInputUrl)) {
0246         m_locationInput->completionObject()->addItem(userInputUrl);
0247     }
0248 }
0249 
0250 void Smb4KMountDialog::slotIpAddressEntered()
0251 {
0252     QString userInputIpAddress = m_ipAddressInput->userText().trimmed();
0253 
0254     if (!userInputIpAddress.isEmpty()) {
0255         m_ipAddressInput->completionObject()->addItem(userInputIpAddress);
0256     }
0257 }
0258 
0259 void Smb4KMountDialog::slotWorkgroupEntered()
0260 {
0261     QString userInputWorkgroup = m_workgroupInput->userText().trimmed();
0262 
0263     if (!userInputWorkgroup.isEmpty()) {
0264         m_workgroupInput->completionObject()->addItem(userInputWorkgroup);
0265     }
0266 }
0267 
0268 void Smb4KMountDialog::slotLabelEntered()
0269 {
0270     QString userInputLabel = m_bookmarkLabelInput->userText().trimmed();
0271 
0272     if (!userInputLabel.isEmpty()) {
0273         m_bookmarkLabelInput->completionObject()->addItem(userInputLabel);
0274     }
0275 }
0276 
0277 void Smb4KMountDialog::slotCategoryEntered()
0278 {
0279     QString userInputCategory = m_bookmarkCategoryInput->currentText();
0280 
0281     if (!userInputCategory.isEmpty()) {
0282         m_bookmarkCategoryInput->completionObject()->addItem(userInputCategory);
0283     }
0284 }
0285 
0286 void Smb4KMountDialog::slotAccepted()
0287 {
0288     QString userInputUrl = m_locationInput->userText().trimmed();
0289 
0290     if (userInputUrl.startsWith(QStringLiteral("\\"))) {
0291         userInputUrl.replace(QStringLiteral("\\"), QStringLiteral("/"));
0292     }
0293 
0294     QUrl url = QUrl::fromUserInput(userInputUrl).adjusted(QUrl::StripTrailingSlash);
0295     url.setScheme(QStringLiteral("smb"));
0296 
0297     // This case might never happen, because the buttons are only
0298     // enabled when isValidLocation() returns TRUE, but we leave
0299     // this here for safety.
0300     if (!isValidLocation(userInputUrl)) {
0301         m_locationInput->setFocus();
0302         return;
0303     }
0304 
0305     SharePtr share = SharePtr(new Smb4KShare());
0306     share->setUrl(url);
0307 
0308     BookmarkPtr bookmark = BookmarkPtr(new Smb4KBookmark());
0309     bookmark->setUrl(url);
0310 
0311     QHostAddress userIpAddressInput(m_ipAddressInput->userText().trimmed());
0312 
0313     if (userIpAddressInput.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol) {
0314         share->setHostIpAddress(userIpAddressInput.toString());
0315         bookmark->setHostIpAddress(userIpAddressInput.toString());
0316     }
0317 
0318     QString userInputWorkgroup = m_workgroupInput->userText().trimmed();
0319 
0320     if (!userInputWorkgroup.isEmpty()) {
0321         share->setWorkgroupName(userInputWorkgroup);
0322         bookmark->setWorkgroupName(userInputWorkgroup);
0323     }
0324 
0325     if (m_bookmarkShare->isChecked()) {
0326         bookmark->setLabel(m_bookmarkLabelInput->userText());
0327         bookmark->setCategoryName(m_bookmarkCategoryInput->currentText());
0328 
0329         Smb4KBookmarkHandler::self()->addBookmark(bookmark);
0330     }
0331 
0332     Smb4KMounter::self()->mountShare(share);
0333 
0334     share.clear();
0335     bookmark.clear();
0336 
0337     if (m_bookmarkWidget->isVisible()) {
0338         m_bookmarkInputWidget->setVisible(false);
0339         adjustDialogSize();
0340     }
0341 
0342     KConfigGroup dialogGroup(Smb4KSettings::self()->config(), "MountDialog");
0343     KWindowConfig::saveWindowSize(windowHandle(), dialogGroup);
0344 
0345     KConfigGroup completionGroup(Smb4KSettings::self()->config(), "CompletionItems");
0346     completionGroup.writeEntry("LocationCompletion", m_locationInput->completionObject()->items());
0347     completionGroup.writeEntry("IpAddressCompletion", m_ipAddressInput->completionObject()->items());
0348     completionGroup.writeEntry("WorkgroupCompletion", m_workgroupInput->completionObject()->items());
0349     completionGroup.writeEntry("LabelCompletion", m_bookmarkLabelInput->completionObject()->items());
0350     completionGroup.writeEntry("CategoryCompletion", m_bookmarkCategoryInput->completionObject()->items());
0351 
0352     accept();
0353 }
0354 
0355 void Smb4KMountDialog::slotRejected()
0356 {
0357     reject();
0358 }