FolderWatcher

Форк
0
/
mainwindow.cpp 
345 строк · 15.4 Кб
1
#include "mainwindow.h"
2
#include "ui_mainwindow.h"
3

4
MainWindow::MainWindow(QWidget *parent)
5
    : QMainWindow(parent)
6
    , ui(new Ui::MainWindow)
7
{
8
    // настройка модели работы с директориями
9
    ui->setupUi(this);
10
    dir = new QFileSystemModel;
11
    dir->setRootPath(QDir::currentPath());
12
    ui->listView->setModel(dir);
13
    ui->listView->setRootIndex(dir->index(QDir::currentPath()));
14
    // Отключаем горячие клавиши для listView
15
    filter = new ShortcutsEventFilter(this);
16
    ui->listView->installEventFilter(filter);
17

18
    ui->path_line->setText(QDir::currentPath());
19

20
    // настройка модели работы с инфой о директориях
21
    info = new QStandardItemModel;
22
    ui->tableView->resizeColumnsToContents();
23
    QHeaderView *header = ui->tableView->horizontalHeader();
24
    header->setStretchLastSection(true);
25
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
26
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
27
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
28
    ui->tableView->setModel(info);
29

30
    // Ищем доступные локальные хранилища и добавляем их в комбо бокс
31
    QStringList storages_paths;
32
    foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
33
        if (storage.isValid() && storage.isReady()) {
34
            storages_paths << storage.rootPath();
35
        }
36
    }
37
    ui->storages_box->addItems(storages_paths);
38

39
    // Объект для вычислений КС, заносим вычисления в отдельный поток
40
    HashSum *calculator = new HashSum(this);
41
    calculator->moveToThread(&hash_sum_thread);
42

43
    // Заносим логгер в отдельный поток
44
    Logger *logger = new Logger(this);
45
    logger->moveToThread(&logger_thread);
46

47
    // Создаем окно загрузки и скрываем его
48
    loading_window = new LoadingWindow();
49
    loading_window->hide();
50

51
    // Коннектим нажатие на кнопки подсчета КС к слоту-отправителю сигнала с данными о выделенных
52
    // файлах и папках
53
    connect(ui->actionSHA_256, &QAction::triggered, this, &MainWindow::chooseSHA_256);
54
    connect(ui->actionSHA_512, &QAction::triggered, this, &MainWindow::chooseSHA_512);
55
    connect(ui->actionMD5, &QAction::triggered, this, &MainWindow::chooseMD5);
56

57
    // Коннектим завершение потока с планированием удаления "вычислителя" КС
58
    connect(&hash_sum_thread, &QThread::finished, calculator, &QObject::deleteLater);
59
    // Коннектим сигнал с данными о выделенных файлах и папках со слотом вычисления КС
60
    connect(this, &MainWindow::returnHashSum, calculator, &HashSum::getHashSums);
61
    // Коннектим сигнал о завершении вычисления КС с внесением полученных данных в таблицу
62
    connect(calculator, &HashSum::hashSumsReady, this, &MainWindow::handleHashSumCalculations);
63

64
    // Коннектим завершение потока с планированием удаления логгера
65
    connect(&logger_thread, &QThread::finished, logger, &QObject::deleteLater);
66
    // Коннектим сигнал о возникшей ошибке с логом
67
    connect(calculator, &HashSum::errorOccured, &Logger::logHashSumToFile);
68
    // Коннектим сигнал о возникшей ошибке с логом
69
    connect(this, &MainWindow::errorOccured, &Logger::logSizeToFile);
70

71
    // // Коннектим сигнал о завершении вычисления КС с показом логов
72
    // connect(calculator, &HashSum::hashSumsReady, this, &MainWindow::showHashSumLogs);
73
    // // Коннектим сигнал об ошибках со сбором ошибок
74
    // connect(calculator, &HashSum::errorOccured, this, &MainWindow::handleHashSumErrors);
75

76
    hash_sum_thread.start();
77

78
    logger_thread.start();
79

80
    // Коннектим двойное нажатие по папке/файлу к его открытию
81
    connect(ui->listView, &QListView::doubleClicked, this, &MainWindow::goDownDir);
82
    // Коннектим нажатие по кнопке с поднятием на одну папку наверх
83
    connect(ui->back_button, &QPushButton::clicked, this, &MainWindow::goUpDir);
84
    // Коннектим нажатие по кнопке с отображением инфы
85
    connect(ui->main_info_button, &QPushButton::clicked, this, &MainWindow::showMainInfo);
86
    // Коннектим выбор доступного хранилища в комбо боксе с его открытием модели
87
    connect(ui->storages_box, &QComboBox::textActivated, this, &MainWindow::goToStorage);
88
    // Коннектим изменение корневого пути в модели с его отображением в строке
89
    connect(dir, &QFileSystemModel::rootPathChanged, ui->path_line, &QLineEdit::setText);
90
}
91

92
void MainWindow::goDownDir(const QModelIndex &index) {
93
    // Назначаем новый корень для отображения
94
    ui->listView->setRootIndex(index);
95
    // Назначаем новый корень для самой модели
96
    dir->setRootPath(dir->filePath(index));
97
}
98

99
void MainWindow::goUpDir() {
100
    // Получаем адрес директории в которой сейчас находимся,
101
    // затем пермещаемся на директорию (cdUp()) выше и переназначаем корни
102
    // для модели и отображения
103
    QDir now_dir(dir->rootPath());
104
    now_dir.cdUp();
105
    ui->listView->setRootIndex(dir->index(now_dir.absolutePath()));
106
    dir->setRootPath(now_dir.absolutePath());
107
}
108

109
void MainWindow::goToStorage(const QString &storage_path) {
110
    // Назначаем новый корень для отображения
111
    ui->listView->setRootIndex(dir->index(storage_path));
112
    // Назначаем новый корень для самой модели
113
    dir->setRootPath(storage_path);
114
}
115

116
void MainWindow::showMainInfo() {
117
    //
118
    info->clear();
119

120
    // установка названий столбцов
121
    info->setColumnCount(4);
122
    info->setHorizontalHeaderLabels(QStringList{"name", "date", "type", "size"});
123

124
    // Получаем индекс текущей директории и количество файлов в директории
125
    QModelIndex currentDirIndex = dir->index(dir->rootPath());
126
    int fileCount = dir->rowCount(currentDirIndex);
127

128
    if (ui->dir_size_box->isChecked()) {
129
        ui->info_label->setText("Молчать! Идет подсчет размера директорий");
130
        ui->info_label->setStyleSheet("color: rgb(255, 165, 0)");
131
    }
132

133
    // Проходимся по всем файлам и печатаем информацию о них
134
    for (int i = 0; i < fileCount; i++) {
135
        QModelIndex fileIndex = dir->index(i, 0, currentDirIndex);
136

137
        // Получаем тип файла (расширение)
138
        QString fileType = (dir->isDir(fileIndex)) ? "Folder" : dir->fileInfo(fileIndex).completeSuffix();
139
        if (fileType == "") fileType = "File";
140

141
        // добавляем строку с инфой о файле
142
        QList<QStandardItem *> row;
143
        row << new QStandardItem(dir->fileName(fileIndex));
144
        row << new QStandardItem(dir->lastModified(fileIndex).toString("yyyy-MM-dd HH:mm:ss"));
145
        row << new QStandardItem(fileType);
146
        if (fileType != "Folder")
147
        {
148
            // Делаем читаемый размер
149
            double file_size = dir->size(fileIndex);
150
            row << new QStandardItem(getMinimizedFormSize(file_size));
151
        }
152
        else
153
        {
154
            // Если стоит галочка в чек боксе, считаем еще и размер папок
155
            if (ui->dir_size_box->isChecked()) {
156
                // Задержка для постепенной отрисовки строк
157
                delay(100);
158
                unsigned long long dir_size = 0;
159
                // Переделываем слеши в бэкслеши для понятного формата для функции
160
                std::wstring path_for_fsys = dir->filePath(fileIndex).replace('/', "\\\\").toStdWString();
161

162
                try {
163
                    getFoldersizeIterative(path_for_fsys, dir_size);
164
                    // Делаем читаемый размер
165
                    double d_dir_size = dir_size;
166
                    row << new QStandardItem(getMinimizedFormSize(d_dir_size));
167
                } catch(std::exception &e) {
168
                    // Вписываем сообщение об ошибке
169
                    row << new QStandardItem("ОШИБКА");
170
                    emit errorOccured(e, dir->filePath(fileIndex));
171
                }
172

173
            }
174
            // Если галочки нет - в таблице для папок размер не указывается
175
            else
176
                row << new QStandardItem("");
177
        }
178

179
        info->appendRow(row);
180
    }
181
    ui->info_label->setStyleSheet("color: rgb(0, 0, 0)");
182
    ui->info_label->setText("Информация");
183
}
184

185
MainWindow::~MainWindow()
186
{
187
    delete dir;
188
    delete info;
189
    delete ui;
190
    delete loading_window;
191
    delete filter;
192
    hash_sum_thread.quit();
193
    hash_sum_thread.wait();
194
    logger_thread.quit();
195
    logger_thread.wait();
196
}
197

198
void MainWindow::on_info_message_triggered() const
199
{
200
    QMessageBox info_box;
201
    info_box.setWindowTitle("О программе...");
202
    info_box.setBaseSize(200, 100);
203
    info_box.setIcon(QMessageBox::Information);
204
    info_box.setText("<b>Программа FolderWatcher ver. 0.2</b>");
205
    info_box.setInformativeText("<b>Разработчик ДИПМаксМакс</b>");
206
    info_box.exec();
207
}
208

209
void MainWindow::getFoldersizeIterative(std::wstring rootFolder, unsigned long long &f_size) {
210
    // Функция от пользователя Amit взята на
211
    // https://stackoverflow.com/questions/15495756/how-can-i-find-the-size-of-all-files-located-inside-a-folder
212
    // и переписана в итеративный вид
213
    // Стек для хранения вложенных путей
214
    QStack<std::wstring> folders;
215
    folders.push(rootFolder);
216

217
    while (!folders.empty()) {
218
        std::wstring current_folder = folders.top();
219
        folders.pop();
220

221
        fsys::path folderPath(current_folder);
222
        if (fsys::exists(folderPath)) {
223
            fsys::directory_iterator end_itr;
224
            for (fsys::directory_iterator dirIte(current_folder, fsys::directory_options::skip_permission_denied);
225
                 dirIte != end_itr; ++dirIte) {
226
                fsys::path filePath(dirIte->path());
227
                try {
228
                    if (!fsys::is_directory(dirIte->status())) {
229
                        f_size += fsys::file_size(filePath);
230
                    } else {
231
                        folders.push(filePath.wstring());
232
                    }
233
                } catch (std::exception &e) {
234
                    // записываем в лог ошибки
235
                    emit errorOccured(e, QString::fromStdString(filePath.string()));
236
                }
237
            }
238
        }
239
    }
240
}
241

242
void MainWindow::delay(int n) const
243
{
244
    QTime dieTime= QTime::currentTime().addMSecs(n);
245
    while (QTime::currentTime() < dieTime)
246
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
247
}
248

249
QString MainWindow::getMinimizedFormSize(double &f_size) {
250
    QString unit = "bytes";
251
    QVector<QString> units {"Kbytes", "Mbytes", "Gbytes"};
252
    int i = 0;
253
    // Делим пока можем на 1024 и меняем соответсвтенно приставку
254
    while (f_size > 1024 && i < 2) {
255
        f_size /= 1024.0;
256
        unit = units[i++];
257
    }
258
    if (i == 0)
259
        return QString::number(f_size, 'f', 0) + " " + unit;
260
    return QString::number(f_size, 'f', 2) + " " + unit;
261
}
262

263
void MainWindow::handleHashSumCalculations(const HashSumRow &vec_rows, const QString &elapsed_time)
264
{
265
    // Готовим таблицу для хэш сумм
266
    info->clear();
267
    info->setColumnCount(2);
268
    info->setHorizontalHeaderLabels(QStringList{"name", "hash sum"});
269

270
    // Заполняем таблицу данными полученными вычислителем КС
271
    for (auto item : vec_rows) {
272
        QList<QStandardItem *> row;
273
        row << new QStandardItem(item.first);
274
        row << new QStandardItem(item.second);
275
        info->appendRow(row);
276
    }
277

278
    ui->info_label->setStyleSheet("color: rgb(0, 0, 0)");
279
    ui->info_label->setText("Информация. Время вычисления " +
280
                            elapsed_time + " c.");
281
    // скрываем окно
282
    loading_window->hide();
283
}
284

285
void MainWindow::calcFileHashSumTriggered(const ALG_ID &hashAlgorithm) {
286
    // очищаем лог
287
    hash_sum_log = "";
288
    // открываем окно
289
    loading_window->show();
290
    emit returnHashSum(ui->listView->selectionModel()->selectedIndexes(), dir, hashAlgorithm);
291
}
292

293
void MainWindow::handleHashSumErrors(const HashSumErrors &error, const QString &file_path) {
294
    switch (error) {
295
    case HashSumErrors::MakeHashSumFileError:
296
        hash_sum_log += file_path + ": Не удалось создать файл контрольных сумм!\n";
297
        break;
298
    case HashSumErrors::DeleteHashSumFileError:
299
        hash_sum_log += file_path + ": Не удалось удалить файл контрольных сумм!\n";
300
        break;
301
    case HashSumErrors::GetHashSumError:
302
        hash_sum_log += file_path + ": Не удалось получить контрольную сумму файла!\n";
303
        break;
304
    case HashSumErrors::CreateHashError:
305
        hash_sum_log += file_path + ": Не удалось создать хэш!\n";
306
        break;
307
    case HashSumErrors::ProviderAccessError:
308
        hash_sum_log += file_path + ": Не удалось получить доступ к криптопровайдеру!\n";
309
        break;
310
    case HashSumErrors::OpenFileError:
311
        hash_sum_log += file_path + ": Не удалось открыть файл для чтения или получить"
312
                                    "доступ к файлам папки!\n";
313
        break;
314
    default:
315
        break;
316
    }
317
}
318

319
void MainWindow::showHashSumLogs() {
320
    QMessageBox info_box;
321
    info_box.setWindowTitle("Логи вычисления контрольных сумм");
322
    info_box.setBaseSize(200, 100);
323
    info_box.setIcon(QMessageBox::Information);
324
    if (hash_sum_log.isEmpty()) info_box.setText("Контрольные суммы успешно посчитаны");
325
    else info_box.setText(hash_sum_log);
326
    info_box.exec();
327
}
328

329
void MainWindow::chooseSHA_256() {
330
    calcFileHashSumTriggered(CALG_SHA_256);
331
}
332

333
void MainWindow::chooseSHA_512() {
334
    calcFileHashSumTriggered(CALG_SHA_512);
335
}
336

337
void MainWindow::chooseMD5() {
338
    calcFileHashSumTriggered(CALG_MD5);
339
}
340

341
void MainWindow::on_show_log_2_triggered()
342
{
343
    // NOTE: открываем файл с логами (не факт что работает, так и не смог протестить)
344
    QDesktopServices::openUrl(QUrl::fromLocalFile("log.txt"));
345
}
346

347

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.