| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- #include <QtWidgets>
- #include "veditarea.h"
- #include "veditwindow.h"
- #include "vedittab.h"
- #include "vnote.h"
- #include "vconfigmanager.h"
- #include "vfile.h"
- #include "dialog/vfindreplacedialog.h"
- #include "utils/vutils.h"
- extern VConfigManager *g_config;
- extern VNote *g_vnote;
- VEditArea::VEditArea(VNote *vnote, QWidget *parent)
- : QWidget(parent), VNavigationMode(),
- vnote(vnote), curWindowIndex(-1)
- {
- setupUI();
- insertSplitWindow(0);
- setCurrentWindow(0, false);
- }
- void VEditArea::setupUI()
- {
- splitter = new QSplitter(this);
- m_findReplace = new VFindReplaceDialog(this);
- m_findReplace->setOption(FindOption::CaseSensitive,
- g_config->getFindCaseSensitive());
- m_findReplace->setOption(FindOption::WholeWordOnly,
- g_config->getFindWholeWordOnly());
- m_findReplace->setOption(FindOption::RegularExpression,
- g_config->getFindRegularExpression());
- m_findReplace->setOption(FindOption::IncrementalSearch,
- g_config->getFindIncrementalSearch());
- QVBoxLayout *mainLayout = new QVBoxLayout();
- mainLayout->addWidget(splitter);
- mainLayout->addWidget(m_findReplace);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- mainLayout->setSpacing(0);
- mainLayout->setStretch(0, 1);
- mainLayout->setStretch(1, 0);
- setLayout(mainLayout);
- connect(m_findReplace, &VFindReplaceDialog::findTextChanged,
- this, &VEditArea::handleFindTextChanged);
- connect(m_findReplace, &VFindReplaceDialog::findOptionChanged,
- this, &VEditArea::handleFindOptionChanged);
- connect(m_findReplace, SIGNAL(findNext(const QString &, uint, bool)),
- this, SLOT(handleFindNext(const QString &, uint, bool)));
- connect(m_findReplace,
- SIGNAL(replace(const QString &, uint, const QString &, bool)),
- this,
- SLOT(handleReplace(const QString &, uint, const QString &, bool)));
- connect(m_findReplace,
- SIGNAL(replaceAll(const QString &, uint, const QString &)),
- this,
- SLOT(handleReplaceAll(const QString &, uint, const QString &)));
- connect(m_findReplace, &VFindReplaceDialog::dialogClosed,
- this, &VEditArea::handleFindDialogClosed);
- m_findReplace->hide();
- }
- void VEditArea::insertSplitWindow(int idx)
- {
- VEditWindow *win = new VEditWindow(vnote, this);
- splitter->insertWidget(idx, win);
- connect(win, &VEditWindow::tabStatusUpdated,
- this, &VEditArea::handleWindowTabStatusUpdated);
- connect(win, &VEditWindow::requestSplitWindow,
- this, &VEditArea::splitWindow);
- connect(win, &VEditWindow::requestRemoveSplit,
- this, &VEditArea::handleRemoveSplitRequest);
- connect(win, &VEditWindow::getFocused,
- this, &VEditArea::handleWindowFocused);
- connect(win, &VEditWindow::outlineChanged,
- this, &VEditArea::handleOutlineChanged);
- connect(win, &VEditWindow::curHeaderChanged,
- this, &VEditArea::handleCurHeaderChanged);
- connect(win, &VEditWindow::statusMessage,
- this, &VEditArea::handleWindowStatusMessage);
- connect(win, &VEditWindow::vimStatusUpdated,
- this, &VEditArea::handleWindowVimStatusUpdated);
- }
- void VEditArea::handleWindowTabStatusUpdated(const VEditTabInfo &p_info)
- {
- if (splitter->widget(curWindowIndex) == sender()) {
- emit tabStatusUpdated(p_info);
- }
- }
- void VEditArea::handleWindowStatusMessage(const QString &p_msg)
- {
- if (splitter->widget(curWindowIndex) == sender()) {
- emit statusMessage(p_msg);
- }
- }
- void VEditArea::handleWindowVimStatusUpdated(const VVim *p_vim)
- {
- if (splitter->widget(curWindowIndex) == sender()) {
- emit vimStatusUpdated(p_vim);
- }
- }
- void VEditArea::removeSplitWindow(VEditWindow *win)
- {
- if (!win) {
- return;
- }
- win->hide();
- win->setParent(this);
- disconnect(win, 0, this, 0);
- // Should be deleted later
- win->deleteLater();
- }
- // A given file can be opened in multiple split windows. A given file could be
- // opened at most in one tab inside a window.
- void VEditArea::openFile(VFile *p_file, OpenFileMode p_mode)
- {
- if (!p_file) {
- return;
- }
- // If it is DocType::Unknown, open it using system default method.
- if (p_file->getDocType() == DocType::Unknown) {
- QUrl url = QUrl::fromLocalFile(p_file->fetchPath());
- QDesktopServices::openUrl(url);
- return;
- }
- // Find if it has been opened already
- int winIdx, tabIdx;
- bool existFile = false;
- bool setFocus = false;
- auto tabs = findTabsByFile(p_file);
- if (!tabs.empty()) {
- // Current window first
- winIdx = tabs[0].first;
- tabIdx = tabs[0].second;
- for (int i = 0; i < tabs.size(); ++i) {
- if (tabs[i].first == curWindowIndex) {
- winIdx = tabs[i].first;
- tabIdx = tabs[i].second;
- break;
- }
- }
- setFocus = true;
- existFile = true;
- goto out;
- }
- // Open it in current window
- if (curWindowIndex == -1) {
- // insert a new split
- insertSplitWindow(0);
- curWindowIndex = 0;
- }
- winIdx = curWindowIndex;
- tabIdx = openFileInWindow(winIdx, p_file, p_mode);
- out:
- setCurrentTab(winIdx, tabIdx, setFocus);
- if (existFile) {
- if (p_mode == OpenFileMode::Read) {
- readFile();
- } else if (p_mode == OpenFileMode::Edit) {
- editFile();
- }
- }
- }
- QVector<QPair<int, int> > VEditArea::findTabsByFile(const VFile *p_file)
- {
- QVector<QPair<int, int> > tabs;
- int nrWin = splitter->count();
- for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
- VEditWindow *win = getWindow(winIdx);
- int tabIdx = win->findTabByFile(p_file);
- if (tabIdx != -1) {
- QPair<int, int> match;
- match.first = winIdx;
- match.second = tabIdx;
- tabs.append(match);
- }
- }
- return tabs;
- }
- int VEditArea::openFileInWindow(int windowIndex, VFile *p_file, OpenFileMode p_mode)
- {
- Q_ASSERT(windowIndex < splitter->count());
- VEditWindow *win = getWindow(windowIndex);
- return win->openFile(p_file, p_mode);
- }
- void VEditArea::setCurrentTab(int windowIndex, int tabIndex, bool setFocus)
- {
- VEditWindow *win = getWindow(windowIndex);
- win->setCurrentIndex(tabIndex);
- setCurrentWindow(windowIndex, setFocus);
- }
- void VEditArea::setCurrentWindow(int windowIndex, bool setFocus)
- {
- int nrWin = splitter->count();
- curWindowIndex = windowIndex;
- for (int i = 0; i < nrWin; ++i) {
- getWindow(i)->setCurrentWindow(false);
- }
- if (curWindowIndex > -1) {
- getWindow(curWindowIndex)->setCurrentWindow(true);
- if (setFocus) {
- getWindow(curWindowIndex)->focusWindow();
- }
- }
- // Update status
- updateWindowStatus();
- }
- void VEditArea::updateWindowStatus()
- {
- if (curWindowIndex == -1) {
- Q_ASSERT(splitter->count() == 0);
- emit tabStatusUpdated(VEditTabInfo());
- emit outlineChanged(VToc());
- emit curHeaderChanged(VAnchor());
- return;
- }
- VEditWindow *win = getWindow(curWindowIndex);
- win->updateTabStatus();
- win->requestUpdateOutline();
- win->requestUpdateCurHeader();
- }
- bool VEditArea::closeFile(const VFile *p_file, bool p_forced)
- {
- if (!p_file) {
- return true;
- }
- bool ret = false;
- int i = 0;
- while (i < splitter->count()) {
- VEditWindow *win = getWindow(i);
- int nrWin = splitter->count();
- ret = ret || win->closeFile(p_file, p_forced);
- if (nrWin == splitter->count()) {
- ++i;
- }
- }
- updateWindowStatus();
- return ret;
- }
- bool VEditArea::closeFile(const VDirectory *p_dir, bool p_forced)
- {
- if (!p_dir) {
- return true;
- }
- int i = 0;
- while (i < splitter->count()) {
- VEditWindow *win = getWindow(i);
- if (!p_forced) {
- setCurrentWindow(i, false);
- }
- int nrWin = splitter->count();
- if (!win->closeFile(p_dir, p_forced)) {
- return false;
- }
- // win may be removed after closeFile()
- if (nrWin == splitter->count()) {
- ++i;
- }
- }
- updateWindowStatus();
- return true;
- }
- bool VEditArea::closeFile(const VNotebook *p_notebook, bool p_forced)
- {
- if (!p_notebook) {
- return true;
- }
- int i = 0;
- while (i < splitter->count()) {
- VEditWindow *win = getWindow(i);
- if (!p_forced) {
- setCurrentWindow(i, false);
- }
- int nrWin = splitter->count();
- if (!win->closeFile(p_notebook, p_forced)) {
- return false;
- }
- // win may be removed after closeFile()
- if (nrWin == splitter->count()) {
- ++i;
- }
- }
- updateWindowStatus();
- return true;
- }
- bool VEditArea::closeAllFiles(bool p_forced)
- {
- int i = 0;
- while (i < splitter->count()) {
- VEditWindow *win = getWindow(i);
- if (!p_forced) {
- setCurrentWindow(i, false);
- }
- int nrWin = splitter->count();
- if (!win->closeAllFiles(p_forced)) {
- return false;
- }
- if (nrWin == splitter->count()) {
- ++i;
- }
- }
- updateWindowStatus();
- return true;
- }
- void VEditArea::editFile()
- {
- VEditWindow *win = getWindow(curWindowIndex);
- win->editFile();
- }
- void VEditArea::saveFile()
- {
- VEditWindow *win = getWindow(curWindowIndex);
- win->saveFile();
- }
- void VEditArea::readFile()
- {
- VEditWindow *win = getWindow(curWindowIndex);
- win->readFile();
- }
- void VEditArea::saveAndReadFile()
- {
- VEditWindow *win = getWindow(curWindowIndex);
- win->saveAndReadFile();
- }
- void VEditArea::splitWindow(VEditWindow *p_window, bool p_right)
- {
- if (!p_window) {
- return;
- }
- int idx = splitter->indexOf(p_window);
- Q_ASSERT(idx > -1);
- if (p_right) {
- ++idx;
- } else {
- --idx;
- if (idx < 0) {
- idx = 0;
- }
- }
- insertSplitWindow(idx);
- setCurrentWindow(idx, true);
- }
- void VEditArea::splitCurrentWindow()
- {
- if (curWindowIndex > -1) {
- splitWindow(getWindow(curWindowIndex));
- }
- }
- void VEditArea::handleRemoveSplitRequest(VEditWindow *curWindow)
- {
- if (!curWindow || splitter->count() <= 1) {
- return;
- }
- int idx = splitter->indexOf(curWindow);
- // curWindow will be deleted later
- removeSplitWindow(curWindow);
- if (idx >= splitter->count()) {
- idx = splitter->count() - 1;
- }
- setCurrentWindow(idx, true);
- }
- void VEditArea::removeCurrentWindow()
- {
- if (curWindowIndex > -1) {
- handleRemoveSplitRequest(getWindow(curWindowIndex));
- }
- }
- void VEditArea::mousePressEvent(QMouseEvent *event)
- {
- QPoint pos = event->pos();
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- VEditWindow *win = getWindow(i);
- if (win->geometry().contains(pos, true)) {
- setCurrentWindow(i, true);
- break;
- }
- }
- QWidget::mousePressEvent(event);
- }
- void VEditArea::handleWindowFocused()
- {
- QObject *winObject = sender();
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- if (splitter->widget(i) == winObject) {
- setCurrentWindow(i, false);
- break;
- }
- }
- }
- void VEditArea::handleOutlineChanged(const VToc &toc)
- {
- QObject *winObject = sender();
- if (splitter->widget(curWindowIndex) == winObject) {
- emit outlineChanged(toc);
- }
- }
- void VEditArea::handleCurHeaderChanged(const VAnchor &anchor)
- {
- QObject *winObject = sender();
- if (splitter->widget(curWindowIndex) == winObject) {
- emit curHeaderChanged(anchor);
- }
- }
- void VEditArea::handleOutlineItemActivated(const VAnchor &anchor)
- {
- // Notice current window
- getWindow(curWindowIndex)->scrollCurTab(anchor);
- }
- bool VEditArea::isFileOpened(const VFile *p_file)
- {
- return !findTabsByFile(p_file).isEmpty();
- }
- void VEditArea::handleFileUpdated(const VFile *p_file)
- {
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- getWindow(i)->updateFileInfo(p_file);
- }
- }
- void VEditArea::handleDirectoryUpdated(const VDirectory *p_dir)
- {
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- getWindow(i)->updateDirectoryInfo(p_dir);
- }
- }
- void VEditArea::handleNotebookUpdated(const VNotebook *p_notebook)
- {
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- getWindow(i)->updateNotebookInfo(p_notebook);
- }
- }
- VEditTab *VEditArea::currentEditTab()
- {
- if (curWindowIndex == -1) {
- return NULL;
- }
- VEditWindow *win = getWindow(curWindowIndex);
- return win->currentEditTab();
- }
- int VEditArea::windowIndex(const VEditWindow *p_window) const
- {
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- if (p_window == getWindow(i)) {
- return i;
- }
- }
- return -1;
- }
- void VEditArea::moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx)
- {
- int nrWin = splitter->count();
- if (!p_widget || p_fromIdx < 0 || p_fromIdx >= nrWin
- || p_toIdx < 0 || p_toIdx >= nrWin) {
- return;
- }
- qDebug() << "move widget" << p_widget << "from" << p_fromIdx << "to" << p_toIdx;
- if (!getWindow(p_toIdx)->addEditTab(p_widget)) {
- delete p_widget;
- }
- }
- // Only propogate the search in the IncrementalSearch case.
- void VEditArea::handleFindTextChanged(const QString &p_text, uint p_options)
- {
- VEditTab *tab = currentEditTab();
- if (tab) {
- if (p_options & FindOption::IncrementalSearch) {
- tab->findText(p_text, p_options, true);
- }
- }
- }
- void VEditArea::handleFindOptionChanged(uint p_options)
- {
- qDebug() << "find option changed" << p_options;
- g_config->setFindCaseSensitive(p_options & FindOption::CaseSensitive);
- g_config->setFindWholeWordOnly(p_options & FindOption::WholeWordOnly);
- g_config->setFindRegularExpression(p_options & FindOption::RegularExpression);
- g_config->setFindIncrementalSearch(p_options & FindOption::IncrementalSearch);
- }
- void VEditArea::handleFindNext(const QString &p_text, uint p_options,
- bool p_forward)
- {
- qDebug() << "find next" << p_text << p_options << p_forward;
- VEditTab *tab = currentEditTab();
- if (tab) {
- tab->findText(p_text, p_options, false, p_forward);
- }
- }
- void VEditArea::handleReplace(const QString &p_text, uint p_options,
- const QString &p_replaceText, bool p_findNext)
- {
- qDebug() << "replace" << p_text << p_options << "with" << p_replaceText
- << p_findNext;
- VEditTab *tab = currentEditTab();
- if (tab) {
- tab->replaceText(p_text, p_options, p_replaceText, p_findNext);
- }
- }
- void VEditArea::handleReplaceAll(const QString &p_text, uint p_options,
- const QString &p_replaceText)
- {
- qDebug() << "replace all" << p_text << p_options << "with" << p_replaceText;
- VEditTab *tab = currentEditTab();
- if (tab) {
- tab->replaceTextAll(p_text, p_options, p_replaceText);
- }
- }
- // Let VEditArea get focus after VFindReplaceDialog is closed.
- void VEditArea::handleFindDialogClosed()
- {
- if (curWindowIndex == -1) {
- setFocus();
- } else {
- getWindow(curWindowIndex)->focusWindow();
- }
- // Clear all the search highlight.
- int nrWin = splitter->count();
- for (int i = 0; i < nrWin; ++i) {
- getWindow(i)->clearSearchedWordHighlight();
- }
- }
- QString VEditArea::getSelectedText()
- {
- VEditTab *tab = currentEditTab();
- if (tab) {
- return tab->getSelectedText();
- } else {
- return QString();
- }
- }
- int VEditArea::focusNextWindow(int p_biaIdx)
- {
- if (p_biaIdx == 0) {
- return curWindowIndex;
- }
- int newIdx = curWindowIndex + p_biaIdx;
- if (newIdx < 0) {
- newIdx = 0;
- } else if (newIdx >= splitter->count()) {
- newIdx = splitter->count() - 1;
- }
- if (newIdx >= 0 && newIdx < splitter->count()) {
- setCurrentWindow(newIdx, true);
- } else {
- newIdx = -1;
- }
- return newIdx;
- }
- void VEditArea::moveCurrentTabOneSplit(bool p_right)
- {
- getWindow(curWindowIndex)->moveCurrentTabOneSplit(p_right);
- }
- VEditWindow *VEditArea::getCurrentWindow() const
- {
- if (curWindowIndex < 0) {
- return NULL;
- }
- return getWindow(curWindowIndex);
- }
- void VEditArea::registerNavigation(QChar p_majorKey)
- {
- m_majorKey = p_majorKey;
- V_ASSERT(m_keyMap.empty());
- V_ASSERT(m_naviLabels.empty());
- }
- void VEditArea::showNavigation()
- {
- // Clean up.
- m_keyMap.clear();
- for (auto label : m_naviLabels) {
- delete label;
- }
- m_naviLabels.clear();
- if (!isVisible()) {
- return;
- }
- // Generate labels for VEditWindow.
- for (int i = 0; i < 26 && i < splitter->count(); ++i) {
- QChar key('a' + i);
- m_keyMap[key] = getWindow(i);
- QString str = QString(m_majorKey) + key;
- QLabel *label = new QLabel(str, this);
- label->setStyleSheet(g_vnote->getNavigationLabelStyle(str));
- label->move(getWindow(i)->geometry().topLeft());
- label->show();
- m_naviLabels.append(label);
- }
- }
- void VEditArea::hideNavigation()
- {
- m_keyMap.clear();
- for (auto label : m_naviLabels) {
- delete label;
- }
- m_naviLabels.clear();
- }
- bool VEditArea::handleKeyNavigation(int p_key, bool &p_succeed)
- {
- static bool secondKey = false;
- bool ret = false;
- p_succeed = false;
- QChar keyChar = VUtils::keyToChar(p_key);
- if (secondKey && !keyChar.isNull()) {
- secondKey = false;
- p_succeed = true;
- ret = true;
- auto it = m_keyMap.find(keyChar);
- if (it != m_keyMap.end()) {
- setCurrentWindow(splitter->indexOf(it.value()), true);
- }
- } else if (keyChar == m_majorKey) {
- // Major key pressed.
- // Need second key if m_keyMap is not empty.
- if (m_keyMap.isEmpty()) {
- p_succeed = true;
- } else {
- secondKey = true;
- }
- ret = true;
- }
- return ret;
- }
|