showarchivestructuredialog.cpp 9.34 KB
Newer Older
1
/*
Laurent Montel's avatar
Laurent Montel committed
2
   Copyright (C) 2013-2019 Montel Laurent <montel@kde.org>
3

Laurent Montel's avatar
Laurent Montel committed
4
5
6
7
   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.
8

Laurent Montel's avatar
Laurent Montel committed
9
10
11
12
   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.
13

Laurent Montel's avatar
Laurent Montel committed
14
15
16
17
   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
18
19
20
*/

#include "showarchivestructuredialog.h"
21
#include "core/utils.h"
22
#include "pimdataexportgui_debug.h"
Laurent Montel's avatar
Laurent Montel committed
23
#include "PimCommon/PimUtil"
Laurent Montel's avatar
Laurent Montel committed
24
#include <QDialog>
25
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
26
#include <KZip>
Laurent Montel's avatar
Laurent Montel committed
27
#include <KMessageBox>
Laurent Montel's avatar
Laurent Montel committed
28
29

#include <QTreeWidget>
Laurent Montel's avatar
Laurent Montel committed
30
#include <QHeaderView>
31
#include <KSharedConfig>
Laurent Montel's avatar
Laurent Montel committed
32
33
34
35
#include <QDialogButtonBox>
#include <KConfigGroup>
#include <QPushButton>
#include <QVBoxLayout>
36

37
#include <QFileDialog>
Laurent Montel's avatar
Laurent Montel committed
38
39
#include <ktreewidgetsearchline.h>

40
ShowArchiveStructureDialog::ShowArchiveStructureDialog(const QString &filename, QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
41
42
    : QDialog(parent)
    , mFileName(filename)
43
{
Laurent Montel's avatar
Laurent Montel committed
44
45
    setWindowTitle(i18n("Show Archive Content on file \"%1\"", filename));
    setModal(true);
Laurent Montel's avatar
Laurent Montel committed
46
47
48
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    mTreeWidget = new QTreeWidget(this);
Laurent Montel's avatar
Laurent Montel committed
49
    mTreeWidget->header()->hide();
50
    mTreeWidget->setAlternatingRowColors(true);
Laurent Montel's avatar
Laurent Montel committed
51

Laurent Montel's avatar
Laurent Montel committed
52
    KTreeWidgetSearchLine *searchLine = new KTreeWidgetSearchLine(this, mTreeWidget);
Laurent Montel's avatar
Laurent Montel committed
53
    searchLine->setPlaceholderText(i18n("Search..."));
Laurent Montel's avatar
Laurent Montel committed
54
    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this);
Laurent Montel's avatar
Laurent Montel committed
55
    QPushButton *user1Button = new QPushButton(this);
56
    user1Button->setText(i18n("Save As Text..."));
Laurent Montel's avatar
Laurent Montel committed
57
    buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole);
58

Laurent Montel's avatar
Laurent Montel committed
59
60
    connect(buttonBox, &QDialogButtonBox::rejected, this, &ShowArchiveStructureDialog::reject);

61
62
63
    mExtractFile = new QPushButton(this);
    mExtractFile->setText(i18n("Extract Selected File"));
    mExtractFile->setEnabled(false);
64
    connect(mExtractFile, &QPushButton::clicked, this, &ShowArchiveStructureDialog::slotExtractFile);
65
    buttonBox->addButton(mExtractFile, QDialogButtonBox::ActionRole);
66
    connect(mTreeWidget, &QTreeWidget::itemClicked, this, &ShowArchiveStructureDialog::slotItemClicked);
67

Laurent Montel's avatar
Laurent Montel committed
68
    mainLayout->addWidget(searchLine);
Laurent Montel's avatar
Laurent Montel committed
69
70
    mainLayout->addWidget(mTreeWidget);
    mainLayout->addWidget(buttonBox);
Laurent Montel's avatar
Laurent Montel committed
71
72
73
74
    const bool result = fillTree();
    if (result) {
        mTreeWidget->expandAll();
        connect(user1Button, &QPushButton::clicked, this, &ShowArchiveStructureDialog::slotExportAsLogFile);
75
76
    } else {
        user1Button->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
77
78
    }
    readConfig();
79
80
81
82
}

ShowArchiveStructureDialog::~ShowArchiveStructureDialog()
{
83
    writeConfig();
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    delete mZip;
}

void ShowArchiveStructureDialog::slotExtractFile()
{
    QTreeWidgetItem *currentItem = mTreeWidget->currentItem();
    if (currentItem) {
        const QString fullPath = currentItem->data(0, FullPath).toString();
        if (!fullPath.isEmpty()) {
            const KArchiveDirectory *topDirectory = mZip->directory();
            const KArchiveEntry *currentEntry = topDirectory->entry(fullPath);
            if (currentEntry && currentEntry->isFile()) {
                const KArchiveFile *currentFile = static_cast<const KArchiveFile *>(currentEntry);
                const QString dir = QFileDialog::getExistingDirectory(this, i18n("Select Directory"),
Laurent Montel's avatar
Laurent Montel committed
98
99
100
                                                                      QDir::homePath(),
                                                                      QFileDialog::ShowDirsOnly
                                                                      | QFileDialog::DontResolveSymlinks);
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
                if (!dir.isEmpty()) {
                    if (!currentFile->copyTo(dir)) {
                        qCWarning(PIMDATAEXPORTERGUI_LOG) << "Impossible to extract file: " << currentItem->text(0) << " to " << dir;
                    }
                }
            }
        }
    }
}

void ShowArchiveStructureDialog::slotItemClicked(QTreeWidgetItem *item, int column)
{
    Q_UNUSED(column);
    if (item) {
        const QString fullPath = item->data(0, FullPath).toString();
        mExtractFile->setEnabled(!fullPath.isEmpty());
    }
Laurent Montel's avatar
Laurent Montel committed
118
}
119

Laurent Montel's avatar
Laurent Montel committed
120
121
void ShowArchiveStructureDialog::slotExportAsLogFile()
{
122
    PimCommon::Util::saveTextAs(mLogFile, QStringLiteral("%1 (*.txt)").arg(i18nc("qfiledialog filter files text", "Text Files")), this, QUrl(),
123
                                i18nc("@title:window", "Export Log File"));
Laurent Montel's avatar
Laurent Montel committed
124
125
}

126
bool ShowArchiveStructureDialog::fillTree()
Laurent Montel's avatar
Laurent Montel committed
127
{
128
129
    mZip = new KZip(mFileName);
    bool result = mZip->open(QIODevice::ReadOnly);
Laurent Montel's avatar
Laurent Montel committed
130
    if (!result) {
Yuri Chornoivan's avatar
Yuri Chornoivan committed
131
        KMessageBox::error(this, i18n("Archive cannot be opened in read mode."), i18n("Cannot open archive"));
132
133
        delete mZip;
        mZip = nullptr;
Laurent Montel's avatar
Laurent Montel committed
134
        return false;
Laurent Montel's avatar
Laurent Montel committed
135
    }
136
    const KArchiveDirectory *topDirectory = mZip->directory();
137
138
    const bool isAValidArchive = searchArchiveElement(Utils::infoPath(), topDirectory, i18n("Info"));
    if (!isAValidArchive) {
Laurent Montel's avatar
Laurent Montel committed
139
        KMessageBox::error(this, i18n("This is not pim archive."), i18n("Show information"));
140
        result = false;
141
142
143
144
145
146
147
148
149
150
151
    } else {
        searchArchiveElement(Utils::mailsPath(), topDirectory, Utils::appTypeToI18n(Utils::KMail));
        searchArchiveElement(Utils::alarmPath(), topDirectory, Utils::appTypeToI18n(Utils::KAlarm));
        searchArchiveElement(Utils::calendarPath(), topDirectory, Utils::appTypeToI18n(Utils::KOrganizer));
        searchArchiveElement(Utils::addressbookPath(), topDirectory, Utils::appTypeToI18n(Utils::KAddressBook));
        searchArchiveElement(Utils::identitiesPath(), topDirectory, Utils::storedTypeToI18n(Utils::Identity));
        searchArchiveElement(Utils::resourcesPath(), topDirectory, Utils::storedTypeToI18n(Utils::Resources));
        searchArchiveElement(Utils::configsPath(), topDirectory, Utils::storedTypeToI18n(Utils::Config));
        searchArchiveElement(Utils::transportsPath(), topDirectory, Utils::storedTypeToI18n(Utils::MailTransport));
        searchArchiveElement(Utils::dataPath(), topDirectory, Utils::storedTypeToI18n(Utils::Data));
    }
152
    return result;
Laurent Montel's avatar
Laurent Montel committed
153
154
}

155
bool ShowArchiveStructureDialog::searchArchiveElement(const QString &path, const KArchiveDirectory *topDirectory, const QString &name)
Laurent Montel's avatar
Laurent Montel committed
156
157
{
    const KArchiveEntry *topEntry = topDirectory->entry(path);
158
    bool result = true;
Laurent Montel's avatar
Laurent Montel committed
159
    if (topEntry) {
Laurent Montel's avatar
Laurent Montel committed
160
        mLogFile += name + QLatin1Char('\n');
Laurent Montel's avatar
Laurent Montel committed
161
        QTreeWidgetItem *item = addTopItem(name);
162
        addSubItems(path, item, topEntry, 0);
163
164
    } else {
        result = false;
Laurent Montel's avatar
Laurent Montel committed
165
    }
166
    return result;
Laurent Montel's avatar
Laurent Montel committed
167
}
Laurent Montel's avatar
Laurent Montel committed
168

169
void ShowArchiveStructureDialog::addSubItems(const QString &topLevelPath, QTreeWidgetItem *parent, const KArchiveEntry *entry, int indent, const QString &fullpath)
Laurent Montel's avatar
Laurent Montel committed
170
171
{
    const KArchiveDirectory *dir = static_cast<const KArchiveDirectory *>(entry);
Laurent Montel's avatar
Laurent Montel committed
172
    ++indent;
Laurent Montel's avatar
Laurent Montel committed
173
    const QString space = QString(indent * 2, QLatin1Char(' '));
Laurent Montel's avatar
Laurent Montel committed
174
175
    const QStringList lst = dir->entries();
    for (const QString &entryName : lst) {
Laurent Montel's avatar
Laurent Montel committed
176
177
178
179
        const KArchiveEntry *entry = dir->entry(entryName);
        if (entry) {
            if (entry->isDirectory()) {
                const KArchiveDirectory *dirEntry = static_cast<const KArchiveDirectory *>(entry);
180
                QTreeWidgetItem *newTopItem = addItem(parent, dirEntry->name(), QString());
181
                QFont font(newTopItem->font(0));
Laurent Montel's avatar
Laurent Montel committed
182
                font.setBold(true);
Laurent Montel's avatar
Laurent Montel committed
183
                mLogFile += space + dirEntry->name() + QLatin1Char('\n');
184
                newTopItem->setFont(0, font);
185
                addSubItems(topLevelPath, newTopItem, entry, indent, (fullpath.isEmpty() ? QString() : fullpath + QLatin1Char('/')) + dirEntry->name());
Laurent Montel's avatar
Laurent Montel committed
186
187
            } else if (entry->isFile()) {
                const KArchiveFile *file = static_cast<const KArchiveFile *>(entry);
188
                const QString fileFullPath = topLevelPath + (fullpath.isEmpty() ? QString() : fullpath + QLatin1Char('/')) + file->name();
189
190
                //qDebug() << " fileFullPath " <<fileFullPath;
                addItem(parent, file->name(), fileFullPath);
Laurent Montel's avatar
Laurent Montel committed
191
                mLogFile += space + file->name() + QLatin1Char('\n');
Laurent Montel's avatar
Laurent Montel committed
192
193
194
            }
        }
    }
Laurent Montel's avatar
Laurent Montel committed
195
196
}

197
QTreeWidgetItem *ShowArchiveStructureDialog::addItem(QTreeWidgetItem *parent, const QString &name, const QString &fillFullPath)
Laurent Montel's avatar
Laurent Montel committed
198
199
{
    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
Laurent Montel's avatar
Laurent Montel committed
200
    item->setText(0, name);
201
    item->setData(0, FullPath, fillFullPath);
Laurent Montel's avatar
Laurent Montel committed
202
203
204
205
    return item;
}

QTreeWidgetItem *ShowArchiveStructureDialog::addTopItem(const QString &name)
Laurent Montel's avatar
Laurent Montel committed
206
207
{
    QTreeWidgetItem *item = new QTreeWidgetItem;
Laurent Montel's avatar
Laurent Montel committed
208
209
    QFont font = item->font(0);
    font.setBold(true);
Laurent Montel's avatar
Laurent Montel committed
210
211
    item->setFont(0, font);
    item->setText(0, name);
Laurent Montel's avatar
Laurent Montel committed
212
213
    mTreeWidget->addTopLevelItem(item);
    return item;
214
215
}

216
217
void ShowArchiveStructureDialog::writeConfig()
{
Laurent Montel's avatar
Laurent Montel committed
218
219
    KConfigGroup group(KSharedConfig::openConfig(), "ShowArchiveStructureDialog");
    group.writeEntry("Size", size());
220
221
222
223
}

void ShowArchiveStructureDialog::readConfig()
{
Laurent Montel's avatar
Laurent Montel committed
224
225
226
227
    KConfigGroup group(KSharedConfig::openConfig(), "ShowArchiveStructureDialog");
    const QSize sizeDialog = group.readEntry("Size", QSize(600, 400));
    if (sizeDialog.isValid()) {
        resize(sizeDialog);
228
229
    }
}