DISABLE_COMPILER_WARNINGS #include <QApplication> #include <QDragMoveEvent> #include <QHeaderView> #include <QKeyEvent> #include <QMouseEvent> RESTORE_COMPILER_WARNINGS #include <time.h> #include <set> #if defined __linux__ || defined __APPLE__ #include "cfocusframestyle.h" #endif CFileListView::CFileListView(QWidget *parent) : QTreeView(parent), _controller(CController::get()), _panelPosition(UnknownPanel), _bHeaderAdjustmentRequired(true), _singleMouseClickValid(false), _shiftPressedItemSelected(false) { setMouseTracking(true); setItemDelegate(new CFileListItemDelegate); connect(this, &QTreeView::doubleClicked, [this](const QModelIndex &idx) { _itemUnderCursorBeforeMouseClick = QModelIndex(); _singleMouseClickValid = false; for(FileListViewEventObserver* observer: _eventObservers) { if (observer->fileListReturnPressOrDoubleClickPerformed(idx)) break; } }); QHeaderView * headerView = header(); assert_r(headerView); headerView->installEventFilter(this); #if defined __linux__ || defined __APPLE__ setStyle(new CFocusFrameStyle); #endif }
const std::vector<CMyHtmlParser::HtmlTag>& CMyHtmlParser::parse(const QByteArray& html) { _tags.clear(); _tree = myhtml_tree_create(); assert_r(_tree); assert_r(myhtml_tree_init(_tree, _myhtmlInstance) == MyCORE_STATUS_OK); myhtml_callback_tree_node_insert_set(_tree, &CMyHtmlParser::callbackNodeInserted, this); /* * From Specification: * * The authoring conformance requirements for character encoding declarations limit them to only * appearing in the first 1024 bytes. User agents are therefore encouraged to use the prescan * algorithm below (as invoked by these steps) on the first 1024 bytes, but not to stall beyond that. */ _encoding = myencoding_prescan_stream_to_determine_encoding(html.data(), std::min(html.size(), 1024)); if (_encoding == MyENCODING_NOT_DETERMINED) { assert_unconditional_r("Failed to determine data encoding"); _encoding = MyENCODING_UTF_8; } assert_r(myhtml_parse(_tree, _encoding, html.data(), html.size()) == MyCORE_STATUS_OK); myhtml_tree_destroy(_tree); return _tags; }
void CController::openTerminal(const QString &folder) { #ifdef _WIN32 const bool started = QProcess::startDetached(CShell::shellExecutable(), QStringList(), folder); assert_r(started); #elif defined __APPLE__ system(QString("osascript -e \"tell application \\\"Terminal\\\" to do script \\\"cd %1\\\"\"").arg(folder).toUtf8().data()); #elif defined __linux__ const bool started = QProcess::startDetached(CShell::shellExecutable(), QStringList(), folder); assert_r(started); #else #error unknown platform #endif }
void CMainWindow::currentPanelChanged(QStackedWidget *panel) { _currentPanelWidget = panel; _currentFileList = dynamic_cast<CPanelWidget*>(panel->widget(0)); if (panel) { _otherPanelWidget = panel == ui->leftWidget ? ui->rightWidget : ui->leftWidget; _otherFileList = dynamic_cast<CPanelWidget*>(_otherPanelWidget->widget(0)); assert_r(_otherPanelWidget && _otherFileList); } else { _otherPanelWidget = 0; _otherFileList = 0; } if (_currentFileList) { _controller->activePanelChanged(_currentFileList->panelPosition()); CSettings().setValue(KEY_LAST_ACTIVE_PANEL, _currentFileList->panelPosition()); ui->fullPath->setText(_controller->panel(_currentFileList->panelPosition()).currentDirPathNative()); CPluginEngine::get().currentPanelChanged(_currentFileList->panelPosition()); _commandLineCompleter.setModel(_currentFileList->sortModel()); } else _commandLineCompleter.setModel(0); }
const QIcon& CIconProvider::iconFor(const CFileSystemObject& object) { const qulonglong objectHash = hash(object); if (_iconForObject.count(objectHash) == 0) { const QIcon icon = _provider->iconFor(object); assert_r(!icon.isNull()); const auto qimage = icon.pixmap(icon.availableSizes().front()).toImage(); const qulonglong iconHash = fasthash64((const char*)qimage.constBits(), qimage.bytesPerLine() * qimage.height(), 0); if (_iconCache.size() > 300) { _iconCache.clear(); _iconForObject.clear(); } const auto iconInContainer = _iconCache.insert(std::make_pair(iconHash, icon)).first; _iconForObject[objectHash] = iconHash; return iconInContainer->second; } return _iconCache[_iconForObject[objectHash]]; }
CMainWindow::CMainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::CMainWindow), _controller(new CController), _currentFileList(0), _otherFileList(0), _quickViewActive(false) { assert_r(!_instance); _instance = this; ui->setupUi(this); connect(qApp, &QApplication::focusChanged, this, &CMainWindow::focusChanged); _controller->pluginProxy().setToolMenuEntryCreatorImplementation(CPluginProxy::CreateToolMenuEntryImplementationType(std::bind(&CMainWindow::createToolMenuEntries, this, std::placeholders::_1))); _currentFileList = ui->leftPanel; _otherFileList = ui->rightPanel; connect(ui->leftPanel->fileListView(), &CFileListView::ctrlEnterPressed, this, &CMainWindow::pasteCurrentFileName); connect(ui->rightPanel->fileListView(), &CFileListView::ctrlEnterPressed, this, &CMainWindow::pasteCurrentFileName); connect(ui->leftPanel->fileListView(), &CFileListView::ctrlShiftEnterPressed, this, &CMainWindow::pasteCurrentFilePath); connect(ui->rightPanel->fileListView(), &CFileListView::ctrlShiftEnterPressed, this, &CMainWindow::pasteCurrentFilePath); connect(ui->leftPanel, &CPanelWidget::currentItemChangedSignal, this, &CMainWindow::currentItemChanged); connect(ui->rightPanel, &CPanelWidget::currentItemChangedSignal, this, &CMainWindow::currentItemChanged); connect(ui->leftPanel, &CPanelWidget::itemActivated, this, &CMainWindow::itemActivated); connect(ui->rightPanel, &CPanelWidget::itemActivated, this, &CMainWindow::itemActivated); ui->leftPanel->fileListView()->addEventObserver(this); ui->rightPanel->fileListView()->addEventObserver(this); initButtons(); initActions(); ui->leftPanel->setPanelPosition(LeftPanel); ui->rightPanel->setPanelPosition(RightPanel); ui->fullPath->clear(); QSplitterHandle * handle = ui->splitter->handle(1); handle->setContextMenuPolicy(Qt::CustomContextMenu); connect(handle, &QSplitterHandle::customContextMenuRequested, this, &CMainWindow::splitterContextMenuRequested); connect(ui->commandLine, &CHistoryComboBox::itemActivated, this, &CMainWindow::executeCommand); _commandLineCompleter.setCaseSensitivity(Qt::CaseInsensitive); _commandLineCompleter.setCompletionMode(QCompleter::InlineCompletion); _commandLineCompleter.setCompletionColumn(NameColumn); ui->commandLine->setCompleter(&_commandLineCompleter); ui->commandLine->setClearEditorOnItemActivation(true); ui->leftWidget->setCurrentIndex(0); // PanelWidget ui->rightWidget->setCurrentIndex(0); // PanelWidget connect(&_uiThreadTimer, &QTimer::timeout, this, &CMainWindow::uiThreadTimerTick); _uiThreadTimer.start(5); }
void CController::setDisksChangedListener(CController::IDiskListObserver *listener) { assert_r(std::find(_disksChangedListeners.begin(), _disksChangedListeners.end(), listener) == _disksChangedListeners.end()); _disksChangedListeners.push_back(listener); // Force an update disksChanged(); }
void CMainWindow::addToolMenuEntriesRecursively(CPluginProxy::MenuTree entry, QMenu* toolMenu) { assert_r(toolMenu); QAction* action = toolMenu->addAction(entry.name); QObject::connect(action, &QAction::triggered, [entry](bool){entry.handler();}); for(const auto& childEntry: entry.children) addToolMenuEntriesRecursively(childEntry, toolMenu); }
std::vector<QString> CFileSystemObject::pathHierarchy(const QString& path) { assert_r(!path.contains('\\')); assert_r(!path.contains(QStringLiteral("//")) || !path.rightRef(path.length() - 2).contains(QStringLiteral("//"))); if (path.isEmpty()) return {}; else if (path == '/') return { QString('/') }; QString pathItem = path.endsWith('/') ? path.left(path.length() - 1) : path; std::vector<QString> result {path == '/' ? QString() : path}; while ((pathItem = QFileInfo(pathItem).absolutePath()).length() < result.back().length()) result.push_back(pathItem); return result; }
void OsShell::executeShellCommand(const QString& command, const QString& workingDir) { std::thread([command, workingDir](){ #ifdef _WIN32 _wsystem((QString("pushd ") + workingDir + " && " + command).toStdWString().data()); #else const int result = std::system((QString("cd ") + workingDir + " && " + command).toUtf8().data()); assert_r(result == 0); #endif }).detach(); }
void CFavoriteLocationsEditor::addLocationsToTreeWidget(std::list<CLocationsCollection>& parentList, std::list<CLocationsCollection>::iterator& locationCollectionListIterator, QTreeWidgetItem* parent) { assert_r(locationCollectionListIterator->subLocations.empty() || locationCollectionListIterator->absolutePath.isEmpty()); const bool isCategory = locationCollectionListIterator->absolutePath.isEmpty(); CFavoriteLocationsListItem * treeWidgetItem = parent ? new CFavoriteLocationsListItem(parent, parentList, locationCollectionListIterator, isCategory) : new CFavoriteLocationsListItem(ui->_list, parentList, locationCollectionListIterator, isCategory); if (!locationCollectionListIterator->subLocations.empty()) for (auto it = locationCollectionListIterator->subLocations.begin(); it != locationCollectionListIterator->subLocations.end(); ++it) addLocationsToTreeWidget(locationCollectionListIterator->subLocations, it, treeWidgetItem); if (isCategory) treeWidgetItem->setExpanded(true); }
bool prepareContextMenuForObjects(std::vector<std::wstring> objects, void * parentWindow, HMENU& hmenu, IContextMenu*& imenu) { ComInitializer comInitializer; if (objects.empty()) return false; std::vector<ITEMIDLIST*> ids; std::vector<LPCITEMIDLIST> relativeIds; IShellFolder * ifolder = 0; for (size_t i = 0; i < objects.size(); ++i) { std::replace(objects[i].begin(), objects[i].end(), '/', '\\'); ids.push_back(0); HRESULT result = SHParseDisplayName(objects[i].c_str(), 0, &ids.back(), 0, 0); if (!SUCCEEDED(result) || !ids.back()) { ids.pop_back(); continue; } relativeIds.push_back(0); result = SHBindToParent(ids.back(), IID_IShellFolder, (void**)&ifolder, &relativeIds.back()); if (!SUCCEEDED(result) || !relativeIds.back()) relativeIds.pop_back(); else if (i < objects.size() - 1 && ifolder) { ifolder->Release(); ifolder = nullptr; } } CItemIdArrayReleaser arrayReleaser(ids); assert_r(parentWindow); assert_and_return_message_r(ifolder, "Error getting ifolder", false); assert_and_return_message_r(!relativeIds.empty(), "RelativeIds is empty", false); imenu = 0; HRESULT result = ifolder->GetUIObjectOf((HWND)parentWindow, (UINT)relativeIds.size(), (const ITEMIDLIST **)relativeIds.data(), IID_IContextMenu, 0, (void**)&imenu); if (!SUCCEEDED(result) || !imenu) return false; hmenu = CreatePopupMenu(); if (!hmenu) return false; return (SUCCEEDED(imenu->QueryContextMenu(hmenu, 0, 1, 0x7FFF, CMF_NORMAL))); }
void CMainWindow::toggleQuickView() { if (_quickViewActive) { _quickViewActive = false; assert_r(_currentPanelWidget->count() == 2 || _otherPanelWidget->count() == 2); if (_currentPanelWidget->count() == 2) _currentPanelWidget->removeWidget(_currentPanelWidget->widget(1)); else _otherPanelWidget->removeWidget(_otherPanelWidget->widget(1)); emit fileQuickVewFinished(); } else quickViewCurrentFile(); }
CController::CController() : _leftPanel(LeftPanel), _rightPanel(RightPanel), _workerThread(4, "CController worker thread") { assert_r(_instance == nullptr); // Only makes sense to create one controller _instance = this; _diskEnumerator.addObserver(this); CPluginEngine::get().loadPlugins(); _leftPanel.addPanelContentsChangedListener(&CPluginEngine::get()); _rightPanel.addPanelContentsChangedListener(&CPluginEngine::get()); // Manual update for the CPanels to get the disk list _diskEnumerator.updateSynchronously(); _leftPanel.restoreFromSettings(); _rightPanel.restoreFromSettings(); }
void CMainWindow::quickViewCurrentFile() { if (_quickViewActive) { assert_r(_otherPanelWidget->count() == 2); _otherPanelWidget->removeWidget(_otherPanelWidget->widget(1)); emit fileQuickVewFinished(); } CPluginWindow * viewerWindow = CPluginEngine::get().createViewerWindowForCurrentFile(); if (!viewerWindow) return; connect(this, &CMainWindow::fileQuickVewFinished, viewerWindow, &CPluginWindow::deleteLater); _otherPanelWidget->setCurrentIndex(_otherPanelWidget->addWidget(viewerWindow->centralWidget())); _quickViewActive = true; }
// A current disk has been switched bool CController::switchToDisk(Panel p, size_t index) { assert_r(index < _diskEnumerator.drives().size()); const QString drivePath = _diskEnumerator.drives().at(index).storageInfo.rootPath(); FileOperationResultCode result = rcDirNotAccessible; if (drivePath == _diskEnumerator.drives().at(currentDiskIndex(otherPanelPosition(p))).storageInfo.rootPath()) { result = setPath(p, otherPanel(p).currentDirPathNative(), refreshCauseOther); } else { const QString lastPathForDrive = CSettings().value(p == LeftPanel ? KEY_LAST_PATH_FOR_DRIVE_L.arg(drivePath.toHtmlEscaped()) : KEY_LAST_PATH_FOR_DRIVE_R.arg(drivePath.toHtmlEscaped()), drivePath).toString(); result = setPath(p, lastPathForDrive, refreshCauseOther); } return result == rcOk; }
DISABLE_COMPILER_WARNINGS #include <QApplication> #include <QKeyEvent> #include <QLineEdit> #include <QPlainTextEdit> #include <QSortFilterProxyModel> #include <QTextEdit> #include <QTimer> RESTORE_COMPILER_WARNINGS // Item rename handling void CFileListItemDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const { QStyledItemDelegate::setEditorData(editor, index); auto lineEditor = dynamic_cast<QLineEdit*>(editor); assert_r(lineEditor); assert_and_return_r(index.isValid(), ); auto sortModel = dynamic_cast<const QSortFilterProxyModel*>(index.model()); assert_and_return_message_r(sortModel, "Something has changed in the model hierarchy", ); auto model = dynamic_cast<const CFileListModel*>(sortModel->sourceModel()); assert_and_return_message_r(model, "Something has changed in the model hierarchy", ); auto hash = model->itemHash(sortModel->mapToSource(index)); const auto item = CController::get().itemByHash(model->panelPosition(), hash); if (item.isValid() && item.isFile()) { const QString itemName = lineEditor->text(); const int dot = itemName.lastIndexOf('.'); if (dot != -1) { QTimer::singleShot(0, Qt::CoarseTimer, lineEditor, [=]() { lineEditor->setSelection(0, dot); }); } } }
void CFileListView::selectRegion(const QModelIndex &start, const QModelIndex &end) { bool itemBelongsToSelection = false; assert_r(selectionModel()); for (int i = 0; i < model()->rowCount(); ++i) { // Start item found - beginning selection QModelIndex currentItem = model()->index(i, 0); if (!itemBelongsToSelection && (currentItem == start || currentItem == end)) { itemBelongsToSelection = true; selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows); } else if (itemBelongsToSelection && (currentItem == start || currentItem == end)) { // End item found - finishing selection selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows); return; } if (itemBelongsToSelection) selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows); } }
void CDiskEnumerator::addObserver(IDiskListObserver *observer) { assert_r(std::find(_observers.begin(), _observers.end(), observer) == _observers.end()); _observers.push_back(observer); }
void CFileCommanderPlugin::setProxy(CPluginProxy *proxy) { assert_r(proxy); _proxy = proxy; proxySet(); }
bool OsShell::deleteItems(const std::vector<std::wstring>& items, bool moveToTrash, void * parentWindow) { ComInitializer comInitializer; assert_r(parentWindow); std::vector<ITEMIDLIST*> idLists; for (auto& path: items) { __unaligned ITEMIDLIST* idl = ILCreateFromPathW(path.c_str()); if (!idl) { for (auto& pid : idLists) ILFree(pid); qInfo() << "ILCreateFromPathW" << "failed for path" << QString::fromWCharArray(path.c_str()); return false; } idLists.push_back(idl); assert_r(idLists.back()); } IShellItemArray * iArray = 0; HRESULT result = SHCreateShellItemArrayFromIDLists((UINT)idLists.size(), (LPCITEMIDLIST*)idLists.data(), &iArray); // Freeing memory for (auto& pid: idLists) ILFree(pid); idLists.clear(); if (!SUCCEEDED(result) || !iArray) { qInfo() << "SHCreateShellItemArrayFromIDLists failed"; return false; } IFileOperation * iOperation = 0; result = CoCreateInstance(CLSID_FileOperation, 0, CLSCTX_ALL, IID_IFileOperation, (void**)&iOperation); if (!SUCCEEDED(result) || !iOperation) { qInfo() << "CoCreateInstance(CLSID_FileOperation, 0, CLSCTX_ALL, IID_IFileOperation, (void**)&iOperation) failed"; return false; } result = iOperation->DeleteItems(iArray); if (!SUCCEEDED(result)) { qInfo() << "DeleteItems failed"; } else { if (moveToTrash) { result = iOperation->SetOperationFlags(FOF_ALLOWUNDO); } else result = iOperation->SetOperationFlags(FOF_WANTNUKEWARNING); if (!SUCCEEDED(result)) qInfo() << "SetOperationFlags failed"; result = iOperation->SetOwnerWindow((HWND) parentWindow); if (!SUCCEEDED(result)) qInfo() << "SetOwnerWindow failed"; result = iOperation->PerformOperations(); if (!SUCCEEDED(result) && result != COPYENGINE_E_USER_CANCELLED) { qInfo() << "PerformOperations failed"; if (result == COPYENGINE_E_REQUIRES_ELEVATION) qInfo() << "Elevation required"; } else result = S_OK; } iOperation->Release(); iArray->Release(); return SUCCEEDED(result); }
CController& CController::get() { assert_r(_instance); return *_instance; }
// Sets the position (left or right) of a panel that this model represents void CFileListView::setPanelPosition(enum Panel p) { assert_r(_panelPosition == UnknownPanel); // Doesn't make sense to call this method more than once _panelPosition = p; }
ComInitializer() { const auto result = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); assert_r(SUCCEEDED(result)); }
void CTimeElapsed::resume() { assert_r(_paused); _paused = false; _pausedFor += std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - _pauseTimeStamp); }
void CTimeElapsed::pause() { assert_r(!_paused); _pauseTimeStamp = std::chrono::high_resolution_clock::now(); _paused = true; }