/*
    The configuration page for the mount options

    SPDX-FileCopyrightText: 2015-2022 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
    SPDX-License-Identifier: GPL-2.0-or-later
*/

// application specific includes
#include "smb4kconfigpagemounting.h"
#include "core/smb4kglobal.h"

#if defined(Q_OS_LINUX)
#include "core/smb4kmountsettings_linux.h"
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
#include "core/smb4kmountsettings_bsd.h"
#endif

// Qt includes
#include <QCheckBox>
#include <QGroupBox>
#include <QInputDialog>
#include <QLabel>
#include <QMenu>
#include <QSpinBox>
#include <QToolButton>
#include <QVBoxLayout>

// KDE includes
#include <KCompletion/KComboBox>
#include <KCompletion/KLineEdit>
#include <KI18n/KLocalizedString>
#include <KIOWidgets/KUrlRequester>
#include <KIconThemes/KIconLoader>
#include <KWidgetsAddons/KMessageBox>

using namespace Smb4KGlobal;

Smb4KConfigPageMounting::Smb4KConfigPageMounting(QWidget *parent)
    : QTabWidget(parent)
{
    setupWidget();
}

Smb4KConfigPageMounting::~Smb4KConfigPageMounting()
{
}

bool Smb4KConfigPageMounting::checkSettings()
{
    KUrlRequester *mountPrefix = findChild<KUrlRequester *>(QStringLiteral("kcfg_MountPrefix"));

    if (mountPrefix) {
        if (!mountPrefix->url().isValid()) {
            mountPrefix->setFocus();
            return false;
        }
    }

    QCheckBox *useFileMode = findChild<QCheckBox *>(QStringLiteral("kcfg_UseFileMode"));
    KLineEdit *fileMode = findChild<KLineEdit *>(QStringLiteral("kcfg_FileMode"));

    if (useFileMode && fileMode) {
        if (useFileMode->isChecked() && fileMode->text().trimmed().isEmpty()) {
            fileMode->setFocus();
            return false;
        }
    }

    QCheckBox *useDirectoryMode = findChild<QCheckBox *>(QStringLiteral("kcfg_UseDirectoryMode"));
    KLineEdit *directoryMode = findChild<KLineEdit *>(QStringLiteral("kcfg_DirectoryMode"));

    if (useDirectoryMode && directoryMode) {
        if (useDirectoryMode->isChecked() && directoryMode->text().trimmed().isEmpty()) {
            directoryMode->setFocus();
            return false;
        }
    }

    return true;
}

#if defined(Q_OS_LINUX)
//
// Linux
//
void Smb4KConfigPageMounting::setupWidget()
{
    //
    // Basic Settings tab
    //
    QWidget *basicTab = new QWidget(this);
    QVBoxLayout *basicTabLayout = new QVBoxLayout(basicTab);

    //
    // Directories
    //
    QGroupBox *directoryBox = new QGroupBox(i18n("Directories"), basicTab);
    QGridLayout *directoryBoxLayout = new QGridLayout(directoryBox);

    QLabel *prefixLabel = new QLabel(Smb4KMountSettings::self()->mountPrefixItem()->label(), directoryBox);
    KUrlRequester *prefix = new KUrlRequester(directoryBox);
    prefix->setMode(KFile::Directory | KFile::LocalOnly);
    prefix->setObjectName(QStringLiteral("kcfg_MountPrefix"));

    prefixLabel->setBuddy(prefix);

    QCheckBox *lowercaseSubdirs = new QCheckBox(Smb4KMountSettings::self()->forceLowerCaseSubdirsItem()->label(), directoryBox);
    lowercaseSubdirs->setObjectName(QStringLiteral("kcfg_ForceLowerCaseSubdirs"));

    directoryBoxLayout->addWidget(prefixLabel, 0, 0);
    directoryBoxLayout->addWidget(prefix, 0, 1);
    directoryBoxLayout->addWidget(lowercaseSubdirs, 1, 0, 1, 2);

    basicTabLayout->addWidget(directoryBox, 0);

    //
    // Behavior
    //
    QGroupBox *behaviorBox = new QGroupBox(i18n("Behavior"), this);
    QGridLayout *behaviorBoxLayout = new QGridLayout(behaviorBox);

    QCheckBox *remountShares = new QCheckBox(Smb4KMountSettings::self()->remountSharesItem()->label(), behaviorBox);
    remountShares->setObjectName(QStringLiteral("kcfg_RemountShares"));

    QLabel *remountAttemptsLabel = new QLabel(Smb4KMountSettings::self()->remountAttemptsItem()->label(), behaviorBox);
    remountAttemptsLabel->setObjectName(QStringLiteral("RemountAttemptsLabel"));
    remountAttemptsLabel->setIndent(25);

    QSpinBox *remountAttempts = new QSpinBox(behaviorBox);
    remountAttempts->setObjectName(QStringLiteral("kcfg_RemountAttempts"));
    remountAttemptsLabel->setBuddy(remountAttempts);

    QLabel *remountIntervalLabel = new QLabel(Smb4KMountSettings::self()->remountIntervalItem()->label(), behaviorBox);
    remountIntervalLabel->setObjectName(QStringLiteral("RemountIntervalLabel"));
    remountIntervalLabel->setIndent(25);

    QSpinBox *remountInterval = new QSpinBox(behaviorBox);
    remountInterval->setObjectName(QStringLiteral("kcfg_RemountInterval"));
    remountInterval->setSuffix(i18n(" min"));
    remountIntervalLabel->setBuddy(remountInterval);

    QCheckBox *unmountAllShares = new QCheckBox(Smb4KMountSettings::self()->unmountSharesOnExitItem()->label(), behaviorBox);
    unmountAllShares->setObjectName(QStringLiteral("kcfg_UnmountSharesOnExit"));

    QCheckBox *unmountForeignShares = new QCheckBox(Smb4KMountSettings::self()->unmountForeignSharesItem()->label(), behaviorBox);
    unmountForeignShares->setObjectName(QStringLiteral("kcfg_UnmountForeignShares"));

    QCheckBox *unmountInaccessibleShares = new QCheckBox(Smb4KMountSettings::self()->forceUnmountInaccessibleItem()->label(), behaviorBox);
    unmountInaccessibleShares->setObjectName(QStringLiteral("kcfg_ForceUnmountInaccessible"));

    QCheckBox *detectAllShares = new QCheckBox(Smb4KMountSettings::self()->detectAllSharesItem()->label(), behaviorBox);
    detectAllShares->setObjectName(QStringLiteral("kcfg_DetectAllShares"));

    behaviorBoxLayout->addWidget(remountShares, 0, 0, 1, 2);
    behaviorBoxLayout->addWidget(remountAttemptsLabel, 1, 0);
    behaviorBoxLayout->addWidget(remountAttempts, 1, 1);
    behaviorBoxLayout->addWidget(remountIntervalLabel, 2, 0);
    behaviorBoxLayout->addWidget(remountInterval, 2, 1);
    behaviorBoxLayout->addWidget(unmountAllShares, 3, 0, 1, 2);
    behaviorBoxLayout->addWidget(unmountInaccessibleShares, 4, 0, 1, 2);
    behaviorBoxLayout->addWidget(unmountForeignShares, 5, 0, 1, 2);
    behaviorBoxLayout->addWidget(detectAllShares, 6, 0, 1, 2);

    basicTabLayout->addWidget(behaviorBox, 0);
    basicTabLayout->addStretch(100);

    addTab(basicTab, i18n("Basic Settings"));

    //
    // Common Mount Settings tab
    //
    QWidget *commonTab = new QWidget(this);
    QVBoxLayout *commonTabLayout = new QVBoxLayout(commonTab);

    //
    // Common options group box
    //
    QGroupBox *commonOptions = new QGroupBox(i18n("Common Options"), commonTab);
    QGridLayout *commonOptionsLayout = new QGridLayout(commonOptions);

    // Write access
    QCheckBox *useWriteAccess = new QCheckBox(Smb4KMountSettings::self()->useWriteAccessItem()->label(), commonOptions);
    useWriteAccess->setObjectName(QStringLiteral("kcfg_UseWriteAccess"));

    KComboBox *writeAccess = new KComboBox(commonOptions);
    writeAccess->setObjectName(QStringLiteral("kcfg_WriteAccess"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> writeAccessChoices = Smb4KMountSettings::self()->writeAccessItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &wa : qAsConst(writeAccessChoices)) {
        writeAccess->addItem(wa.label);
    }

    commonOptionsLayout->addWidget(useWriteAccess, 0, 0);
    commonOptionsLayout->addWidget(writeAccess, 0, 1);

    // Character set
    QCheckBox *useCharacterSet = new QCheckBox(Smb4KMountSettings::self()->useClientCharsetItem()->label(), commonOptions);
    useCharacterSet->setObjectName(QStringLiteral("kcfg_UseClientCharset"));

    KComboBox *characterSet = new KComboBox(commonOptions);
    characterSet->setObjectName(QStringLiteral("kcfg_ClientCharset"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> charsetChoices = Smb4KMountSettings::self()->clientCharsetItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &c : qAsConst(charsetChoices)) {
        characterSet->addItem(c.label);
    }

    commonOptionsLayout->addWidget(useCharacterSet, 1, 0);
    commonOptionsLayout->addWidget(characterSet, 1, 1);

    // Remote filesystem port
    QCheckBox *useFilesystemPort = new QCheckBox(Smb4KMountSettings::self()->useRemoteFileSystemPortItem()->label(), commonOptions);
    useFilesystemPort->setObjectName(QStringLiteral("kcfg_UseRemoteFileSystemPort"));

    QSpinBox *filesystemPort = new QSpinBox(commonOptions);
    filesystemPort->setObjectName(QStringLiteral("kcfg_RemoteFileSystemPort"));

    commonOptionsLayout->addWidget(useFilesystemPort, 2, 0);
    commonOptionsLayout->addWidget(filesystemPort, 2, 1);

    commonTabLayout->addWidget(commonOptions, 0);

    //
    // CIFS Unix Extensions Support group box
    //
    QGroupBox *cifsExtensionSupportBox = new QGroupBox(i18n("CIFS Unix Extensions Support"), commonTab);
    QGridLayout *cifsExtensionSupportLayout = new QGridLayout(cifsExtensionSupportBox);

    // CIFS Unix extensions support
    QCheckBox *cifsExtensionsSupport = new QCheckBox(Smb4KMountSettings::self()->cifsUnixExtensionsSupportItem()->label(), cifsExtensionSupportBox);
    cifsExtensionsSupport->setObjectName(QStringLiteral("kcfg_CifsUnixExtensionsSupport"));

    cifsExtensionSupportLayout->addWidget(cifsExtensionsSupport, 0, 0, 1, 2);

    // User information
    QCheckBox *useUserId = new QCheckBox(Smb4KMountSettings::self()->useUserIdItem()->label(), cifsExtensionSupportBox);
    useUserId->setObjectName(QStringLiteral("kcfg_UseUserId"));

    QWidget *userIdInputWidget = new QWidget(cifsExtensionSupportBox);
    userIdInputWidget->setObjectName(QStringLiteral("UserIdInputWidget"));

    QGridLayout *userLayout = new QGridLayout(userIdInputWidget);
    userLayout->setContentsMargins(0, 0, 0, 0);

    KLineEdit *userId = new KLineEdit(userIdInputWidget);
    userId->setObjectName(QStringLiteral("kcfg_UserId"));
    userId->setAlignment(Qt::AlignRight);
    userId->setReadOnly(true);

    QToolButton *userChooser = new QToolButton(userIdInputWidget);
    userChooser->setIcon(KDE::icon(QStringLiteral("edit-find-user")));
    userChooser->setToolTip(i18n("Choose a different user"));
    userChooser->setPopupMode(QToolButton::InstantPopup);

    QMenu *userMenu = new QMenu(userChooser);
    userChooser->setMenu(userMenu);

    QList<KUser> allUsers = KUser::allUsers();

    for (const KUser &u : qAsConst(allUsers)) {
        QAction *userAction = userMenu->addAction(u.loginName() + QStringLiteral(" (") + u.userId().toString() + QStringLiteral(")"));
        userAction->setData(u.userId().nativeId());
    }

    userLayout->addWidget(userId, 0, 0);
    userLayout->addWidget(userChooser, 0, 1, Qt::AlignCenter);

    cifsExtensionSupportLayout->addWidget(useUserId, 1, 0);
    cifsExtensionSupportLayout->addWidget(userIdInputWidget, 1, 1);

    // Group information
    QCheckBox *useGroupId = new QCheckBox(Smb4KMountSettings::self()->useGroupIdItem()->label(), cifsExtensionSupportBox);
    useGroupId->setObjectName(QStringLiteral("kcfg_UseGroupId"));

    QWidget *groupIdInputWidget = new QWidget(cifsExtensionSupportBox);
    groupIdInputWidget->setObjectName(QStringLiteral("GroupIdInputWidget"));

    QGridLayout *groupLayout = new QGridLayout(groupIdInputWidget);
    groupLayout->setContentsMargins(0, 0, 0, 0);

    KLineEdit *groupId = new KLineEdit(groupIdInputWidget);
    groupId->setObjectName(QStringLiteral("kcfg_GroupId"));
    groupId->setAlignment(Qt::AlignRight);
    groupId->setReadOnly(true);

    QToolButton *groupChooser = new QToolButton(groupIdInputWidget);
    groupChooser->setIcon(KDE::icon(QStringLiteral("edit-find-user")));
    groupChooser->setToolTip(i18n("Choose a different group"));
    groupChooser->setPopupMode(QToolButton::InstantPopup);

    QMenu *groupMenu = new QMenu(groupChooser);
    groupChooser->setMenu(groupMenu);

    QList<KUserGroup> groupList = KUserGroup::allGroups();

    for (const KUserGroup &g : qAsConst(groupList)) {
        QAction *groupAction = groupMenu->addAction(g.name() + QStringLiteral(" (") + g.groupId().toString() + QStringLiteral(")"));
        groupAction->setData(g.groupId().nativeId());
    }

    groupLayout->addWidget(groupId, 0, 0);
    groupLayout->addWidget(groupChooser, 0, 1, Qt::AlignCenter);

    cifsExtensionSupportLayout->addWidget(useGroupId, 2, 0);
    cifsExtensionSupportLayout->addWidget(groupIdInputWidget, 2, 1);

    // File mask
    QCheckBox *useFileMode = new QCheckBox(Smb4KMountSettings::self()->useFileModeItem()->label(), cifsExtensionSupportBox);
    useFileMode->setObjectName(QStringLiteral("kcfg_UseFileMode"));

    KLineEdit *fileMode = new KLineEdit(cifsExtensionSupportBox);
    fileMode->setObjectName(QStringLiteral("kcfg_FileMode"));
    fileMode->setClearButtonEnabled(true);
    fileMode->setAlignment(Qt::AlignRight);

    cifsExtensionSupportLayout->addWidget(useFileMode, 3, 0);
    cifsExtensionSupportLayout->addWidget(fileMode, 3, 1);

    // Directory mask
    QCheckBox *useDirectoryMode = new QCheckBox(Smb4KMountSettings::self()->useDirectoryModeItem()->label(), cifsExtensionSupportBox);
    useDirectoryMode->setObjectName(QStringLiteral("kcfg_UseDirectoryMode"));

    KLineEdit *directoryMode = new KLineEdit(cifsExtensionSupportBox);
    directoryMode->setObjectName(QStringLiteral("kcfg_DirectoryMode"));
    directoryMode->setClearButtonEnabled(true);
    directoryMode->setAlignment(Qt::AlignRight);

    cifsExtensionSupportLayout->addWidget(useDirectoryMode, 4, 0);
    cifsExtensionSupportLayout->addWidget(directoryMode, 4, 1);

    commonTabLayout->addWidget(cifsExtensionSupportBox, 1);
    commonTabLayout->addStretch(100);

    addTab(commonTab, i18n("Common Mount Settings"));

    //
    // Advanced Mount Settings tab
    //
    QWidget *advancedTab = new QWidget(this);
    QVBoxLayout *advancedTabLayout = new QVBoxLayout(advancedTab);

    QGroupBox *advancedOptions = new QGroupBox(i18n("Advanced Options"), advancedTab);
    QGridLayout *advancedOptionsLayout = new QGridLayout(advancedOptions);

    // Force Uid
    QCheckBox *forceUid = new QCheckBox(Smb4KMountSettings::self()->forceUIDItem()->label(), advancedOptions);
    forceUid->setObjectName(QStringLiteral("kcfg_ForceUID"));

    advancedOptionsLayout->addWidget(forceUid, 0, 0);

    // Force Gid
    QCheckBox *forceGid = new QCheckBox(Smb4KMountSettings::self()->forceGIDItem()->label(), advancedOptions);
    forceGid->setObjectName(QStringLiteral("kcfg_ForceGID"));

    advancedOptionsLayout->addWidget(forceGid, 0, 1);

    // Permission checks
    QCheckBox *permissionChecks = new QCheckBox(Smb4KMountSettings::self()->permissionChecksItem()->label(), advancedOptions);
    permissionChecks->setObjectName(QStringLiteral("kcfg_PermissionChecks"));

    advancedOptionsLayout->addWidget(permissionChecks, 1, 0);

    // Client controls Ids
    QCheckBox *clientControlsIds = new QCheckBox(Smb4KMountSettings::self()->clientControlsIDsItem()->label(), advancedOptions);
    clientControlsIds->setObjectName(QStringLiteral("kcfg_ClientControlsIDs"));

    advancedOptionsLayout->addWidget(clientControlsIds, 1, 1);

    // Use server inode numbers
    QCheckBox *useServerInodes = new QCheckBox(Smb4KMountSettings::self()->serverInodeNumbersItem()->label(), advancedOptions);
    useServerInodes->setObjectName(QStringLiteral("kcfg_ServerInodeNumbers"));

    advancedOptionsLayout->addWidget(useServerInodes, 2, 0);

    // Translate reserved characters
    QCheckBox *translateReservedCharacters = new QCheckBox(Smb4KMountSettings::self()->translateReservedCharsItem()->label(), advancedOptions);
    translateReservedCharacters->setObjectName(QStringLiteral("kcfg_TranslateReservedChars"));

    advancedOptionsLayout->addWidget(translateReservedCharacters, 2, 1);

    // No locking
    QCheckBox *no_locking = new QCheckBox(Smb4KMountSettings::self()->noLockingItem()->label(), advancedOptions);
    no_locking->setObjectName(QStringLiteral("kcfg_NoLocking"));

    advancedOptionsLayout->addWidget(no_locking, 3, 0);

    // Extra widget for the rest of the options
    QWidget *advancedOptionsExtraWidget = new QWidget(advancedOptions);
    QGridLayout *advancedOptionsExtraWidgetLayout = new QGridLayout(advancedOptionsExtraWidget);
    advancedOptionsExtraWidgetLayout->setContentsMargins(0, 0, 0, 0);

    // SMB protocol version
    QCheckBox *useSmbProtocol = new QCheckBox(Smb4KMountSettings::self()->useSmbProtocolVersionItem()->label(), advancedOptionsExtraWidget);
    useSmbProtocol->setObjectName(QStringLiteral("kcfg_UseSmbProtocolVersion"));

    KComboBox *smbProtocol = new KComboBox(advancedOptionsExtraWidget);
    smbProtocol->setObjectName(QStringLiteral("kcfg_SmbProtocolVersion"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> smbProtocolChoices = Smb4KMountSettings::self()->smbProtocolVersionItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &c : qAsConst(smbProtocolChoices)) {
        smbProtocol->addItem(c.label);
    }

    advancedOptionsExtraWidgetLayout->addWidget(useSmbProtocol, 0, 0);
    advancedOptionsExtraWidgetLayout->addWidget(smbProtocol, 0, 1);

    // Cache mode
    QCheckBox *useCacheMode = new QCheckBox(Smb4KMountSettings::self()->useCacheModeItem()->label(), advancedOptionsExtraWidget);
    useCacheMode->setObjectName(QStringLiteral("kcfg_UseCacheMode"));

    KComboBox *cacheMode = new KComboBox(advancedOptionsExtraWidget);
    cacheMode->setObjectName(QStringLiteral("kcfg_CacheMode"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> cacheModeChoices = Smb4KMountSettings::self()->cacheModeItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &c : qAsConst(cacheModeChoices)) {
        cacheMode->addItem(c.label);
    }

    advancedOptionsExtraWidgetLayout->addWidget(useCacheMode, 1, 0);
    advancedOptionsExtraWidgetLayout->addWidget(cacheMode, 1, 1);

    // Security mode
    QCheckBox *useSecurityMode = new QCheckBox(Smb4KMountSettings::self()->useSecurityModeItem()->label(), advancedOptionsExtraWidget);
    useSecurityMode->setObjectName(QStringLiteral("kcfg_UseSecurityMode"));

    KComboBox *securityMode = new KComboBox(advancedOptionsExtraWidget);
    securityMode->setObjectName(QStringLiteral("kcfg_SecurityMode"));

    QList<KConfigSkeleton::ItemEnum::Choice> securityModeChoices = Smb4KMountSettings::self()->securityModeItem()->choices();

    for (const KConfigSkeleton::ItemEnum::Choice &c : qAsConst(securityModeChoices)) {
        securityMode->addItem(c.label);
    }

    advancedOptionsExtraWidgetLayout->addWidget(useSecurityMode, 2, 0);
    advancedOptionsExtraWidgetLayout->addWidget(securityMode, 2, 1);

    // Additional options
    QLabel *additionalOptionsLabel = new QLabel(Smb4KMountSettings::self()->customCIFSOptionsItem()->label(), advancedOptionsExtraWidget);

    QWidget *additionalOptionsWidget = new QWidget(advancedOptionsExtraWidget);
    QHBoxLayout *additionalOptionsWidgetLayout = new QHBoxLayout(additionalOptionsWidget);
    additionalOptionsWidgetLayout->setContentsMargins(0, 0, 0, 0);

    KLineEdit *additionalOptions = new KLineEdit(additionalOptionsWidget);
    additionalOptions->setObjectName(QStringLiteral("kcfg_CustomCIFSOptions"));
    additionalOptions->setReadOnly(true);
    additionalOptions->setClearButtonEnabled(true);
    additionalOptionsLabel->setBuddy(additionalOptions);

    QToolButton *additionalOptionsEdit = new QToolButton(advancedOptionsExtraWidget);
    additionalOptionsEdit->setIcon(KDE::icon(QStringLiteral("document-edit")));
    additionalOptionsEdit->setToolTip(i18n("Edit the additional CIFS options."));

    additionalOptionsWidgetLayout->addWidget(additionalOptions, 0);
    additionalOptionsWidgetLayout->addWidget(additionalOptionsEdit, 0);

    advancedOptionsExtraWidgetLayout->addWidget(additionalOptionsLabel, 3, 0);
    advancedOptionsExtraWidgetLayout->addWidget(additionalOptionsWidget, 3, 1);

    advancedOptionsLayout->addWidget(advancedOptionsExtraWidget, 4, 0, 1, 2);

    advancedTabLayout->addWidget(advancedOptions, 0);
    advancedTabLayout->addStretch(100);

    addTab(advancedTab, i18n("Advanced Mount Settings"));

    //
    // Adjust widgets
    //
    slotCIFSUnixExtensionsSupport(Smb4KMountSettings::cifsUnixExtensionsSupport());
    slotRemountSharesToggled(Smb4KMountSettings::remountShares());

    //
    // Connections
    //
    connect(userMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotNewUserTriggered(QAction *)));
    connect(groupMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotNewGroupTriggered(QAction *)));
    connect(cifsExtensionsSupport, SIGNAL(toggled(bool)), this, SLOT(slotCIFSUnixExtensionsSupport(bool)));
    connect(additionalOptionsEdit, SIGNAL(toggled(bool)), this, SLOT(slotAdditionalCIFSOptions()));
    connect(remountShares, SIGNAL(toggled(bool)), this, SLOT(slotRemountSharesToggled(bool)));
}
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
//
// FreeBSD and NetBSD
//
void Smb4KConfigPageMounting::setupWidget()
{
    //
    // Basic Settings tab
    //
    QWidget *basicTab = new QWidget(this);
    QVBoxLayout *basicTabLayout = new QVBoxLayout(basicTab);

    //
    // Directories
    //
    QGroupBox *directoryBox = new QGroupBox(i18n("Directories"), basicTab);
    QGridLayout *directoryBoxLayout = new QGridLayout(directoryBox);

    QLabel *prefixLabel = new QLabel(Smb4KMountSettings::self()->mountPrefixItem()->label(), directoryBox);
    KUrlRequester *prefix = new KUrlRequester(directoryBox);
    prefix->setMode(KFile::Directory | KFile::LocalOnly);
    prefix->setObjectName(QStringLiteral("kcfg_MountPrefix"));

    prefixLabel->setBuddy(prefix);

    QCheckBox *lowercaseSubdirs = new QCheckBox(Smb4KMountSettings::self()->forceLowerCaseSubdirsItem()->label(), directoryBox);
    lowercaseSubdirs->setObjectName(QStringLiteral("kcfg_ForceLowerCaseSubdirs"));

    directoryBoxLayout->addWidget(prefixLabel, 0, 0);
    directoryBoxLayout->addWidget(prefix, 0, 1);
    directoryBoxLayout->addWidget(lowercaseSubdirs, 1, 0, 1, 2);

    basicTabLayout->addWidget(directoryBox, 0);

    //
    // Behavior
    //
    QGroupBox *behaviorBox = new QGroupBox(i18n("Behavior"), basicTab);
    QGridLayout *behaviorBoxLayout = new QGridLayout(behaviorBox);

    QCheckBox *remountShares = new QCheckBox(Smb4KMountSettings::self()->remountSharesItem()->label(), behaviorBox);
    remountShares->setObjectName(QStringLiteral("kcfg_RemountShares"));

    QLabel *remountAttemptsLabel = new QLabel(Smb4KMountSettings::self()->remountAttemptsItem()->label(), behaviorBox);
    remountAttemptsLabel->setObjectName(QStringLiteral("RemountAttemptsLabel"));
    remountAttemptsLabel->setIndent(25);

    QSpinBox *remountAttempts = new QSpinBox(behaviorBox);
    remountAttempts->setObjectName(QStringLiteral("kcfg_RemountAttempts"));
    remountAttemptsLabel->setBuddy(remountAttempts);

    QLabel *remountIntervalLabel = new QLabel(Smb4KMountSettings::self()->remountIntervalItem()->label(), behaviorBox);
    remountIntervalLabel->setObjectName(QStringLiteral("RemountIntervalLabel"));
    remountIntervalLabel->setIndent(25);

    QSpinBox *remountInterval = new QSpinBox(behaviorBox);
    remountInterval->setObjectName(QStringLiteral("kcfg_RemountInterval"));
    remountInterval->setSuffix(i18n(" min"));
    remountIntervalLabel->setBuddy(remountInterval);

    QCheckBox *unmountAllShares = new QCheckBox(Smb4KMountSettings::self()->unmountSharesOnExitItem()->label(), behaviorBox);
    unmountAllShares->setObjectName(QStringLiteral("kcfg_UnmountSharesOnExit"));

    QCheckBox *unmountForeignShares = new QCheckBox(Smb4KMountSettings::self()->unmountForeignSharesItem()->label(), behaviorBox);
    unmountForeignShares->setObjectName(QStringLiteral("kcfg_UnmountForeignShares"));

    QCheckBox *detectAllShares = new QCheckBox(Smb4KMountSettings::self()->detectAllSharesItem()->label(), behaviorBox);
    detectAllShares->setObjectName(QStringLiteral("kcfg_DetectAllShares"));

    behaviorBoxLayout->addWidget(remountShares, 0, 0, 1, 2);
    behaviorBoxLayout->addWidget(remountAttemptsLabel, 1, 0);
    behaviorBoxLayout->addWidget(remountAttempts, 1, 1);
    behaviorBoxLayout->addWidget(remountIntervalLabel, 2, 0);
    behaviorBoxLayout->addWidget(remountInterval, 2, 1);
    behaviorBoxLayout->addWidget(unmountAllShares, 3, 0, 1, 2);
    behaviorBoxLayout->addWidget(unmountForeignShares, 4, 0, 1, 2);
    behaviorBoxLayout->addWidget(detectAllShares, 5, 0, 1, 2);

    basicTabLayout->addWidget(behaviorBox, 0);
    basicTabLayout->addStretch(100);

    addTab(basicTab, i18n("Basic Settings"));

    //
    // Mount Settings tab
    //
    QWidget *mountTab = new QWidget(this);
    QVBoxLayout *mountTabLayout = new QVBoxLayout(mountTab);

    //
    // Common Options
    //
    QGroupBox *commonOptionsBox = new QGroupBox(i18n("Common Options"), mountTab);
    QGridLayout *commonOptionsBoxLayout = new QGridLayout(commonOptionsBox);

    // User information
    QCheckBox *useUserId = new QCheckBox(Smb4KMountSettings::self()->useUserIdItem()->label(), commonOptionsBox);
    useUserId->setObjectName(QStringLiteral("kcfg_UseUserId"));

    QWidget *userIdInputWidget = new QWidget(commonOptionsBox);
    userIdInputWidget->setObjectName(QStringLiteral("UserIdInputWidget"));

    QGridLayout *userLayout = new QGridLayout(userIdInputWidget);
    userLayout->setContentsMargins(0, 0, 0, 0);

    KLineEdit *userId = new KLineEdit(userIdInputWidget);
    userId->setObjectName(QStringLiteral("kcfg_UserId"));
    userId->setAlignment(Qt::AlignRight);
    userId->setReadOnly(true);

    QToolButton *userChooser = new QToolButton(userIdInputWidget);
    userChooser->setIcon(KDE::icon(QStringLiteral("edit-find-user")));
    userChooser->setToolTip(i18n("Choose a different user"));
    userChooser->setPopupMode(QToolButton::InstantPopup);

    QMenu *userMenu = new QMenu(userChooser);
    userChooser->setMenu(userMenu);

    QList<KUser> allUsers = KUser::allUsers();

    for (const KUser &u : allUsers) {
        QAction *userAction = userMenu->addAction(u.loginName() + QStringLiteral(" (") + u.userId().toString() + QStringLiteral(")"));
        userAction->setData(u.userId().nativeId());
    }

    userLayout->addWidget(userId, 0, 0);
    userLayout->addWidget(userChooser, 0, 1, Qt::AlignCenter);

    commonOptionsBoxLayout->addWidget(useUserId, 0, 0);
    commonOptionsBoxLayout->addWidget(userIdInputWidget, 0, 1);

    // Group information
    QCheckBox *useGroupId = new QCheckBox(Smb4KMountSettings::self()->useGroupIdItem()->label(), commonOptionsBox);
    useGroupId->setObjectName(QStringLiteral("kcfg_UseGroupId"));

    QWidget *groupIdInputWidget = new QWidget(commonOptionsBox);
    groupIdInputWidget->setObjectName(QStringLiteral("GroupIdInputWidget"));

    QGridLayout *groupLayout = new QGridLayout(groupIdInputWidget);
    groupLayout->setContentsMargins(0, 0, 0, 0);

    KLineEdit *groupId = new KLineEdit(groupIdInputWidget);
    groupId->setObjectName(QStringLiteral("kcfg_GroupId"));
    groupId->setAlignment(Qt::AlignRight);
    groupId->setReadOnly(true);

    QToolButton *groupChooser = new QToolButton(groupIdInputWidget);
    groupChooser->setIcon(KDE::icon(QStringLiteral("edit-find-user")));
    groupChooser->setToolTip(i18n("Choose a different group"));
    groupChooser->setPopupMode(QToolButton::InstantPopup);

    QMenu *groupMenu = new QMenu(groupChooser);
    groupChooser->setMenu(groupMenu);

    QList<KUserGroup> groupList = KUserGroup::allGroups();

    for (const KUserGroup &g : groupList) {
        QAction *groupAction = groupMenu->addAction(g.name() + QStringLiteral(" (") + g.groupId().toString() + QStringLiteral(")"));
        groupAction->setData(g.groupId().nativeId());
    }

    groupLayout->addWidget(groupId, 0, 0);
    groupLayout->addWidget(groupChooser, 0, 1, Qt::AlignCenter);

    commonOptionsBoxLayout->addWidget(useGroupId, 1, 0);
    commonOptionsBoxLayout->addWidget(groupIdInputWidget, 1, 1);

    // File mask
    QCheckBox *useFileMode = new QCheckBox(Smb4KMountSettings::self()->useFileModeItem()->label(), commonOptionsBox);
    useFileMode->setObjectName(QStringLiteral("kcfg_UseFileMode"));

    KLineEdit *fileMode = new KLineEdit(commonOptionsBox);
    fileMode->setObjectName(QStringLiteral("kcfg_FileMode"));
    fileMode->setClearButtonEnabled(true);
    fileMode->setAlignment(Qt::AlignRight);

    commonOptionsBoxLayout->addWidget(useFileMode, 2, 0);
    commonOptionsBoxLayout->addWidget(fileMode, 2, 1);

    // Directory mask
    QCheckBox *useDirectoryMode = new QCheckBox(Smb4KMountSettings::self()->useDirectoryModeItem()->label(), commonOptionsBox);
    useDirectoryMode->setObjectName(QStringLiteral("kcfg_UseDirectoryMode"));

    KLineEdit *directoryMode = new KLineEdit(commonOptionsBox);
    directoryMode->setObjectName(QStringLiteral("kcfg_DirectoryMode"));
    directoryMode->setClearButtonEnabled(true);
    directoryMode->setAlignment(Qt::AlignRight);

    commonOptionsBoxLayout->addWidget(useDirectoryMode, 3, 0);
    commonOptionsBoxLayout->addWidget(directoryMode, 3, 1);

    //
    // Character sets
    //
    QGroupBox *characterSetsBox = new QGroupBox(i18n("Character Sets"), mountTab);
    QGridLayout *characterSetsBoxLayout = new QGridLayout(characterSetsBox);

    // Client character set
    QCheckBox *useCharacterSets = new QCheckBox(Smb4KMountSettings::self()->useCharacterSetsItem()->label(), characterSetsBox);
    useCharacterSets->setObjectName(QStringLiteral("kcfg_UseCharacterSets"));

    QLabel *clientCharacterSetLabel = new QLabel(Smb4KMountSettings::self()->clientCharsetItem()->label(), characterSetsBox);
    clientCharacterSetLabel->setIndent(25);
    clientCharacterSetLabel->setObjectName(QStringLiteral("ClientCharacterSetLabel"));

    KComboBox *clientCharacterSet = new KComboBox(characterSetsBox);
    clientCharacterSet->setObjectName(QStringLiteral("kcfg_ClientCharset"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> charsetChoices = Smb4KMountSettings::self()->clientCharsetItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &c : charsetChoices) {
        clientCharacterSet->addItem(c.label);
    }

    clientCharacterSetLabel->setBuddy(clientCharacterSet);

    // Server character set
    QLabel *serverCharacterSetLabel = new QLabel(Smb4KMountSettings::self()->serverCodepageItem()->label(), characterSetsBox);
    serverCharacterSetLabel->setIndent(25);
    serverCharacterSetLabel->setObjectName(QStringLiteral("ServerCodepageLabel"));

    KComboBox *serverCharacterSet = new KComboBox(characterSetsBox);
    serverCharacterSet->setObjectName(QStringLiteral("kcfg_ServerCodepage"));

    QList<KCoreConfigSkeleton::ItemEnum::Choice> codepageChoices = Smb4KMountSettings::self()->serverCodepageItem()->choices();

    for (const KCoreConfigSkeleton::ItemEnum::Choice &c : codepageChoices) {
        serverCharacterSet->addItem(c.label);
    }

    serverCharacterSetLabel->setBuddy(serverCharacterSet);

    characterSetsBoxLayout->addWidget(useCharacterSets, 0, 0, 1, 2);
    characterSetsBoxLayout->addWidget(clientCharacterSetLabel, 1, 0);
    characterSetsBoxLayout->addWidget(clientCharacterSet, 1, 1);
    characterSetsBoxLayout->addWidget(serverCharacterSetLabel, 2, 0);
    characterSetsBoxLayout->addWidget(serverCharacterSet, 2, 1);

    mountTabLayout->addWidget(commonOptionsBox, 0);
    mountTabLayout->addWidget(characterSetsBox, 0);
    mountTabLayout->addStretch(100);

    addTab(mountTab, i18n("Mount Settings"));

    //
    // Connections
    //
    connect(userMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotNewUserTriggered(QAction *)));
    connect(groupMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotNewGroupTriggered(QAction *)));
    connect(useCharacterSets, SIGNAL(toggled(bool)), this, SLOT(slotCharacterSets(bool)));
    connect(remountShares, SIGNAL(toggled(bool)), this, SLOT(slotRemountSharesToggled(bool)));

    //
    // Enable / disable widgets
    //
    slotCharacterSets(Smb4KMountSettings::useCharacterSets());
    slotRemountSharesToggled(Smb4KMountSettings::remountShares());
}
#else
//
// Dummy
//
void Smb4KConfigPageMounting::setupWidget()
{
}
#endif

void Smb4KConfigPageMounting::slotNewUserTriggered(QAction *action)
{
    KLineEdit *userId = findChild<KLineEdit *>(QStringLiteral("kcfg_UserId"));

    if (userId) {
        userId->setText(action->data().toString());
    }
}

void Smb4KConfigPageMounting::slotNewGroupTriggered(QAction *action)
{
    KLineEdit *groupId = findChild<KLineEdit *>(QStringLiteral("kcfg_GroupId"));

    if (groupId) {
        groupId->setText(action->data().toString());
    }
}

void Smb4KConfigPageMounting::slotCIFSUnixExtensionsSupport(bool checked)
{
    QCheckBox *useUserId = findChild<QCheckBox *>(QStringLiteral("kcfg_UseUserId"));

    if (useUserId) {
        useUserId->setEnabled(!checked);
    }

    QWidget *userIdInputWidget = findChild<QWidget *>(QStringLiteral("UserIdInputWidget"));

    if (userIdInputWidget) {
        userIdInputWidget->setEnabled(!checked);
    }

    QCheckBox *useGroupId = findChild<QCheckBox *>(QStringLiteral("kcfg_UseGroupId"));

    if (useGroupId) {
        useGroupId->setEnabled(!checked);
    }

    QWidget *groupIdInputWidget = findChild<QWidget *>(QStringLiteral("GroupIdInputWidget"));

    if (groupIdInputWidget) {
        groupIdInputWidget->setEnabled(!checked);
    }

    QCheckBox *useFileMode = findChild<QCheckBox *>(QStringLiteral("kcfg_UseFileMode"));

    if (useFileMode) {
        useFileMode->setEnabled(!checked);
    }

    KLineEdit *fileMode = findChild<KLineEdit *>(QStringLiteral("kcfg_FileMode"));

    if (fileMode) {
        fileMode->setEnabled(!checked);
    }

    QCheckBox *useDirectoryMode = findChild<QCheckBox *>(QStringLiteral("kcfg_UseDirectoryMode"));

    if (useDirectoryMode) {
        useDirectoryMode->setEnabled(!checked);
    }

    KLineEdit *directoryMode = findChild<KLineEdit *>(QStringLiteral("kcfg_DirectoryMode"));

    if (directoryMode) {
        directoryMode->setEnabled(!checked);
    }
}

void Smb4KConfigPageMounting::slotAdditionalCIFSOptions()
{
#if defined(Q_OS_LINUX)
    KLineEdit *cifsOptions = findChild<KLineEdit *>(QStringLiteral("kcfg_CustomCIFSOptions"));

    if (cifsOptions) {
        QString options = cifsOptions->originalText();

        bool ok = false;
        options = QInputDialog::getText(this,
                                        i18n("Additional CIFS Options"),
                                        i18n("<qt>Enter the desired options as a comma separated list:</qt>"),
                                        QLineEdit::Normal,
                                        options,
                                        &ok);

        if (ok) {
            if (!options.trimmed().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 allowedArgs = allowedMountArguments();
                QStringList deniedArgs;
                QStringList list = options.split(QStringLiteral(","), Qt::SkipEmptyParts);
                QMutableStringListIterator it(list);

                while (it.hasNext()) {
                    QString arg = it.next().section(QStringLiteral("="), 0, 0);

                    if (!allowedArgs.contains(arg)) {
                        deniedArgs << arg;
                        it.remove();
                    }
                }

                if (!deniedArgs.isEmpty()) {
                    QString msg = i18np(
                        "<qt>The following entry is going to be removed from the additional options: %2. Please read the handbook for details.</qt>",
                        "<qt>The following %1 entries are going to be removed from the additional options: %2. Please read the handbook for details.</qt>",
                        deniedArgs.size(),
                        deniedArgs.join(QStringLiteral(", ")));
                    KMessageBox::information(this, msg);
                }

                cifsOptions->setText(list.join(QStringLiteral(",")).trimmed());
            } else {
                cifsOptions->clear();
            }
        }
    }
#endif
}

void Smb4KConfigPageMounting::slotCharacterSets(bool on)
{
    //
    // Client character set
    //
    QLabel *clientCharacterSetLabel = findChild<QLabel *>(QStringLiteral("ClientCharacterSetLabel"));

    if (clientCharacterSetLabel) {
        clientCharacterSetLabel->setEnabled(on);
    }

    KComboBox *clientCharacterSet = findChild<KComboBox *>(QStringLiteral("kcfg_ClientCharset"));

    if (clientCharacterSet) {
        clientCharacterSet->setEnabled(on);
    }

    //
    // Server character set
    //
    QLabel *serverCharacterSetLabel = findChild<QLabel *>(QStringLiteral("ServerCodepageLabel"));

    if (serverCharacterSetLabel) {
        serverCharacterSetLabel->setEnabled(on);
    }

    KComboBox *serverCharacterSet = findChild<KComboBox *>(QStringLiteral("kcfg_ServerCodepage"));

    if (serverCharacterSet) {
        serverCharacterSet->setEnabled(on);
    }
}

void Smb4KConfigPageMounting::slotRemountSharesToggled(bool on)
{
    //
    // Get the widget
    //
    QLabel *remountAttemptsLabel = findChild<QLabel *>(QStringLiteral("RemountAttemptsLabel"));
    QSpinBox *remountAttempts = findChild<QSpinBox *>(QStringLiteral("kcfg_RemountAttempts"));
    QLabel *remountIntervalLabel = findChild<QLabel *>(QStringLiteral("RemountIntervalLabel"));
    QSpinBox *remountInterval = findChild<QSpinBox *>(QStringLiteral("kcfg_RemountInterval"));

    //
    // Enable / disable the widgets
    //
    remountAttemptsLabel->setEnabled(on);
    remountAttempts->setEnabled(on);
    remountIntervalLabel->setEnabled(on);
    remountInterval->setEnabled(on);
}
