File indexing completed on 2024-12-01 10:41:11

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