mainwindow.cpp 10.2 KB
Newer Older
1 2 3
/*
 * ark -- archiver for the KDE project
 *
4
 * Copyright (C) 2002-2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de>
5 6 7
 * Copyright (C) 2003: Helio Chissini de Castro <helio@conectiva.com>
 * Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
 * Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * 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, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */
24

Henrique Pinto's avatar
Henrique Pinto committed
25
#include "mainwindow.h"
26
#include "ark_debug.h"
27
#include "kerfuffle/archive_kerfuffle.h"
28
#include "kerfuffle/createdialog.h"
29
#include "kerfuffle/settingspage.h"
30
#include "mimetypes.h"
31
#include "part/interface.h"
Henrique Pinto's avatar
Henrique Pinto committed
32

33
#include <KPluginFactory>
Henrique Pinto's avatar
Henrique Pinto committed
34
#include <KMessageBox>
35
#include <KLocalizedString>
Henrique Pinto's avatar
Henrique Pinto committed
36 37
#include <KActionCollection>
#include <KStandardAction>
38
#include <KRecentFilesAction>
39 40
#include <KEditToolBar>
#include <KShortcutsDialog>
Bhushan Shah's avatar
Bhushan Shah committed
41
#include <KService>
42
#include <KSharedConfig>
43
#include <KConfigDialog>
Bhushan Shah's avatar
Bhushan Shah committed
44
#include <KConfigGroup>
45
#include <KConfigSkeleton>
46
#include <KXMLGUIFactory>
Henrique Pinto's avatar
Henrique Pinto committed
47

48
#include <QApplication>
49
#include <QDebug>
50 51
#include <QDragEnterEvent>
#include <QDragMoveEvent>
Lukáš Tinkl's avatar
Lukáš Tinkl committed
52 53
#include <QFileDialog>
#include <QMimeData>
54
#include <QPointer>
55
#include <QRegularExpression>
Elvis Angelaccio's avatar
Elvis Angelaccio committed
56
#include <QStatusBar>
57

58 59
static bool isValidArchiveDrag(const QMimeData *data)
{
60
    return ((data->hasUrls()) && (data->urls().count() == 1));
61 62
}

63 64
MainWindow::MainWindow(QWidget *)
        : KParts::MainWindow()
Henrique Pinto's avatar
Henrique Pinto committed
65
{
66
    setXMLFile(QStringLiteral("arkui.rc"));
Henrique Pinto's avatar
Henrique Pinto committed
67

68
    setupActions();
Henrique Pinto's avatar
Henrique Pinto committed
69

70 71
    resize(640, 480);

72
    setAutoSaveSettings(QStringLiteral("MainWindow"));
73

74
    setAcceptDrops(true);
Henrique Pinto's avatar
Henrique Pinto committed
75 76 77 78
}

MainWindow::~MainWindow()
{
79
    if (m_recentFilesAction) {
Laurent Montel's avatar
Laurent Montel committed
80
        m_recentFilesAction->saveEntries(KSharedConfig::openConfig()->group("Recent Files"));
81
    }
82 83

    guiFactory()->removeClient(m_part);
84 85
    delete m_part;
    m_part = 0;
Henrique Pinto's avatar
Henrique Pinto committed
86 87
}

88
void MainWindow::dragEnterEvent(QDragEnterEvent * event)
89
{
90
    qCDebug(ARK) << "dragEnterEvent" << event;
91

92
    Interface *iface = qobject_cast<Interface*>(m_part);
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
93 94 95
    if (iface->isBusy()) {
        return;
    }
96

Lukáš Tinkl's avatar
Lukáš Tinkl committed
97
    if (!event->source() && isValidArchiveDrag(event->mimeData())) {
98
        event->acceptProposedAction();
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
99
    }
100
    return;
101 102
}

103
void MainWindow::dropEvent(QDropEvent * event)
104
{
105
    qCDebug(ARK) << "dropEvent" << event;
106

107
    Interface *iface = qobject_cast<Interface*>(m_part);
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
108 109 110
    if (iface->isBusy()) {
        return;
    }
111

Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
112 113
    if ((event->source() == NULL) &&
        (isValidArchiveDrag(event->mimeData()))) {
114
        event->acceptProposedAction();
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
115
    }
116 117 118 119

    //TODO: if this call provokes a message box the drag will still be going
    //while the box is onscreen. looks buggy, do something about it
    openUrl(event->mimeData()->urls().at(0));
120 121
}

122
void MainWindow::dragMoveEvent(QDragMoveEvent * event)
123
{
124
    qCDebug(ARK) << "dragMoveEvent" << event;
125

126
    Interface *iface = qobject_cast<Interface*>(m_part);
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
127 128 129
    if (iface->isBusy()) {
        return;
    }
130

Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
131 132
    if ((event->source() == NULL) &&
        (isValidArchiveDrag(event->mimeData()))) {
133
        event->acceptProposedAction();
Raphael Kubo da Costa's avatar
Raphael Kubo da Costa committed
134
    }
135 136
}

137 138
bool MainWindow::loadPart()
{
Bhushan Shah's avatar
Bhushan Shah committed
139
    KPluginFactory *factory = 0;
140
    KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("ark_part"));
Bhushan Shah's avatar
Bhushan Shah committed
141 142 143

    if (service) {
        factory = KPluginLoader(service->library()).factory();
144
    }
Bhushan Shah's avatar
Bhushan Shah committed
145 146 147 148

    m_part = factory ? static_cast<KParts::ReadWritePart*>(factory->create<KParts::ReadWritePart>(this)) : 0;

    if (!m_part) {
149
        KMessageBox::error(this, i18n("Unable to find Ark's KPart component, please check your installation."));
150
        qCWarning(ARK) << "Error loading Ark KPart.";
151 152
        return false;
    }
153

154
    m_part->setObjectName(QStringLiteral("ArkPart"));
155 156
    setCentralWidget(m_part->widget());
    createGUI(m_part);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
157
    statusBar()->hide();
158

159 160
    connect(m_part, SIGNAL(busy()), this, SLOT(updateActions()));
    connect(m_part, SIGNAL(ready()), this, SLOT(updateActions()));
161
    connect(m_part, SIGNAL(quit()), this, SLOT(quit()));
162

163
    return true;
164 165
}

Henrique Pinto's avatar
Henrique Pinto committed
166 167
void MainWindow::setupActions()
{
168 169 170 171 172 173
    m_newAction = actionCollection()->addAction(KStandardAction::New, QStringLiteral("ark_file_new"), this, SLOT(newArchive()));
    m_openAction = actionCollection()->addAction(KStandardAction::Open, QStringLiteral("ark_file_open"), this, SLOT(openArchive()));
    actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("ark_quit"), this, SLOT(quit()));

    m_recentFilesAction = KStandardAction::openRecent(this, SLOT(openUrl(QUrl)), Q_NULLPTR);
    actionCollection()->addAction(QStringLiteral("ark_file_open_recent"), m_recentFilesAction);
174

175 176 177 178
    m_recentFilesAction->setToolBarMode(KRecentFilesAction::MenuMode);
    m_recentFilesAction->setToolButtonPopupMode(QToolButton::DelayedPopup);
    m_recentFilesAction->setIconText(i18nc("action, to open an archive", "Open"));
    m_recentFilesAction->setToolTip(i18n("Open an archive"));
Laurent Montel's avatar
Laurent Montel committed
179
    m_recentFilesAction->loadEntries(KSharedConfig::openConfig()->group("Recent Files"));
180 181
    connect(m_recentFilesAction, SIGNAL(triggered()),
            this, SLOT(openArchive()));
182

183 184
    KStandardAction::configureToolbars(this, SLOT(editToolbars()), actionCollection());
    KStandardAction::keyBindings(this, SLOT(editKeyBindings()), actionCollection());
185
    KStandardAction::preferences(this, SLOT(showSettings()), actionCollection());
186 187
}

188 189
void MainWindow::updateActions()
{
190 191 192 193
    Interface *iface = qobject_cast<Interface*>(m_part);
    m_newAction->setEnabled(!iface->isBusy());
    m_openAction->setEnabled(!iface->isBusy());
    m_recentFilesAction->setEnabled(!iface->isBusy());
194 195
}

196 197
void MainWindow::editKeyBindings()
{
198 199 200
    KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this);
    dlg.addCollection(actionCollection());
    dlg.addCollection(m_part->actionCollection());
201

202
    dlg.configure();
203 204 205 206
}

void MainWindow::editToolbars()
{
Bhushan Shah's avatar
Bhushan Shah committed
207 208
    KConfigGroup cfg(KSharedConfig::openConfig(), "MainWindow");
    saveMainWindowSettings(cfg);
209

210
    QPointer<KEditToolBar> dlg = new KEditToolBar(factory(), this);
211
    dlg.data()->exec();
212

213
    createGUI(m_part);
214

215
    applyMainWindowSettings(KSharedConfig::openConfig()->group(QStringLiteral("MainWindow")));
216

217
    delete dlg.data();
Henrique Pinto's avatar
Henrique Pinto committed
218 219 220 221
}

void MainWindow::openArchive()
{
222 223
    Interface *iface = qobject_cast<Interface*>(m_part);
    Q_ASSERT(iface);
224
    Q_UNUSED(iface);
Lukáš Tinkl's avatar
Lukáš Tinkl committed
225

226
    auto dlg = new QFileDialog(this, i18nc("to open an archive", "Open Archive"));
227 228

    dlg->setMimeTypeFilters(Kerfuffle::supportedMimeTypes());
229 230
    dlg->setFileMode(QFileDialog::ExistingFile);
    dlg->setAcceptMode(QFileDialog::AcceptOpen);
231 232 233 234 235 236 237 238 239

    connect(dlg, &QDialog::finished, this, [this, dlg](int result) {
        if (result == QDialog::Accepted) {
            openUrl(dlg->selectedUrls().first());
        }
        dlg->deleteLater();
    });

    dlg->open();
240
}
Henrique Pinto's avatar
Henrique Pinto committed
241

Lukáš Tinkl's avatar
Lukáš Tinkl committed
242
void MainWindow::openUrl(const QUrl& url)
243
{
244 245
    if (!url.isEmpty()) {
        m_part->setArguments(m_openArgs);
246

247 248 249 250 251 252
        if (m_part->openUrl(url)) {
            m_recentFilesAction->addUrl(url);
        } else {
            m_recentFilesAction->removeUrl(url);
        }
    }
Henrique Pinto's avatar
Henrique Pinto committed
253 254
}

255 256
void MainWindow::setShowExtractDialog(bool option)
{
257
    if (option) {
258
        m_openArgs.metaData()[QStringLiteral("showExtractDialog")] = QStringLiteral("true");
259
    } else {
260
        m_openArgs.metaData().remove(QStringLiteral("showExtractDialog"));
261
    }
262 263
}

264 265 266 267 268 269 270 271
void MainWindow::closeEvent(QCloseEvent *event)
{
    // Preview windows don't have a parent, so we need to manually close them.
    foreach (QWidget *widget, qApp->topLevelWidgets()) {
        if (widget->isVisible()) {
            widget->close();
        }
    }
272 273

    KParts::MainWindow::closeEvent(event);
274 275
}

Henrique Pinto's avatar
Henrique Pinto committed
276 277
void MainWindow::quit()
{
278
    close();
279 280
}

281 282 283 284 285
void MainWindow::showSettings()
{
    Interface *iface = qobject_cast<Interface*>(m_part);
    Q_ASSERT(iface);

286
    KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), iface->config());
287 288 289 290 291 292 293

    foreach (Kerfuffle::SettingsPage *page, iface->settingsPages(this)) {
        dialog->addPage(page, page->name(), page->iconName());
    }
    // Hide the icons list if only one page has been added.
    dialog->setFaceType(KPageDialog::Auto);

Laurent Montel's avatar
Laurent Montel committed
294
    connect(dialog, &KConfigDialog::settingsChanged, this, &MainWindow::writeSettings);
295 296 297 298 299 300 301 302 303 304
    dialog->show();
}

void MainWindow::writeSettings()
{
    Interface *iface = qobject_cast<Interface*>(m_part);
    Q_ASSERT(iface);
    iface->config()->save();
}

305 306
void MainWindow::newArchive()
{
307 308
    qCDebug(ARK) << "Creating new archive";

309 310
    Interface *iface = qobject_cast<Interface*>(m_part);
    Q_ASSERT(iface);
311
    Q_UNUSED(iface);
Raphael Kubo da Costa's avatar
const++  
Raphael Kubo da Costa committed
312

313 314 315 316 317 318 319 320 321 322 323 324 325
    QPointer<Kerfuffle::CreateDialog> dialog = new Kerfuffle::CreateDialog(
        Q_NULLPTR, // parent
        i18n("Create a new Archive"), // caption
        QUrl()); // startDir

    dialog.data()->show();
    dialog.data()->restoreWindowSize();

    if (dialog.data()->exec()) {
        const QUrl saveFileUrl = dialog.data()->selectedUrls().first();
        const QString password = dialog.data()->password();

        qCDebug(ARK) << "CreateDialog returned URL:" << saveFileUrl.toString();
326
        qCDebug(ARK) << "CreateDialog returned mime:" << dialog.data()->currentFilterMimeType().name();
327

328 329
        m_openArgs.metaData()[QStringLiteral("createNewArchive")] = QStringLiteral("true");
        m_openArgs.metaData()[QStringLiteral("encryptionPassword")] = password;
330

331
        if (dialog.data()->isHeaderEncryptionEnabled()) {
332
            m_openArgs.metaData()[QStringLiteral("encryptHeader")] = QStringLiteral("true");
333 334 335 336
        }

        openUrl(saveFileUrl);

337 338 339 340
        m_openArgs.metaData().remove(QStringLiteral("showExtractDialog"));
        m_openArgs.metaData().remove(QStringLiteral("createNewArchive"));
        m_openArgs.metaData().remove(QStringLiteral("encryptionPassword"));
        m_openArgs.metaData().remove(QStringLiteral("encryptHeader"));
Lukáš Tinkl's avatar
Lukáš Tinkl committed
341
    }
342 343

    delete dialog.data();
Henrique Pinto's avatar
Henrique Pinto committed
344
}