File indexing completed on 2024-12-22 05:17:22

0001 // SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
0002 //
0003 // SPDX-License-Identifier: LGPL-2.0-or-later
0004 
0005 #include "mobilefiledialog.h"
0006 
0007 #include <QGuiApplication>
0008 #include <QQmlApplicationEngine>
0009 #include <QQmlContext>
0010 #include <QQuickWindow>
0011 #include <QStandardPaths>
0012 
0013 #include <KLocalizedContext>
0014 #include <KLocalizedString>
0015 
0016 #include "dirmodel.h"
0017 #include "dirmodelutils.h"
0018 #include "fileplacesmodel.h"
0019 #include "mobilefiledialog_debug.h"
0020 
0021 #include "filechooserqmlcallback.h"
0022 
0023 constexpr auto URI = "org.kde.kirigamifilepicker";
0024 
0025 MobileFileDialog::MobileFileDialog(QObject *parent)
0026     : QObject(parent)
0027     , m_engine(new QQmlApplicationEngine(this))
0028     , m_window(nullptr)
0029     , m_customTitleSet(false)
0030 {
0031     qmlRegisterType<DirModel>(URI, 0, 1, "DirModel");
0032     qmlRegisterSingletonType<DirModelUtils>(URI, 0, 1, "DirModelUtils", [=](QQmlEngine *, QJSEngine *) {
0033         return new DirModelUtils;
0034     });
0035     qmlRegisterType<FileChooserQmlCallback>(URI, 0, 1, "FileChooserCallback");
0036     qmlRegisterType<FilePlacesModel>(URI, 0, 1, "FilePlacesModel");
0037 
0038     Q_INIT_RESOURCE(filepicker);
0039 
0040     auto *i18nContext = new KLocalizedContext(m_engine);
0041     m_engine->rootContext()->setContextObject(i18nContext);
0042 
0043     m_engine->load(QStringLiteral("qrc:/org.kde.kirigamifilepicker/FilePickerWindow.qml"));
0044     m_window = qobject_cast<QQuickWindow *>(m_engine->rootObjects().first());
0045     m_callback = m_window->findChild<FileChooserQmlCallback *>(QStringLiteral("callback"));
0046 
0047     // Connect everything to callback
0048     connect(m_callback, &FileChooserQmlCallback::accepted, this, &MobileFileDialog::accepted);
0049     connect(m_callback, &FileChooserQmlCallback::cancel, this, &MobileFileDialog::cancel);
0050     connect(m_callback, &FileChooserQmlCallback::titleChanged, this, &MobileFileDialog::titleChanged);
0051     connect(m_callback, &FileChooserQmlCallback::selectMultipleChanged, this, &MobileFileDialog::selectMultipleChanged);
0052     connect(m_callback, &FileChooserQmlCallback::selectExistingChanged, this, &MobileFileDialog::selectExistingChanged);
0053     connect(m_callback, &FileChooserQmlCallback::nameFiltersChanged, this, &MobileFileDialog::nameFiltersChanged);
0054     connect(m_callback, &FileChooserQmlCallback::mimeTypeFiltersChanged, this, &MobileFileDialog::mimeTypeFiltersChanged);
0055     connect(m_callback, &FileChooserQmlCallback::folderChanged, this, &MobileFileDialog::folderChanged);
0056     connect(m_callback, &FileChooserQmlCallback::currentFileChanged, this, &MobileFileDialog::currentFileChanged);
0057     connect(m_callback, &FileChooserQmlCallback::acceptLabelChanged, this, &MobileFileDialog::acceptLabelChanged);
0058     connect(m_callback, &FileChooserQmlCallback::selectFolderChanged, this, &MobileFileDialog::selectFolderChanged);
0059 
0060     // Set default path for file dialog
0061     setFolder(QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)));
0062 }
0063 
0064 // FileDialog methods pass through to the callback to provide a nice c++ api
0065 QString MobileFileDialog::title() const
0066 {
0067     return m_callback->title();
0068 }
0069 
0070 void MobileFileDialog::setTitle(const QString &title)
0071 {
0072     // Don't accept an empty titles
0073     if (!title.isEmpty()) {
0074         m_customTitleSet = true;
0075         m_callback->setTitle(title);
0076     }
0077 }
0078 
0079 bool MobileFileDialog::selectMultiple() const
0080 {
0081     return m_callback->selectMultiple();
0082 }
0083 
0084 void MobileFileDialog::setSelectMultiple(bool selectMultiple)
0085 {
0086     m_callback->setSelectMultiple(selectMultiple);
0087 }
0088 
0089 bool MobileFileDialog::selectExisting() const
0090 {
0091     return m_callback->selectExisting();
0092 }
0093 
0094 void MobileFileDialog::setSelectExisting(bool selectExisting)
0095 {
0096     m_callback->setSelectExisting(selectExisting);
0097 
0098     // Detect that no custom title is set
0099     if (!m_customTitleSet) {
0100         if (selectFolder()) {
0101             setTitle(i18n("Select Folder"));
0102         } else {
0103             if (selectExisting) {
0104                 setTitle(i18n("Open File"));
0105             } else {
0106                 setTitle(i18n("Save File"));
0107             }
0108         }
0109     }
0110 }
0111 
0112 QStringList MobileFileDialog::nameFilters() const
0113 {
0114     return m_callback->nameFilters();
0115 }
0116 
0117 void MobileFileDialog::setNameFilters(const QStringList &nameFilters)
0118 {
0119     m_callback->setNameFilters(nameFilters);
0120 }
0121 
0122 QStringList MobileFileDialog::mimeTypeFilters() const
0123 {
0124     return m_callback->mimeTypeFilters();
0125 }
0126 
0127 void MobileFileDialog::setMimeTypeFilters(const QStringList &mimeTypeFilters)
0128 {
0129     m_callback->setMimeTypeFilters(mimeTypeFilters);
0130 }
0131 
0132 QUrl MobileFileDialog::folder() const
0133 {
0134     return m_callback->folder();
0135 }
0136 
0137 void MobileFileDialog::setFolder(const QUrl &folder)
0138 {
0139     m_callback->setFolder(folder);
0140 }
0141 
0142 QString MobileFileDialog::currentFile() const
0143 {
0144     return m_callback->currentFile();
0145 }
0146 
0147 void MobileFileDialog::setCurrentFile(const QString &currentFile)
0148 {
0149     m_callback->setCurrentFile(currentFile);
0150 }
0151 
0152 QString MobileFileDialog::acceptLabel() const
0153 {
0154     return m_callback->acceptLabel();
0155 }
0156 
0157 void MobileFileDialog::setAcceptLabel(const QString &acceptLabel)
0158 {
0159     m_callback->setAcceptLabel(acceptLabel);
0160 }
0161 
0162 bool MobileFileDialog::selectFolder() const
0163 {
0164     return m_callback->selectFolder();
0165 }
0166 
0167 void MobileFileDialog::setSelectFolder(bool selectFolder)
0168 {
0169     m_callback->setSelectFolder(selectFolder);
0170 }
0171 
0172 uint MobileFileDialog::exec()
0173 {
0174     // Show window
0175     m_window->setVisible(true);
0176     m_window->raise();
0177     m_window->requestActivate();
0178     m_window->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager")));
0179 
0180     // Reset old data
0181     m_results.clear();
0182 
0183     uint exitCode = 0;
0184 
0185     const auto acceptedConn = connect(m_callback, &FileChooserQmlCallback::accepted, this, [this, &exitCode](const QList<QUrl> &urls) {
0186         m_results = urls;
0187         exitCode = 0;
0188         qDebug(KirigamiFilepicker) << "Got results" << m_results;
0189     });
0190     const auto cancelConn = connect(m_callback, &FileChooserQmlCallback::cancel, this, [&exitCode] {
0191         qDebug(KirigamiFilepicker) << "Quit without results";
0192         exitCode = 1;
0193     });
0194 
0195     QEventLoop loop;
0196 
0197     connect(this, &MobileFileDialog::accepted, &loop, &QEventLoop::quit);
0198     connect(this, &MobileFileDialog::cancel, &loop, &QEventLoop::quit);
0199 
0200     loop.exec();
0201 
0202     qDebug(KirigamiFilepicker) << "exiting file dialog";
0203 
0204     // Disconnect signals, to avoid them being connected twice
0205     // when the dialog is used again
0206     disconnect(acceptedConn);
0207     disconnect(cancelConn);
0208 
0209     if (m_window) {
0210         m_window->setVisible(false);
0211     }
0212 
0213     return exitCode;
0214 }
0215 
0216 QList<QUrl> MobileFileDialog::results() const
0217 {
0218     return m_results;
0219 }
0220 
0221 #include "moc_mobilefiledialog.cpp"