9#include <QWidgetAction>
10#include <QDesktopServices>
16#include <QLoggingCategory>
18#include <QApplication>
20#include <QMimeDatabase>
23#include <QTextDocument>
27#include "RabbitCommonDir.h"
28#include "UndoCommand.h"
29#include "FileBroserTreeView.h"
30#include "FileBrowser.h"
32static Q_LOGGING_CATEGORY(log,
"RabbitCommon.Browser.File")
36 , m_pUndoStack(
nullptr)
42 , m_pTextEdit(
nullptr)
43 , m_pHiddenFile(
nullptr)
44 , m_pAssociated(
nullptr)
45 , m_pOrientation(
nullptr)
48 setAttribute(Qt::WA_DeleteOnClose);
49 setWindowTitle(tr(
"File browser"));
50 setWindowIcon(QIcon::fromTheme(
"browser"));
52 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
53 QSettings::IniFormat);
59 rect = parent->frameGeometry();
61 QScreen* pScreen = QApplication::primaryScreen();
63 rect = pScreen->geometry();
65 rect.setLeft((rect.width() - nWidth) / 2);
66 rect.setTop((rect.height() - nHeight) / 2);
67 rect.setWidth(nWidth);
68 rect.setHeight(nHeight);
71 QVBoxLayout* pLayout =
new QVBoxLayout(
this);
74 m_pModel =
new QFileSystemModel(
this);
83 m_pSpliter =
new QSplitter(
this);
84 if(!m_pSpliter)
break;
87 m_pTree->setAutoScroll(
true);
99 m_pTable =
new QTableView(m_pSpliter);
101 m_pTextEdit =
new QTextEdit(m_pSpliter);
104 QToolBar* pToolBar =
new QToolBar(
this);
105 szTitle = tr(
"Close");
106 QAction* pAction = pToolBar->addAction(QIcon::fromTheme(
"window-close"),
107 szTitle,
this, &CFileBrowser::close);
108 pAction->setStatusTip(szTitle);
110 m_pUndoStack =
new QUndoStack(
this);
111 if(!m_pUndoStack)
break;
113 QList<QAction*> lstUndo;
114 pAction = m_pUndoStack->createUndoAction(
this);
115 pAction->setIcon(QIcon::fromTheme(
"edit-undo"));
117 pAction = m_pUndoStack->createRedoAction(
this);
118 pAction->setIcon(QIcon::fromTheme(
"edit-redo"));
120 pToolBar->addActions(lstUndo);
156 pToolBar->addAction(QIcon::fromTheme(
"go-up"), tr(
"Up folder"),
159 QModelIndex index = m_pTree->currentIndex();
160 szDir = m_pModel->filePath(index);
163 szDir = szDir + QDir::separator() +
"..";
166 szDir = fi.absolutePath();
168 qDebug(log) <<
"Dir" << szDir;
169 auto i = m_pModel->index(szDir);
172 m_pUndoStack->push(
new CChange(i,
this));
173 m_pTree->setCurrentIndex(i);
175 m_pTree->doItemsLayout();
176 m_pTree->scrollTo(i);
180 szTitle = tr(
"Option");
181 QToolButton* pButtonOption =
new QToolButton(pToolBar);
182 pButtonOption->setIcon(QIcon::fromTheme(
"emblem-system"));
183 pButtonOption->setStatusTip(szTitle);
184 pButtonOption->setPopupMode(QToolButton::InstantPopup);
185 QMenu* pMenuOption =
new QMenu(szTitle, pButtonOption);
186 pButtonOption->setMenu(pMenuOption);
187 pToolBar->addWidget(pButtonOption);
189 szTitle = tr(
"Hidden file");
190 m_pHiddenFile = pMenuOption->addAction(
193 bool checked = m_pHiddenFile->isChecked();
195 m_pModel->setFilter(m_pModel->filter() | QDir::Hidden);
197 m_pModel->setFilter(m_pModel->filter() & (~QDir::Hidden));
198 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
199 QSettings::IniFormat);
200 set.setValue(GetSetPrefix() +
"/HiddenFile", checked);
202 check = set.value(GetSetPrefix() +
"/HiddenFile", check).toBool();
203 m_pHiddenFile->setStatusTip(szTitle);
204 m_pHiddenFile->setToolTip(szTitle);
205 m_pHiddenFile->setCheckable(
true);
206 m_pHiddenFile->setChecked(check);
208 m_pModel->setFilter(m_pModel->filter() | QDir::Hidden);
210 m_pModel->setFilter(m_pModel->filter() & (~QDir::Hidden));
212 szTitle = tr(
"Open with the System Associated Program");
213 m_pAssociated = pMenuOption->addAction(
214 szTitle,
this, [&](){
215 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
216 QSettings::IniFormat);
217 set.setValue(GetSetPrefix() +
"/SystemAssociatedProgram", m_pAssociated->isChecked());
219 m_pAssociated->setStatusTip(szTitle);
220 m_pAssociated->setToolTip(szTitle);
221 m_pAssociated->setCheckable(
true);
222 m_pAssociated->setChecked(
224 GetSetPrefix() +
"/SystemAssociatedProgram",
225 m_pAssociated->isChecked()).toBool());
227 szTitle = tr(
"Horizontal");
228 m_pOrientation = pMenuOption->addAction(
229 szTitle,
this, [&](){
230 bool checked = m_pOrientation->isChecked();
232 m_pSpliter->setOrientation(Qt::Horizontal);
234 m_pSpliter->setOrientation(Qt::Vertical);
235 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
236 QSettings::IniFormat);
237 set.setValue(GetSetPrefix() +
"/Spliter/Horizontal", checked);
239 m_pOrientation->setStatusTip(szTitle);
240 m_pOrientation->setToolTip(szTitle);
241 m_pOrientation->setCheckable(
true);
242#if defined(Q_OS_ANDROID)
247 check = set.value(GetSetPrefix() +
"/Spliter/Horizontal", check).toBool();
248 m_pOrientation->setChecked(check);
250 m_pSpliter->setOrientation(Qt::Horizontal);
252 m_pSpliter->setOrientation(Qt::Vertical);
254 QComboBox* pUrl =
new QComboBox(pToolBar);
255 pUrl->setEditable(
true);
256 pUrl->setSizePolicy(QSizePolicy::Policy::Expanding,
257 QSizePolicy::Policy::Preferred);
259 pUrl, &QComboBox::currentTextChanged,
this,
260 [&](
const QString &szText) {
261 qDebug(log) <<
"QComboBox::currentTextChanged";
262 QComboBox* pUrl = qobject_cast<QComboBox*>(sender());
264 QModelIndex index = m_pModel->index(szText);
265 if(index.isValid()) {
266 m_pUndoStack->push(
new CChange(index,
this));
267 m_pTree->setCurrentIndex(index);
269 m_pTree->doItemsLayout();
270 m_pTree->scrollTo(index);
271 int index = pUrl->findText(szText);
273 pUrl->addItem(szText);
277 pToolBar->addWidget(pUrl);
279 pLayout->addWidget(pToolBar);
280 pLayout->addWidget(m_pSpliter);
292 m_pTree->setModel(m_pModel);
293 m_pTree->setHeaderHidden(
true);
295 m_pTree->header()->hideSection(1);
296 m_pTree->header()->hideSection(2);
297 m_pTree->header()->hideSection(3);
298 m_pSpliter->addWidget(m_pTree);
312 m_pTree, &QTreeView::clicked,
313 this, [&](
const QModelIndex& index){
314 m_pUndoStack->push(
new CChange(index,
this));
319 m_pTree, &QTreeView::doubleClicked,
320 this, [&](
const QModelIndex &index) {
322 QString szFile = m_pModel->filePath(index);
323 emit sigDoubleClicked(szFile, m_pModel->isDir(index));
324 if(m_pModel->isDir(index)) {
332 check = connect(m_pTree, &CFileBroserTreeView::sigChanged,
333 this, &CFileBrowser::sigChanged);
338 m_pSpliter->addWidget(m_pList);
339 m_pList->setModel(m_pModel);
344 m_pSpliter->addWidget(m_pTable);
345 m_pTable->setModel(m_pModel);
346 m_pTable->setShowGrid(
false);
347 m_pTable->verticalHeader()->hide();
349 m_pTable, &QTableView::clicked,
350 this, [&](
const QModelIndex &index) {
352 m_pUndoStack->push(
new CChange(index,
this));
353 QString szDir = m_pModel->filePath(index);
354 m_pTree->setCurrentIndex(index);
355 m_pTree->expand(index);
356 if(m_pModel->isDir(index)) {
357 m_pModel->setRootPath(szDir);
358 m_pTable->setRootIndex(m_pModel->index(szDir));
359 if(!m_pTextEdit->isHidden())
362#
if defined(Q_OS_ANDROID)
370 check = connect(m_pTable, &QTableView::doubleClicked,
371 this, [&](
const QModelIndex &index){
372 QString szFile = m_pModel->filePath(index);
374 emit sigDoubleClicked(szFile, m_pModel->isDir(index));
381 m_pSpliter->addWidget(m_pTextEdit);
405CFileBrowser::~CFileBrowser()
407 qDebug(log) <<
"CFileBrowser::~CFileBrowser()";
412 m_pModel->setRootPath(dir);
413 m_pTree->setRootIndex(m_pModel->index(dir));
418 return m_pModel->rootPath();
421QString CFileBrowser::GetSetPrefix()
423 QString szPrefix(
"FileBrowser");
424 if(!this->objectName().isEmpty())
425 szPrefix = szPrefix +
"/" + this->objectName();
429QString CFileBrowser::readFile(
const QString &filePath)
433 if (filePath.isEmpty())
436 QFile file(filePath);
438 static const QMimeDatabase db;
439 const QMimeType mime = db.mimeTypeForFile(QFileInfo(file));
440 qDebug(log) << mime << filePath;
442 if(mime.name() ==
"application/x-executable")
444 if(QProcess::startDetached(filePath))
447 qCritical(log) <<
"Start fail:" << filePath;
448 }
else if(mime.name().contains(
"image", Qt::CaseInsensitive)) {
450 if(img.load(filePath)) {
451 QTextCursor cursor = m_pTextEdit->textCursor();
452 QTextDocument *document = m_pTextEdit->document();
455 document->addResource(
456 QTextDocument::ImageResource, QUrl(
"image"), img);
458 cursor.insertImage(
"image");
461 qCritical(log) <<
"Error: load image" << filePath;
463 if (file.size() >= 2000000)
464 return tr(
"File size is too big.\nYou can read files up to %1 MB.").arg(2);
467 const auto mimeTypesForFile = mime.parentMimeTypes();
468 for (
const auto &m : mimeTypesForFile) {
469 qDebug(log) <<
"m" << m;
470 if (m.contains(
"text", Qt::CaseInsensitive)
471 || mime.comment().contains(
"text", Qt::CaseInsensitive)) {
472 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
473 return tr(
"Error opening the File!");
475 QTextStream stream(&file);
476 return stream.readAll();
480 return tr(
"Filetype ") + mime.name() +
" not supported!";
483int CFileBrowser::ShowFile(
const QString &szFile)
485 if(m_pAssociated->isChecked()) {
486 QUrl url = QUrl::fromLocalFile(szFile);
487 if(QDesktopServices::openUrl(url))
491 QString szText = readFile(szFile);
492 if(!szText.isEmpty())
493 m_pTextEdit->setText(szText);
494 if(m_pTextEdit->isHidden())
499void CFileBrowser::slotClicked(
const QModelIndex &index)
501 qDebug(log) <<
"CFileBrowser::slotClicked" << index;
503 if(m_pModel->isDir(index)) {
504 m_pTable->setRootIndex(index);
510#if defined(Q_OS_ANDROID)
511 QString szFile = m_pModel->filePath(index);
517CDlgFileBrowser::CDlgFileBrowser(QWidget *parent) : QDialog(parent)
518 ,m_pFileBrowser(nullptr)
521 setWindowIcon(m_pFileBrowser->windowIcon());
522 setWindowTitle(m_pFileBrowser->windowTitle());
524 bool check = connect(m_pFileBrowser, SIGNAL(destroyed(QObject*)),
525 this, SLOT(close()));
528 QHBoxLayout *layout =
new QHBoxLayout(
this);
529 layout->addWidget(m_pFileBrowser);
530 layout->setContentsMargins(0, 0, 0, 0);
void setRootPath(const QString dir)
Set root path.
QString rootPath() const
Get root path.