support custom startup pages

- Support continuing where user left off on startup;
    - Support recovering the edit/read mode and the anchor position;
- Support opening user-specified files on startup;
- Add config startup_page_type, startup_pages, and last_opened_files;
This commit is contained in:
Le Tan 2017-10-08 20:40:59 +08:00
parent fa870f132e
commit 598e8144bb
33 changed files with 787 additions and 90 deletions

View File

@ -142,7 +142,8 @@ void VNewNotebookDialog::handleBrowseBtnClicked()
}
}
QString dirPath = QFileDialog::getExistingDirectory(this, tr("Select Root Folder Of The Notebook"),
QString dirPath = QFileDialog::getExistingDirectory(this,
tr("Select Root Folder Of The Notebook"),
defaultPath,
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

View File

@ -169,9 +169,6 @@ VGeneralTab::VGeneralTab(QWidget *p_parent)
m_langCombo->addItem(lang.second, lang.first);
}
QLabel *langLabel = new QLabel(tr("Language:"), this);
langLabel->setToolTip(m_langCombo->toolTip());
// System tray checkbox.
m_systemTray = new QCheckBox(tr("System tray"), this);
m_systemTray->setToolTip(tr("Minimized to the system tray after closing VNote"
@ -181,9 +178,13 @@ VGeneralTab::VGeneralTab(QWidget *p_parent)
m_systemTray->setEnabled(false);
#endif
// Startup pages.
QLayout *startupLayout = setupStartupPagesLayout();
QFormLayout *optionLayout = new QFormLayout();
optionLayout->addRow(langLabel, m_langCombo);
optionLayout->addRow(tr("Language:"), m_langCombo);
optionLayout->addRow(m_systemTray);
optionLayout->addRow(tr("Startup pages:"), startupLayout);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addLayout(optionLayout);
@ -191,6 +192,60 @@ VGeneralTab::VGeneralTab(QWidget *p_parent)
setLayout(mainLayout);
}
QLayout *VGeneralTab::setupStartupPagesLayout()
{
m_startupPageTypeCombo = new QComboBox(this);
m_startupPageTypeCombo->setToolTip(tr("Restore tabs or open specific notes on startup"));
m_startupPageTypeCombo->addItem(tr("None"), (int)StartupPageType::None);
m_startupPageTypeCombo->addItem(tr("Continue where you left off"), (int)StartupPageType::ContinueLeftOff);
m_startupPageTypeCombo->addItem(tr("Open specific pages"), (int)StartupPageType::SpecificPages);
connect(m_startupPageTypeCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
this, [this](int p_index) {
int type = m_startupPageTypeCombo->itemData(p_index).toInt();
bool pagesEditVisible = type == (int)StartupPageType::SpecificPages;
m_startupPagesEdit->setVisible(pagesEditVisible);
m_startupPagesAddBtn->setVisible(pagesEditVisible);
});
m_startupPagesEdit = new QPlainTextEdit(this);
m_startupPagesEdit->setToolTip(tr("Absolute path of the notes to open on startup (one note per line)"));
m_startupPagesAddBtn = new QPushButton(tr("Browse"), this);
m_startupPagesAddBtn->setToolTip(tr("Select files to add as startup pages"));
connect(m_startupPagesAddBtn, &QPushButton::clicked,
this, [this]() {
static QString lastPath = QDir::homePath();
QStringList files = QFileDialog::getOpenFileNames(this,
tr("Select Files As Startup Pages"),
lastPath);
if (files.isEmpty()) {
return;
}
// Update lastPath
lastPath = QFileInfo(files[0]).path();
m_startupPagesEdit->appendPlainText(files.join("\n"));
});
QHBoxLayout *startupPagesBtnLayout = new QHBoxLayout();
startupPagesBtnLayout->addStretch();
startupPagesBtnLayout->addWidget(m_startupPagesAddBtn);
QVBoxLayout *startupPagesLayout = new QVBoxLayout();
startupPagesLayout->addWidget(m_startupPagesEdit);
startupPagesLayout->addLayout(startupPagesBtnLayout);
QVBoxLayout *startupLayout = new QVBoxLayout();
startupLayout->addWidget(m_startupPageTypeCombo);
startupLayout->addLayout(startupPagesLayout);
m_startupPagesEdit->hide();
m_startupPagesAddBtn->hide();
return startupLayout;
}
bool VGeneralTab::loadConfiguration()
{
if (!loadLanguage()) {
@ -201,6 +256,10 @@ bool VGeneralTab::loadConfiguration()
return false;
}
if (!loadStartupPageType()) {
return false;
}
return true;
}
@ -214,6 +273,10 @@ bool VGeneralTab::saveConfiguration()
return false;
}
if (!saveStartupPageType()) {
return false;
}
return true;
}
@ -264,6 +327,42 @@ bool VGeneralTab::saveSystemTray()
return true;
}
bool VGeneralTab::loadStartupPageType()
{
StartupPageType type = g_config->getStartupPageType();
bool found = false;
for (int i = 0; i < m_startupPageTypeCombo->count(); ++i) {
if (m_startupPageTypeCombo->itemData(i).toInt() == (int)type) {
found = true;
m_startupPageTypeCombo->setCurrentIndex(i);
}
}
Q_ASSERT(found);
const QStringList &pages = g_config->getStartupPages();
m_startupPagesEdit->setPlainText(pages.join("\n"));
bool pagesEditVisible = type == StartupPageType::SpecificPages;
m_startupPagesEdit->setVisible(pagesEditVisible);
m_startupPagesAddBtn->setVisible(pagesEditVisible);
return true;
}
bool VGeneralTab::saveStartupPageType()
{
StartupPageType type = (StartupPageType)m_startupPageTypeCombo->currentData().toInt();
g_config->setStartupPageType(type);
if (type == StartupPageType::SpecificPages) {
QStringList pages = m_startupPagesEdit->toPlainText().split("\n");
g_config->setStartupPages(pages);
}
return true;
}
VReadEditTab::VReadEditTab(QWidget *p_parent)
: QWidget(p_parent)
{

View File

@ -13,6 +13,8 @@ class QCheckBox;
class QLineEdit;
class QStackedLayout;
class QListWidget;
class QPlainTextEdit;
class QVBoxLayout;
class VGeneralTab : public QWidget
{
@ -23,18 +25,32 @@ public:
bool saveConfiguration();
private:
QLayout *setupStartupPagesLayout();
bool loadLanguage();
bool saveLanguage();
bool loadSystemTray();
bool saveSystemTray();
bool loadStartupPageType();
bool saveStartupPageType();
// Language
QComboBox *m_langCombo;
// System tray
QCheckBox *m_systemTray;
// Startup page type.
QComboBox *m_startupPageTypeCombo;
// Startup pages.
QPlainTextEdit *m_startupPagesEdit;
// Startup pages add files button.
QPushButton *m_startupPagesAddBtn;
static const QVector<QString> c_availableLangs;
};

View File

@ -116,22 +116,10 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
// The file path passed via command line arguments.
QStringList filePaths;
QStringList args = app.arguments();
for (int i = 1; i < args.size(); ++i) {
if (QFileInfo::exists(args[i])) {
QString filePath = args[i];
QFileInfo fi(filePath);
if (fi.isFile()) {
// Need to use absolute path here since VNote may be launched
// in different working directory.
filePath = QDir::cleanPath(fi.absoluteFilePath());
filePaths.append(filePath);
}
}
}
QStringList filePaths = VUtils::filterFilePathsToOpen(app.arguments().mid(1));
qDebug() << "command line arguments" << args;
qDebug() << "command line arguments" << app.arguments();
qDebug() << "files to open from arguments" << filePaths;
if (!canRun) {
// Ask another instance to open files passed in.
@ -178,7 +166,9 @@ int main(int argc, char *argv[])
w.show();
w.openExternalFiles(filePaths);
w.openFiles(filePaths);
w.openStartupPages();
return app.exec();
}

View File

@ -141,6 +141,16 @@ enable_compact_mode=false
; Whether enable tools dock widget
tools_dock_checked=true
; Pages to open on startup
; 0 - none; 1 - Continue where you left off; 2 - specific pages
startup_page_type=0
; Specific pages to open on startup when startup_page_type is 2
; A list of file path separated by ,
; Notice: should escape \ by \\
; C:\users\vnote\vnote.md -> C:\\users\\vnote\\vnote.md
startup_pages=
[web]
; Location and configuration for Mathjax
mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML

View File

@ -77,7 +77,8 @@ SOURCES += main.cpp\
dialog/vconfirmdeletiondialog.cpp \
vnotefile.cpp \
vattachmentlist.cpp \
dialog/vsortdialog.cpp
dialog/vsortdialog.cpp \
vfilesessioninfo.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -142,7 +143,8 @@ HEADERS += vmainwindow.h \
dialog/vconfirmdeletiondialog.h \
vnotefile.h \
vattachmentlist.h \
dialog/vsortdialog.h
dialog/vsortdialog.h \
vfilesessioninfo.h
RESOURCES += \
vnote.qrc \

View File

@ -959,3 +959,30 @@ void VUtils::addErrMsg(QString *p_msg, const QString &p_str)
*p_msg = *p_msg + '\n' + p_str;
}
}
QStringList VUtils::filterFilePathsToOpen(const QStringList &p_files)
{
QStringList paths;
for (int i = 0; i < p_files.size(); ++i) {
QString path = validFilePathToOpen(p_files[i]);
if (!path.isEmpty()) {
paths.append(path);
}
}
return paths;
}
QString VUtils::validFilePathToOpen(const QString &p_file)
{
if (QFileInfo::exists(p_file)) {
QFileInfo fi(p_file);
if (fi.isFile()) {
// Need to use absolute path here since VNote may be launched
// in different working directory.
return QDir::cleanPath(fi.absoluteFilePath());
}
}
return QString();
}

View File

@ -232,6 +232,13 @@ public:
// Assign @p_str to @p_msg if it is not NULL.
static void addErrMsg(QString *p_msg, const QString &p_str);
// Check each file of @p_files and return valid ones for VNote to open.
static QStringList filterFilePathsToOpen(const QStringList &p_files);
// Return the normalized file path of @p_file if it is valid to open.
// Return empty if it is not valid.
static QString validFilePathToOpen(const QString &p_file);
// Regular expression for image link.
// ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" )
// Captured texts (need to be trimmed):

View File

@ -275,7 +275,7 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
// Remove current window split.
m_mainWindow->editArea->removeCurrentWindow();
QWidget *nextFocus = m_mainWindow->editArea->currentEditTab();
QWidget *nextFocus = m_mainWindow->editArea->getCurrentTab();
m_widgetBeforeCaptain = nextFocus ? nextFocus : m_mainWindow->getFileList();
break;
}
@ -304,7 +304,7 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
m_mainWindow->closeCurrentFile();
// m_widgetBeforeCaptain may be the closed tab which will cause crash.
QWidget *nextFocus = m_mainWindow->editArea->currentEditTab();
QWidget *nextFocus = m_mainWindow->editArea->getCurrentTab();
m_widgetBeforeCaptain = nextFocus ? nextFocus : m_mainWindow->getFileList();
break;
}

View File

@ -235,6 +235,18 @@ void VConfigManager::initialize()
m_enableCompactMode = getConfigFromSettings("global",
"enable_compact_mode").toBool();
int tmpStartupPageMode = getConfigFromSettings("global",
"startup_page_type").toInt();
if (tmpStartupPageMode < (int)StartupPageType::Invalid
&& tmpStartupPageMode >= (int)StartupPageType::None) {
m_startupPageType = (StartupPageType)tmpStartupPageMode;
} else {
m_startupPageType = StartupPageType::None;
}
m_startupPages = getConfigFromSettings("global",
"startup_pages").toStringList();
initFromSessionSettings();
}
@ -242,6 +254,8 @@ void VConfigManager::initSettings()
{
Q_ASSERT(!userSettings && !defaultSettings && !m_sessionSettings);
const char *codecForIni = "UTF-8";
// vnote.ini.
// First try to read vnote.ini from the directory of the executable.
QString userIniPath = QDir(QCoreApplication::applicationDirPath()).filePath(c_defaultConfigFile);
@ -257,15 +271,19 @@ void VConfigManager::initSettings()
this);
}
userSettings->setIniCodec(codecForIni);
qDebug() << "use user config" << userSettings->fileName();
// Default vnote.ini from resource file.
defaultSettings = new QSettings(c_defaultConfigFilePath, QSettings::IniFormat, this);
defaultSettings->setIniCodec(codecForIni);
// session.ini.
m_sessionSettings = new QSettings(QDir(getConfigFolder()).filePath(c_sessionConfigFile),
QSettings::IniFormat,
this);
m_sessionSettings->setIniCodec(codecForIni);
}
void VConfigManager::initFromSessionSettings()
@ -364,7 +382,7 @@ QVariant VConfigManager::getConfigFromSettings(const QString &section, const QSt
// First, look up the user-scoped config file
QVariant value = getConfigFromSettingsBySectionKey(userSettings, section, key);
if (!value.isNull()) {
qDebug() << "user config:" << (section + "/" + key) << value.toString();
qDebug() << "user config:" << (section + "/" + key) << value;
return value;
}
@ -376,13 +394,13 @@ void VConfigManager::setConfigToSettings(const QString &section, const QString &
{
// Set the user-scoped config file
setConfigToSettingsBySectionKey(userSettings, section, key, value);
qDebug() << "set user config:" << (section + "/" + key) << value.toString();
qDebug() << "set user config:" << (section + "/" + key) << value;
}
QVariant VConfigManager::getDefaultConfig(const QString &p_section, const QString &p_key) const
{
QVariant value = getConfigFromSettingsBySectionKey(defaultSettings, p_section, p_key);
qDebug() << "default config:" << (p_section + "/" + p_key) << value.toString();
qDebug() << "default config:" << (p_section + "/" + p_key) << value;
return value;
}
@ -1090,3 +1108,41 @@ void VConfigManager::initDocSuffixes()
qDebug() << "doc suffixes" << m_docSuffixes;
}
QVector<VFileSessionInfo> VConfigManager::getLastOpenedFiles()
{
QVector<VFileSessionInfo> files;
int size = m_sessionSettings->beginReadArray("last_opened_files");
for (int i = 0; i < size; ++i) {
m_sessionSettings->setArrayIndex(i);
files.push_back(VFileSessionInfo::fromSettings(m_sessionSettings));
}
m_sessionSettings->endArray();
qDebug() << "read" << files.size()
<< "items from [last_opened_files] section";
return files;
}
void VConfigManager::setLastOpenedFiles(const QVector<VFileSessionInfo> &p_files)
{
const QString section("last_opened_files");
// Clear it first
m_sessionSettings->beginGroup(section);
m_sessionSettings->remove("");
m_sessionSettings->endGroup();
m_sessionSettings->beginWriteArray(section);
for (int i = 0; i < p_files.size(); ++i) {
m_sessionSettings->setArrayIndex(i);
const VFileSessionInfo &info = p_files[i];
info.toSettings(m_sessionSettings);
}
m_sessionSettings->endArray();
qDebug() << "write" << p_files.size()
<< "items in [last_opened_files] section";
}

View File

@ -11,6 +11,8 @@
#include "hgmarkdownhighlighter.h"
#include "vmarkdownconverter.h"
#include "vconstants.h"
#include "vfilesessioninfo.h"
class QJsonObject;
class QString;
@ -300,6 +302,18 @@ public:
bool getEnableCompactMode() const;
void setEnableCompactMode(bool p_enabled);
StartupPageType getStartupPageType() const;
void setStartupPageType(StartupPageType p_type);
const QStringList &getStartupPages() const;
void setStartupPages(const QStringList &p_pages);
// Read last opened files from [last_opened_files] of session.ini.
QVector<VFileSessionInfo> getLastOpenedFiles();
// Write last opened files to [last_opened_files] of session.ini.
void setLastOpenedFiles(const QVector<VFileSessionInfo> &p_files);
// Return the configured key sequence of @p_operation.
// Return empty if there is no corresponding config.
QString getShortcutKeySequence(const QString &p_operation) const;
@ -635,6 +649,12 @@ private:
// Whether put folder and note panel in one single column.
bool m_enableCompactMode;
// Type of the pages to open on startup.
StartupPageType m_startupPageType;
// File paths to open on startup.
QStringList m_startupPages;
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;
@ -1666,4 +1686,34 @@ inline void VConfigManager::setEnableCompactMode(bool p_enabled)
setConfigToSettings("global", "enable_compact_mode", m_enableCompactMode);
}
inline StartupPageType VConfigManager::getStartupPageType() const
{
return m_startupPageType;
}
inline void VConfigManager::setStartupPageType(StartupPageType p_type)
{
if (m_startupPageType == p_type) {
return;
}
m_startupPageType = p_type;
setConfigToSettings("global", "startup_page_type", (int)m_startupPageType);
}
inline const QStringList &VConfigManager::getStartupPages() const
{
return m_startupPages;
}
inline void VConfigManager::setStartupPages(const QStringList &p_pages)
{
if (m_startupPages == p_pages) {
return;
}
m_startupPages = p_pages;
setConfigToSettings("global", "startup_pages", m_startupPages);
}
#endif // VCONFIGMANAGER_H

View File

@ -1,6 +1,8 @@
#ifndef VCONSTANTS_H
#define VCONSTANTS_H
#include <QString>
// Html: rich text file;
// Markdown: Markdown text file;
// List: Infinite list file like WorkFlowy;
@ -22,7 +24,7 @@ namespace ClipboardConfig
static const QString c_dirs = "dirs";
}
enum class OpenFileMode {Read = 0, Edit};
enum class OpenFileMode {Read = 0, Edit, Invalid };
static const qreal c_webZoomFactorMax = 5;
static const qreal c_webZoomFactorMin = 0.25;
@ -97,4 +99,13 @@ enum class LineNumberType
CodeBlock
};
// Pages to open on start up.
enum class StartupPageType
{
None = 0,
ContinueLeftOff = 1,
SpecificPages = 2,
Invalid
};
#endif

View File

@ -163,6 +163,9 @@ signals:
// Request the edit tab to close find and replace dialog.
void requestCloseFindReplaceDialog();
// Emit when all initialization is ready.
void ready();
public slots:
virtual void highlightCurrentLine();

View File

@ -7,6 +7,7 @@
#include "vfile.h"
#include "dialog/vfindreplacedialog.h"
#include "utils/vutils.h"
#include "vfilesessioninfo.h"
extern VConfigManager *g_config;
extern VNote *g_vnote;
@ -119,17 +120,17 @@ void VEditArea::removeSplitWindow(VEditWindow *win)
win->deleteLater();
}
void VEditArea::openFile(VFile *p_file, OpenFileMode p_mode, bool p_forceMode)
VEditTab *VEditArea::openFile(VFile *p_file, OpenFileMode p_mode, bool p_forceMode)
{
if (!p_file) {
return;
return NULL;
}
// 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;
return NULL;
}
// Find if it has been opened already
@ -165,6 +166,8 @@ void VEditArea::openFile(VFile *p_file, OpenFileMode p_mode, bool p_forceMode)
tabIdx = openFileInWindow(winIdx, p_file, p_mode);
out:
VEditTab *tab = getTab(winIdx, tabIdx);
setCurrentTab(winIdx, tabIdx, setFocus);
if (existFile && p_forceMode) {
@ -174,6 +177,8 @@ out:
editFile();
}
}
return tab;
}
QVector<QPair<int, int> > VEditArea::findTabsByFile(const VFile *p_file)
@ -482,13 +487,35 @@ void VEditArea::handleNotebookUpdated(const VNotebook *p_notebook)
}
}
VEditTab *VEditArea::currentEditTab()
VEditTab *VEditArea::getCurrentTab() const
{
if (curWindowIndex == -1) {
return NULL;
}
VEditWindow *win = getWindow(curWindowIndex);
return win->currentEditTab();
return win->getCurrentTab();
}
VEditTab *VEditArea::getTab(int p_winIdx, int p_tabIdx) const
{
VEditWindow *win = getWindow(p_winIdx);
if (!win) {
return NULL;
}
return win->getTab(p_tabIdx);
}
QVector<VEditTabInfo> VEditArea::getAllTabsInfo() const
{
QVector<VEditTabInfo> tabs;
int nrWin = splitter->count();
for (int i = 0; i < nrWin; ++i) {
tabs.append(getWindow(i)->getAllTabsInfo());
}
return tabs;
}
int VEditArea::windowIndex(const VEditWindow *p_window) const
@ -518,7 +545,7 @@ void VEditArea::moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx)
// Only propogate the search in the IncrementalSearch case.
void VEditArea::handleFindTextChanged(const QString &p_text, uint p_options)
{
VEditTab *tab = currentEditTab();
VEditTab *tab = getCurrentTab();
if (tab) {
if (p_options & FindOption::IncrementalSearch) {
tab->findText(p_text, p_options, true);
@ -539,7 +566,7 @@ 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();
VEditTab *tab = getCurrentTab();
if (tab) {
tab->findText(p_text, p_options, false, p_forward);
}
@ -550,7 +577,7 @@ void VEditArea::handleReplace(const QString &p_text, uint p_options,
{
qDebug() << "replace" << p_text << p_options << "with" << p_replaceText
<< p_findNext;
VEditTab *tab = currentEditTab();
VEditTab *tab = getCurrentTab();
if (tab) {
tab->replaceText(p_text, p_options, p_replaceText, p_findNext);
}
@ -560,7 +587,7 @@ 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();
VEditTab *tab = getCurrentTab();
if (tab) {
tab->replaceTextAll(p_text, p_options, p_replaceText);
}
@ -584,7 +611,7 @@ void VEditArea::handleFindDialogClosed()
QString VEditArea::getSelectedText()
{
VEditTab *tab = currentEditTab();
VEditTab *tab = getCurrentTab();
if (tab) {
return tab->getSelectedText();
} else {
@ -694,3 +721,29 @@ bool VEditArea::handleKeyNavigation(int p_key, bool &p_succeed)
return ret;
}
int VEditArea::openFiles(const QVector<VFileSessionInfo> &p_files)
{
int nrOpened = 0;
for (auto const & info : p_files) {
QString filePath = VUtils::validFilePathToOpen(info.m_file);
if (filePath.isEmpty()) {
continue;
}
VFile *file = g_vnote->getFile(filePath);
if (!file) {
continue;
}
VEditTab *tab = openFile(file, info.m_mode, true);
++nrOpened;
VEditTabInfo tabInfo;
tabInfo.m_editTab = tab;
info.toEditTabInfo(&tabInfo);
tab->tryRestoreFromTabInfo(tabInfo);
}
return nrOpened;
}

View File

@ -35,17 +35,31 @@ public:
bool closeFile(const VFile *p_file, bool p_forced);
bool closeFile(const VDirectory *p_dir, bool p_forced);
bool closeFile(const VNotebook *p_notebook, bool p_forced);
// Returns current edit tab.
VEditTab *currentEditTab();
// Returns the count of VEditWindow.
inline int windowCount() const;
// Return current edit window.
VEditWindow *getCurrentWindow() const;
// Return current edit tab.
VEditTab *getCurrentTab() const;
// Return the @p_tabIdx tab in the @p_winIdx window.
VEditTab *getTab(int p_winIdx, int p_tabIdx) const;
// Return VEditTabInfo of all edit tabs.
QVector<VEditTabInfo> getAllTabsInfo() const;
// Return the count of VEditWindow.
int windowCount() const;
// Returns the index of @p_window.
int windowIndex(const VEditWindow *p_window) const;
// Move tab widget @p_widget from window @p_fromIdx to @p_toIdx.
// @p_widget has been removed from the original window.
// If fail, just delete the p_widget.
void moveTab(QWidget *p_widget, int p_fromIdx, int p_toIdx);
inline VFindReplaceDialog *getFindReplaceDialog() const;
VFindReplaceDialog *getFindReplaceDialog() const;
// Return selected text of current edit tab.
QString getSelectedText();
void splitCurrentWindow();
@ -54,7 +68,6 @@ public:
// Return the new current window index, otherwise, return -1.
int focusNextWindow(int p_biaIdx);
void moveCurrentTabOneSplit(bool p_right);
VEditWindow *getCurrentWindow() const;
// Implementations for VNavigationMode.
void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE;
@ -62,6 +75,9 @@ public:
void hideNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
// Open files @p_files.
int openFiles(const QVector<VFileSessionInfo> &p_files);
signals:
// Emit when current window's tab status updated.
void tabStatusUpdated(const VEditTabInfo &p_info);
@ -84,7 +100,7 @@ public slots:
// @p_forceMode is true.
// 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 openFile(VFile *p_file, OpenFileMode p_mode, bool p_forceMode = false);
VEditTab *openFile(VFile *p_file, OpenFileMode p_mode, bool p_forceMode = false);
void editFile();
void saveFile();
@ -128,7 +144,9 @@ private:
int openFileInWindow(int windowIndex, VFile *p_file, OpenFileMode p_mode);
void setCurrentTab(int windowIndex, int tabIndex, bool setFocus);
void setCurrentWindow(int windowIndex, bool setFocus);
inline VEditWindow *getWindow(int windowIndex) const;
VEditWindow *getWindow(int windowIndex) const;
void insertSplitWindow(int idx);
void removeSplitWindow(VEditWindow *win);

View File

@ -82,13 +82,37 @@ void VEditTab::updateStatus()
{
m_modified = m_file->isModified();
emit statusUpdated(createEditTabInfo());
emit statusUpdated(fetchTabInfo());
}
VEditTabInfo VEditTab::createEditTabInfo()
VEditTabInfo VEditTab::fetchTabInfo()
{
VEditTabInfo info;
info.m_editTab = this;
return info;
}
VAnchor VEditTab::getCurrentHeader() const
{
return m_curHeader;
}
void VEditTab::tryRestoreFromTabInfo(const VEditTabInfo &p_info)
{
if (p_info.m_editTab != this) {
// Clear and return.
m_infoToRestore.m_editTab = NULL;
return;
}
if (restoreFromTabInfo(p_info)) {
// Clear and return.
m_infoToRestore.m_editTab = NULL;
return;
}
// Save it and restore later.
m_infoToRestore = p_info;
qDebug() << "save info for restore later" << p_info.m_anchorIndex;
}

View File

@ -69,7 +69,16 @@ public:
virtual void requestUpdateVimStatus() = 0;
// Insert decoration markers or decorate selected text.
virtual void decorateText(TextDecoration p_decoration) {Q_UNUSED(p_decoration);};
virtual void decorateText(TextDecoration p_decoration) {Q_UNUSED(p_decoration);}
// Create a filled VEditTabInfo.
virtual VEditTabInfo fetchTabInfo();
VAnchor getCurrentHeader() const;
// Restore status from @p_info.
// If this tab is not ready yet, it will restore once it is ready.
void tryRestoreFromTabInfo(const VEditTabInfo &p_info);
public slots:
// Enter edit mode
@ -87,8 +96,9 @@ protected:
// Called to zoom in/out content.
virtual void zoom(bool p_zoomIn, qreal p_step = 0.25) = 0;
// Create a filled VEditTabInfo.
virtual VEditTabInfo createEditTabInfo();
// Restore from @p_fino.
// Return true if succeed.
virtual bool restoreFromTabInfo(const VEditTabInfo &p_info) = 0;
// File related to this tab.
QPointer<VFile> m_file;
@ -98,6 +108,9 @@ protected:
VAnchor m_curHeader;
VEditArea *m_editArea;
// Tab info to restore from once ready.
VEditTabInfo m_infoToRestore;
signals:
void getFocused();

View File

@ -6,8 +6,13 @@ class VEditTab;
struct VEditTabInfo
{
VEditTabInfo()
: m_editTab(NULL), m_cursorBlockNumber(-1), m_cursorPositionInBlock(-1),
m_blockCount(-1) {}
: m_editTab(NULL),
m_cursorBlockNumber(-1),
m_cursorPositionInBlock(-1),
m_blockCount(-1),
m_anchorIndex(-1)
{
}
VEditTab *m_editTab;
@ -15,6 +20,9 @@ struct VEditTabInfo
int m_cursorBlockNumber;
int m_cursorPositionInBlock;
int m_blockCount;
// Anchor index in outline.
int m_anchorIndex;
};
#endif // VEDITTABINFO_H

View File

@ -794,15 +794,30 @@ void VEditWindow::updateNotebookInfo(const VNotebook *p_notebook)
}
}
VEditTab *VEditWindow::currentEditTab()
VEditTab *VEditWindow::getCurrentTab() const
{
int idx = currentIndex();
if (idx == -1) {
return NULL;
}
return getTab(idx);
}
QVector<VEditTabInfo> VEditWindow::getAllTabsInfo() const
{
int nrTab = count();
QVector<VEditTabInfo> tabs;
tabs.reserve(nrTab);
for (int i = 0; i < nrTab; ++i) {
VEditTab *editTab = getTab(i);
tabs.push_back(editTab->fetchTabInfo());
}
return tabs;
}
void VEditWindow::handleLocateAct()
{
int tab = m_locateAct->data().toInt();
@ -1014,7 +1029,7 @@ void VEditWindow::dropEvent(QDropEvent *p_event)
if (!files.isEmpty()) {
focusWindow();
g_vnote->getMainWindow()->openExternalFiles(files);
g_vnote->getMainWindow()->openFiles(files);
}
p_event->acceptProposedAction();

View File

@ -40,7 +40,13 @@ public:
void updateFileInfo(const VFile *p_file);
void updateDirectoryInfo(const VDirectory *p_dir);
void updateNotebookInfo(const VNotebook *p_notebook);
VEditTab *currentEditTab();
VEditTab *getCurrentTab() const;
VEditTab *getTab(int tabIndex) const;
QVector<VEditTabInfo> getAllTabsInfo() const;
// Insert a tab with @p_widget. @p_widget is a fully initialized VEditTab.
bool addEditTab(QWidget *p_widget);
// Set whether it is the current window.
@ -53,7 +59,6 @@ public:
bool activateTab(int p_sequence);
// Switch to previous activated tab.
bool alternateTab();
VEditTab *getTab(int tabIndex) const;
// Ask tab @p_index to update its status and propogate.
// The status here means tab status, outline, current header.
@ -124,9 +129,9 @@ private:
int insertEditTab(int p_index, VFile *p_file, QWidget *p_page);
int appendEditTab(VFile *p_file, QWidget *p_page);
int openFileInTab(VFile *p_file, OpenFileMode p_mode);
inline QString generateTooltip(const VFile *p_file) const;
inline QString generateTabText(int p_index, const QString &p_name,
bool p_modified, bool p_modifiable) const;
QString generateTooltip(const VFile *p_file) const;
QString generateTabText(int p_index, const QString &p_name,
bool p_modified, bool p_modifiable) const;
bool canRemoveSplit();
// Move tab at @p_tabIdx one split window.

View File

@ -374,7 +374,7 @@ void VFileList::newFile()
// Move cursor down if content has been inserted.
if (contentInserted) {
const VMdTab *tab = dynamic_cast<VMdTab *>(editArea->currentEditTab());
const VMdTab *tab = dynamic_cast<VMdTab *>(editArea->getCurrentTab());
if (tab) {
VMdEdit *edit = dynamic_cast<VMdEdit *>(tab->getEditor());
if (edit && edit->getFile() == file) {

74
src/vfilesessioninfo.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "vfilesessioninfo.h"
#include <QSettings>
#include "vedittabinfo.h"
#include "vtoc.h"
#include "vedittab.h"
VFileSessionInfo::VFileSessionInfo()
: m_mode(OpenFileMode::Read),
m_anchorIndex(-1),
m_cursorBlockNumber(-1),
m_cursorPositionInBlock(-1)
{
}
VFileSessionInfo::VFileSessionInfo(const QString &p_file,
OpenFileMode p_mode)
: m_file(p_file),
m_mode(p_mode),
m_anchorIndex(-1),
m_cursorBlockNumber(-1),
m_cursorPositionInBlock(-1)
{
}
// Fetch VFileSessionInfo from @p_tabInfo.
VFileSessionInfo VFileSessionInfo::fromEditTabInfo(const VEditTabInfo *p_tabInfo)
{
Q_ASSERT(p_tabInfo);
VEditTab *tab = p_tabInfo->m_editTab;
VFileSessionInfo info(tab->getFile()->fetchPath(),
tab->isEditMode() ? OpenFileMode::Edit : OpenFileMode::Read);
info.m_anchorIndex = p_tabInfo->m_anchorIndex;
info.m_cursorBlockNumber = p_tabInfo->m_cursorBlockNumber;
info.m_cursorPositionInBlock = p_tabInfo->m_cursorPositionInBlock;
return info;
}
void VFileSessionInfo::toEditTabInfo(VEditTabInfo *p_tabInfo) const
{
p_tabInfo->m_anchorIndex = m_anchorIndex;
p_tabInfo->m_cursorBlockNumber = m_cursorBlockNumber;
p_tabInfo->m_cursorPositionInBlock = m_cursorPositionInBlock;
}
VFileSessionInfo VFileSessionInfo::fromSettings(const QSettings *p_settings)
{
VFileSessionInfo info;
info.m_file = p_settings->value(FileSessionConfig::c_file).toString();
int tmpMode = p_settings->value(FileSessionConfig::c_mode).toInt();
if (tmpMode >= (int)OpenFileMode::Read && tmpMode < (int)OpenFileMode::Invalid) {
info.m_mode = (OpenFileMode)tmpMode;
} else {
info.m_mode = OpenFileMode::Read;
}
info.m_anchorIndex = p_settings->value(FileSessionConfig::c_anchorIndex).toInt();
info.m_cursorBlockNumber = p_settings->value(FileSessionConfig::c_cursorBlockNumber).toInt();
info.m_cursorPositionInBlock = p_settings->value(FileSessionConfig::c_cursorPositionInBlock).toInt();
return info;
}
void VFileSessionInfo::toSettings(QSettings *p_settings) const
{
p_settings->setValue(FileSessionConfig::c_file, m_file);
p_settings->setValue(FileSessionConfig::c_mode, (int)m_mode);
p_settings->setValue(FileSessionConfig::c_anchorIndex, m_anchorIndex);
p_settings->setValue(FileSessionConfig::c_cursorBlockNumber, m_cursorBlockNumber);
p_settings->setValue(FileSessionConfig::c_cursorPositionInBlock, m_cursorPositionInBlock);
}

57
src/vfilesessioninfo.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef VFILESESSIONINFO_H
#define VFILESESSIONINFO_H
#include "vconstants.h"
struct VEditTabInfo;
class QSettings;
namespace FileSessionConfig
{
static const QString c_file = "file";
static const QString c_mode = "mode";
// Index in outline of the anchor.
static const QString c_anchorIndex = "anchor_index";
static const QString c_cursorBlockNumber = "cursor_block_number";
static const QString c_cursorPositionInBlock = "cursor_position_in_block";
}
// Information about an opened file (session).
class VFileSessionInfo
{
public:
VFileSessionInfo();
VFileSessionInfo(const QString &p_file,
OpenFileMode p_mode);
// Fetch VFileSessionInfo from @p_tabInfo.
static VFileSessionInfo fromEditTabInfo(const VEditTabInfo *p_tabInfo);
// Fill corresponding fields of @p_tabInfo.
void toEditTabInfo(VEditTabInfo *p_tabInfo) const;
// Fetch VFileSessionInfo from @p_settings.
static VFileSessionInfo fromSettings(const QSettings *p_settings);
void toSettings(QSettings *p_settings) const;
// Absolute path of the file.
QString m_file;
// Mode of this file in this session.
OpenFileMode m_mode;
// Index in outline of the anchor.
int m_anchorIndex;
// Block number of cursor block.
int m_cursorBlockNumber;
// Position in block of cursor.
int m_cursorPositionInBlock;
};
#endif // VFILESESSIONINFO_H

View File

@ -252,3 +252,12 @@ void VHtmlTab::requestUpdateVimStatus()
{
m_editor->requestUpdateVimStatus();
}
bool VHtmlTab::restoreFromTabInfo(const VEditTabInfo &p_info)
{
if (p_info.m_editTab != this) {
return false;
}
return true;
}

View File

@ -78,6 +78,10 @@ private:
// Focus the proper child widget.
void focusChild() Q_DECL_OVERRIDE;
// Restore from @p_fino.
// Return true if succeed.
bool restoreFromTabInfo(const VEditTabInfo &p_info) Q_DECL_OVERRIDE;
VEdit *m_editor;
};
#endif // VHTMLTAB_H

View File

@ -29,6 +29,7 @@
#include "vnotefile.h"
#include "vbuttonwithwidget.h"
#include "vattachmentlist.h"
#include "vfilesessioninfo.h"
extern VConfigManager *g_config;
@ -766,7 +767,7 @@ void VMainWindow::initFileMenu()
// Update lastPath
lastPath = QFileInfo(files[0]).path();
openExternalFiles(files);
openFiles(VUtils::filterFilePathsToOpen(files));
});
fileMenu->addAction(openAct);
@ -1956,12 +1957,33 @@ void VMainWindow::closeEvent(QCloseEvent *event)
}
if (isExit || !m_trayIcon->isVisible()) {
// Get all the opened tabs.
bool saveOpenedNotes = g_config->getStartupPageType() == StartupPageType::ContinueLeftOff;
QVector<VFileSessionInfo> fileInfos;
QVector<VEditTabInfo> tabs;
if (saveOpenedNotes) {
tabs = editArea->getAllTabsInfo();
fileInfos.reserve(tabs.size());
for (auto const & tab : tabs) {
VFileSessionInfo info = VFileSessionInfo::fromEditTabInfo(&tab);
fileInfos.push_back(info);
qDebug() << "file session:" << info.m_file << (info.m_mode == OpenFileMode::Edit);
}
}
if (!editArea->closeAllFiles(false)) {
// Fail to close all the opened files, cancel closing app.
event->ignore();
return;
}
if (saveOpenedNotes) {
g_config->setLastOpenedFiles(fileInfos);
}
QMainWindow::closeEvent(event);
} else {
hide();
@ -2059,7 +2081,7 @@ void VMainWindow::insertImage()
if (!m_curTab) {
return;
}
Q_ASSERT(m_curTab == editArea->currentEditTab());
Q_ASSERT(m_curTab == editArea->getCurrentTab());
m_curTab->insertImage();
}
@ -2310,9 +2332,8 @@ bool VMainWindow::tryOpenInternalFile(const QString &p_filePath)
return false;
}
void VMainWindow::openExternalFiles(const QStringList &p_files, bool p_forceOrphan)
void VMainWindow::openFiles(const QStringList &p_files, bool p_forceOrphan)
{
qDebug() << "open external files" << p_files;
for (int i = 0; i < p_files.size(); ++i) {
VFile *file = NULL;
if (!p_forceOrphan) {
@ -2344,7 +2365,7 @@ void VMainWindow::checkSharedMemory()
QStringList files = m_guard->fetchFilesToOpen();
if (!files.isEmpty()) {
qDebug() << "shared memory fetch files" << files;
openExternalFiles(files);
openFiles(files);
// Eliminate the signal.
m_guard->fetchAskedToShow();
@ -2416,3 +2437,28 @@ void VMainWindow::showAttachmentList()
m_attachmentBtn->showPopupWidget();
}
}
void VMainWindow::openStartupPages()
{
StartupPageType type = g_config->getStartupPageType();
switch (type) {
case StartupPageType::ContinueLeftOff:
{
QVector<VFileSessionInfo> files = g_config->getLastOpenedFiles();
qDebug() << "open" << files.size() << "last opened files";
editArea->openFiles(files);
break;
}
case StartupPageType::SpecificPages:
{
QStringList pagesToOpen = VUtils::filterFilePathsToOpen(g_config->getStartupPages());
qDebug() << "open startup pages" << pagesToOpen;
openFiles(pagesToOpen);
break;
}
default:
break;
}
}

View File

@ -68,10 +68,10 @@ public:
// View and edit the information of @p_file, which is an orphan file.
void editOrphanFileInfo(VFile *p_file);
// Open external files @p_files as orphan files.
// Open files @p_files as orphan files or internal note files.
// If @p_forceOrphan is false, for each file, VNote will try to find out if
// it is a note inside VNote. If yes, VNote will open it as internal file.
void openExternalFiles(const QStringList &p_files, bool p_forceOrphan = false);
void openFiles(const QStringList &p_files, bool p_forceOrphan = false);
// Try to open @p_filePath as internal note.
bool tryOpenInternalFile(const QString &p_filePath);
@ -82,6 +82,9 @@ public:
// Popup the attachment list if it is enabled.
void showAttachmentList();
// Open startup pages according to configuration.
void openStartupPages();
private slots:
void importNoteFromFile();
void viewSettings();

View File

@ -539,7 +539,7 @@ void VMdEdit::updateOutline(const QVector<VElementRegion> &p_headerRegions)
updateCurHeader();
}
void VMdEdit::scrollToHeader(const VAnchor &p_anchor)
void VMdEdit::scrollToAnchor(const VAnchor &p_anchor)
{
if (p_anchor.lineNumber == -1
|| p_anchor.m_outlineIndex < 0) {
@ -557,6 +557,20 @@ void VMdEdit::scrollToHeader(const VAnchor &p_anchor)
scrollToLine(p_anchor.lineNumber);
}
bool VMdEdit::scrollToAnchor(int p_anchorIndex)
{
if (p_anchorIndex >= 0 && p_anchorIndex < m_headers.size()) {
int lineNumber = m_headers[p_anchorIndex].lineNumber;
if (lineNumber >= 0) {
scrollToLine(lineNumber);
return true;
}
}
return false;
}
QString VMdEdit::toPlainTextWithoutImg()
{
QString text;
@ -838,5 +852,7 @@ void VMdEdit::finishOneAsyncJob(int p_idx)
emit statusChanged();
updateOutline(m_mdHighlighter->getHeaderRegions());
emit ready();
}
}

View File

@ -32,7 +32,11 @@ public:
// @p_path is the absolute path of the inserted image.
void imageInserted(const QString &p_path);
void scrollToHeader(const VAnchor &p_anchor);
void scrollToAnchor(const VAnchor &p_anchor);
// Scroll to anchor given the the index in outline.
// Return true if @p_anchorIndex is valid.
bool scrollToAnchor(int p_anchorIndex);
// Like toPlainText(), but remove image preview characters.
QString toPlainTextWithoutImg();

View File

@ -77,27 +77,46 @@ void VMdTab::showFileReadMode()
m_stacks->setCurrentWidget(m_webViewer);
clearSearchedWordHighlight();
scrollWebViewToHeader(outlineIndex);
scrollWebViewToAnchor(outlineIndex);
updateStatus();
}
void VMdTab::scrollWebViewToHeader(int p_outlineIndex)
bool VMdTab::scrollWebViewToAnchor(int p_anchorIndex, bool p_strict)
{
QString anchor;
m_curHeader = VAnchor(m_file, anchor, -1, p_outlineIndex);
VAnchor anch(m_file, anchor, -1, p_anchorIndex);
if (p_outlineIndex < m_toc.headers.size() && p_outlineIndex >= 0) {
QString tmp = m_toc.headers[p_outlineIndex].anchor;
V_ASSERT(!tmp.isEmpty());
m_curHeader.anchor = tmp;
bool validIndex = false;
if (p_anchorIndex < m_toc.headers.size() && p_anchorIndex >= 0) {
QString tmp = m_toc.headers[p_anchorIndex].anchor;
Q_ASSERT(!tmp.isEmpty());
anch.anchor = tmp;
anchor = tmp.mid(1);
validIndex = true;
}
m_document->scrollToAnchor(anchor);
if (validIndex || !p_strict) {
m_curHeader = anch;
emit curHeaderChanged(m_curHeader);
m_document->scrollToAnchor(anchor);
emit curHeaderChanged(m_curHeader);
return true;
} else {
return false;
}
}
bool VMdTab::scrollToAnchor(int p_anchorIndex, bool p_strict)
{
if (m_isEditMode) {
return dynamic_cast<VMdEdit *>(getEditor())->scrollToAnchor(p_anchorIndex);
} else {
return scrollWebViewToAnchor(p_anchorIndex, p_strict);
}
}
void VMdTab::viewWebByConverter()
@ -148,7 +167,7 @@ void VMdTab::showFileEditMode()
VAnchor anchor(m_file, "", lineNumber, outlineIndex);
mdEdit->scrollToHeader(anchor);
mdEdit->scrollToAnchor(anchor);
mdEdit->setFocus();
@ -290,6 +309,8 @@ void VMdTab::setupMarkdownViewer()
this, SLOT(updateCurHeader(const QString &)));
connect(m_document, &VDocument::keyPressed,
this, &VMdTab::handleWebKeyPressed);
connect(m_document, SIGNAL(logicsFinished(void)),
this, SLOT(restoreFromTabInfo(void)));
page->setWebChannel(channel);
m_webViewer->setHtml(VUtils::generateHtmlTemplate(m_mdConType, false),
@ -324,9 +345,11 @@ void VMdTab::setupMarkdownEditor()
connect(m_editor, &VEdit::vimStatusUpdated,
this, &VEditTab::vimStatusUpdated);
connect(m_editor, &VEdit::requestCloseFindReplaceDialog,
this, [this](){
this, [this]() {
this->m_editArea->getFindReplaceDialog()->closeDialog();
});
connect(m_editor, SIGNAL(ready(void)),
this, SLOT(restoreFromTabInfo(void)));
m_editor->reloadFile();
m_stacks->addWidget(m_editor);
@ -467,7 +490,7 @@ void VMdTab::scrollToAnchor(const VAnchor &p_anchor)
m_curHeader = p_anchor;
if (m_isEditMode) {
dynamic_cast<VMdEdit *>(getEditor())->scrollToHeader(p_anchor);
dynamic_cast<VMdEdit *>(getEditor())->scrollToAnchor(p_anchor);
} else {
if (!p_anchor.anchor.isEmpty()) {
m_document->scrollToAnchor(p_anchor.anchor.mid(1));
@ -682,9 +705,9 @@ void VMdTab::requestUpdateVimStatus()
}
}
VEditTabInfo VMdTab::createEditTabInfo()
VEditTabInfo VMdTab::fetchTabInfo()
{
VEditTabInfo info = VEditTab::createEditTabInfo();
VEditTabInfo info = VEditTab::fetchTabInfo();
if (m_editor) {
QTextCursor cursor = m_editor->textCursor();
@ -693,6 +716,8 @@ VEditTabInfo VMdTab::createEditTabInfo()
info.m_blockCount = m_editor->document()->blockCount();
}
info.m_anchorIndex = m_curHeader.m_outlineIndex;
return info;
}
@ -702,3 +727,25 @@ void VMdTab::decorateText(TextDecoration p_decoration)
m_editor->decorateText(p_decoration);
}
}
bool VMdTab::restoreFromTabInfo(const VEditTabInfo &p_info)
{
qDebug() << "restoreFromTabInfo" << p_info.m_anchorIndex;
if (p_info.m_editTab != this) {
return false;
}
// Restore anchor.
int anchorIdx = p_info.m_anchorIndex;
bool ret = scrollToAnchor(anchorIdx, true);
return ret;
}
void VMdTab::restoreFromTabInfo()
{
restoreFromTabInfo(m_infoToRestore);
// Clear it anyway.
m_infoToRestore.m_editTab = NULL;
}

View File

@ -62,6 +62,9 @@ public:
// Insert decoration markers or decorate selected text.
void decorateText(TextDecoration p_decoration) Q_DECL_OVERRIDE;
// Create a filled VEditTabInfo.
VEditTabInfo fetchTabInfo() Q_DECL_OVERRIDE;
public slots:
// Enter edit mode.
void editFile() Q_DECL_OVERRIDE;
@ -91,6 +94,9 @@ private slots:
// m_editor requests to discard changes and enter read mode.
void discardAndRead();
// Restore from m_infoToRestore.
void restoreFromTabInfo();
private:
// Setup UI.
void setupUI();
@ -111,8 +117,16 @@ private:
void viewWebByConverter();
// Scroll Web view to given header.
// @p_outlineIndex is the index in m_toc.headers.
void scrollWebViewToHeader(int p_outlineIndex);
// @p_anchorIndex is the index in m_toc.headers.
// @p_strict: if true, scroll only when @p_anchorIndex is valid.
// Return true if scroll was made.
bool scrollWebViewToAnchor(int p_anchorIndex, bool p_strict = false);
// Scroll web/editor to given header.
// @p_anchorIndex is the index in m_toc.headers.
// @p_strict: if true, scroll only when @p_anchorIndex is valid.
// Return true if scroll was made.
bool scrollToAnchor(int p_anchorIndex, bool p_strict = false);
// Search text in Web view.
void findTextInWebView(const QString &p_text, uint p_options, bool p_peek,
@ -127,12 +141,13 @@ private:
// Focus the proper child widget.
void focusChild() Q_DECL_OVERRIDE;
// Create a filled VEditTabInfo.
VEditTabInfo createEditTabInfo() Q_DECL_OVERRIDE;
// Get the markdown editor. If not init yet, init and return it.
VEdit *getEditor();
// Restore from @p_fino.
// Return true if succeed.
bool restoreFromTabInfo(const VEditTabInfo &p_info) Q_DECL_OVERRIDE;
VEdit *m_editor;
VWebView *m_webViewer;
VDocument *m_document;

View File

@ -330,6 +330,16 @@ VNoteFile *VNote::getInternalFile(const QString &p_path)
return file;
}
VFile *VNote::getFile(const QString &p_path)
{
VFile *file = getInternalFile(p_path);
if (!file) {
file = getOrphanFile(p_path, true, false);
}
return file;
}
VDirectory *VNote::getInternalDirectory(const QString &p_path)
{
VDirectory *dir = NULL;

View File

@ -78,6 +78,10 @@ public:
QString getNavigationLabelStyle(const QString &p_str) const;
// Given the path of a file, first try to open it as note file,
// then try to open it as orphan file.
VFile *getFile(const QString &p_path);
// Given the path of an external file, create a VOrphanFile struct.
VOrphanFile *getOrphanFile(const QString &p_path,
bool p_modifiable,