diff --git a/src/dialog/vfixnotebookdialog.cpp b/src/dialog/vfixnotebookdialog.cpp new file mode 100644 index 00000000..1a84d099 --- /dev/null +++ b/src/dialog/vfixnotebookdialog.cpp @@ -0,0 +1,144 @@ +#include "vfixnotebookdialog.h" + +#include + +#include "vconfigmanager.h" +#include "vlineedit.h" +#include "vnotebook.h" +#include "utils/vutils.h" + +extern VConfigManager *g_config; + +VFixNotebookDialog::VFixNotebookDialog(const VNotebook *p_notebook, + const QVector &p_notebooks, + QWidget *p_parent) + : QDialog(p_parent), m_notebook(p_notebook), m_notebooks(p_notebooks) +{ + setupUI(); + + handleInputChanged(); +} + +void VFixNotebookDialog::setupUI() +{ + QLabel *infoLabel = new QLabel(tr("VNote could not find the root folder of notebook " + "%2. Please specify the new path " + "to the root folder if you moved it somewhere, or VNote " + "will just remove this notebook.") + .arg(g_config->c_dataTextStyle) + .arg(m_notebook->getName()), this); + infoLabel->setWordWrap(true); + + QLabel *nameLabel = new QLabel(m_notebook->getName(), this); + + m_pathEdit = new VLineEdit(m_notebook->getPath(), this); + connect(m_pathEdit, &VLineEdit::textChanged, + this, &VFixNotebookDialog::handleInputChanged); + + m_browseBtn = new QPushButton(tr("&Browse"), this); + connect(m_browseBtn, &QPushButton::clicked, + this, &VFixNotebookDialog::handleBrowseBtnClicked); + + QHBoxLayout *pathLayout = new QHBoxLayout(); + pathLayout->addWidget(m_pathEdit); + pathLayout->addWidget(m_browseBtn); + + QFormLayout *topLayout = new QFormLayout(); + topLayout->addRow(tr("Notebook name:"), nameLabel); + topLayout->addRow(tr("Notebook root folder:"), pathLayout); + + // Warning label. + m_warnLabel = new QLabel(this); + m_warnLabel->setWordWrap(true); + m_warnLabel->hide(); + + // Ok is the default button. + m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok); + okBtn->setProperty("SpecialBtn", true); + m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(infoLabel); + mainLayout->addLayout(topLayout); + mainLayout->addWidget(m_warnLabel); + mainLayout->addWidget(m_btnBox); + + setLayout(mainLayout); + mainLayout->setSizeConstraint(QLayout::SetFixedSize); + setWindowTitle(tr("Fix Notebook")); +} + +void VFixNotebookDialog::handleBrowseBtnClicked() +{ + static QString defaultPath; + + if (defaultPath.isEmpty()) { + defaultPath = g_config->getVnoteNotebookFolderPath(); + if (!QFileInfo::exists(defaultPath)) { + defaultPath = g_config->getDocumentPathOrHomePath(); + } + } + + QString dirPath = QFileDialog::getExistingDirectory(this, + tr("Select Root Folder Of The Notebook"), + defaultPath, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (!dirPath.isEmpty()) { + m_pathEdit->setText(dirPath); + defaultPath = VUtils::basePathFromPath(dirPath); + } +} + +void VFixNotebookDialog::handleInputChanged() +{ + QString warnText = tr("WARNING: The folder chosen is NOT a valid root " + "folder of a notebook.") + .arg(g_config->c_warningTextStyle); + bool pathOk = false; + + QString path = m_pathEdit->text(); + if (!path.isEmpty()) { + if (VConfigManager::directoryConfigExist(path)) { + pathOk = true; + } + } + + if (pathOk) { + // Check if this path has been in VNote. + int idx = -1; + for (idx = 0; idx < m_notebooks.size(); ++idx) { + if (m_notebooks[idx] != m_notebook + && VUtils::equalPath(m_notebooks[idx]->getPath(), path)) { + break; + } + } + + if (idx < m_notebooks.size()) { + pathOk = false; + QString existText = tr("WARNING: The folder chosen has already been a root folder " + "of existing notebook %3 in VNote.") + .arg(g_config->c_warningTextStyle) + .arg(g_config->c_dataTextStyle) + .arg(m_notebooks[idx]->getName()); + m_warnLabel->setText(existText); + } + } else { + m_warnLabel->setText(warnText); + } + + m_warnLabel->setVisible(!pathOk); + QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok); + okBtn->setEnabled(pathOk); +} + +QString VFixNotebookDialog::getPathInput() const +{ + // absoluteFilePath() to convert the drive to upper case. + // cleanPath() to remove duplicate separator, '.', and '..'. + return QDir::cleanPath(QFileInfo(m_pathEdit->text()).absoluteFilePath()); +} diff --git a/src/dialog/vfixnotebookdialog.h b/src/dialog/vfixnotebookdialog.h new file mode 100644 index 00000000..40418032 --- /dev/null +++ b/src/dialog/vfixnotebookdialog.h @@ -0,0 +1,43 @@ +#ifndef VFIXNOTEBOOKDIALOG_H +#define VFIXNOTEBOOKDIALOG_H + +#include + +class VNotebook; +class VLineEdit; +class QLabel; +class QPushButton; +class QDialogButtonBox; + +class VFixNotebookDialog : public QDialog +{ + Q_OBJECT +public: + VFixNotebookDialog(const VNotebook *p_notebook, + const QVector &p_notebooks, + QWidget *p_parent = nullptr); + + QString getPathInput() const; + +private slots: + void handleBrowseBtnClicked(); + + void handleInputChanged(); + +private: + void setupUI(); + + const VNotebook *m_notebook; + + const QVector &m_notebooks; + + VLineEdit *m_pathEdit; + + QPushButton *m_browseBtn; + + QLabel *m_warnLabel; + + QDialogButtonBox *m_btnBox; +}; + +#endif // VFIXNOTEBOOKDIALOG_H diff --git a/src/main.cpp b/src/main.cpp index b16cd2c5..0739324d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -216,11 +216,13 @@ int main(int argc, char *argv[]) w.show(); + w.checkNotebooks(); + + w.promptNewNotebookIfEmpty(); + w.openStartupPages(); w.openFiles(filePaths); - w.promptNewNotebookIfEmpty(); - return app.exec(); } diff --git a/src/src.pro b/src/src.pro index d2b8754b..c6cc137b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -124,7 +124,8 @@ SOURCES += main.cpp\ vsearchue.cpp \ voutlineue.cpp \ vhelpue.cpp \ - vlistfolderue.cpp + vlistfolderue.cpp \ + dialog/vfixnotebookdialog.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -239,7 +240,8 @@ HEADERS += vmainwindow.h \ vsearchue.h \ voutlineue.h \ vhelpue.h \ - vlistfolderue.h + vlistfolderue.h \ + dialog/vfixnotebookdialog.h RESOURCES += \ vnote.qrc \ diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 339e22ba..76be4cb9 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -44,6 +44,7 @@ #include "voutlineue.h" #include "vhelpue.h" #include "vlistfolderue.h" +#include "dialog/vfixnotebookdialog.h" extern VConfigManager *g_config; @@ -108,7 +109,7 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent) setContextMenuPolicy(Qt::NoContextMenu); - notebookSelector->update(); + m_notebookSelector->update(); initSharedMemoryWatcher(); @@ -148,7 +149,7 @@ void VMainWindow::initCaptain() void VMainWindow::registerCaptainAndNavigationTargets() { - m_captain->registerNavigationTarget(notebookSelector); + m_captain->registerNavigationTarget(m_notebookSelector); m_captain->registerNavigationTarget(directoryTree); m_captain->registerNavigationTarget(m_fileList); m_captain->registerNavigationTarget(m_editArea); @@ -234,9 +235,9 @@ void VMainWindow::setupUI() connect(directoryTree, &VDirectoryTree::directoryUpdated, m_editArea, &VEditArea::handleDirectoryUpdated); - connect(notebookSelector, &VNotebookSelector::notebookUpdated, + connect(m_notebookSelector, &VNotebookSelector::notebookUpdated, m_editArea, &VEditArea::handleNotebookUpdated); - connect(notebookSelector, &VNotebookSelector::notebookCreated, + connect(m_notebookSelector, &VNotebookSelector::notebookCreated, directoryTree, [this](const QString &p_name, bool p_import) { Q_UNUSED(p_name); if (!p_import) { @@ -283,9 +284,9 @@ QWidget *VMainWindow::setupDirectoryPanel() QLabel *notebookLabel = new QLabel(tr("Notebooks")); notebookLabel->setProperty("TitleLabel", true); - notebookSelector = new VNotebookSelector(); - notebookSelector->setObjectName("NotebookSelector"); - notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + m_notebookSelector = new VNotebookSelector(); + m_notebookSelector->setObjectName("NotebookSelector"); + m_notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); // Navigation panel. QLabel *directoryLabel = new QLabel(tr("Folders")); @@ -316,7 +317,7 @@ QWidget *VMainWindow::setupDirectoryPanel() QVBoxLayout *nbLayout = new QVBoxLayout; nbLayout->addWidget(notebookLabel); - nbLayout->addWidget(notebookSelector); + nbLayout->addWidget(m_notebookSelector); nbLayout->addWidget(m_naviSplitter); nbLayout->setContentsMargins(3, 0, 0, 0); nbLayout->setSpacing(0); @@ -324,13 +325,13 @@ QWidget *VMainWindow::setupDirectoryPanel() nbContainer->setLayout(nbLayout); nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); - connect(notebookSelector, &VNotebookSelector::curNotebookChanged, + connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged, this, [this](VNotebook *p_notebook) { directoryTree->setNotebook(p_notebook); directoryTree->setFocus(); }); - connect(notebookSelector, &VNotebookSelector::curNotebookChanged, + connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged, this, &VMainWindow::handleCurrentNotebookChanged); connect(directoryTree, &VDirectoryTree::currentDirectoryChanged, @@ -2312,7 +2313,7 @@ bool VMainWindow::locateFile(VFile *p_file) VNoteFile *file = dynamic_cast(p_file); VNotebook *notebook = file->getNotebook(); - if (notebookSelector->locateNotebook(notebook)) { + if (m_notebookSelector->locateNotebook(notebook)) { while (directoryTree->currentNotebook() != notebook) { QCoreApplication::sendPostedEvents(); } @@ -2348,7 +2349,7 @@ bool VMainWindow::locateDirectory(VDirectory *p_directory) } VNotebook *notebook = p_directory->getNotebook(); - if (notebookSelector->locateNotebook(notebook)) { + if (m_notebookSelector->locateNotebook(notebook)) { while (directoryTree->currentNotebook() != notebook) { QCoreApplication::sendPostedEvents(); } @@ -2833,7 +2834,7 @@ bool VMainWindow::exportByCaptain(void *p_target, void *p_data) void VMainWindow::promptNewNotebookIfEmpty() { if (vnote->getNotebooks().isEmpty()) { - notebookSelector->newNotebook(); + m_notebookSelector->newNotebook(); } } @@ -3151,7 +3152,7 @@ void VMainWindow::updateEditReadAct(const VEditTab *p_tab) void VMainWindow::handleExportAct() { - VExportDialog dialog(notebookSelector->currentNotebook(), + VExportDialog dialog(m_notebookSelector->currentNotebook(), directoryTree->currentDirectory(), m_curFile, m_cart, @@ -3162,7 +3163,7 @@ void VMainWindow::handleExportAct() VNotebook *VMainWindow::getCurrentNotebook() const { - return notebookSelector->currentNotebook(); + return m_notebookSelector->currentNotebook(); } void VMainWindow::activateUniversalEntry() @@ -3218,3 +3219,34 @@ void VMainWindow::initUniversalEntry() m_ue->registerEntry('m', new VListFolderUE(this), 0); m_ue->registerEntry('?', new VHelpUE(this), 0); } + +void VMainWindow::checkNotebooks() +{ + bool updated = false; + QVector ¬ebooks = g_vnote->getNotebooks(); + for (int i = 0; i < notebooks.size(); ++i) { + VNotebook *nb = notebooks[i]; + if (nb->isValid()) { + continue; + } + + VFixNotebookDialog dialog(nb, notebooks, this); + if (dialog.exec()) { + qDebug() << "fix path of notebook" << nb->getName() << "to" << dialog.getPathInput(); + nb->updatePath(dialog.getPathInput()); + } else { + notebooks.removeOne(nb); + --i; + } + + updated = true; + } + + if (updated) { + g_config->setNotebooks(notebooks); + + m_notebookSelector->update(); + } + + m_notebookSelector->restoreCurrentNotebook(); +} diff --git a/src/vmainwindow.h b/src/vmainwindow.h index caccee59..c355cd19 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -102,6 +102,9 @@ public: // Prompt user for new notebook if there is no notebook. void promptNewNotebookIfEmpty(); + // Check invalid notebooks. Set current notebook according to config. + void checkNotebooks(); + VFile *getCurrentFile() const; VEditTab *getCurrentTab() const; @@ -317,7 +320,7 @@ private: VCaptain *m_captain; - VNotebookSelector *notebookSelector; + VNotebookSelector *m_notebookSelector; VFileList *m_fileList; VDirectoryTree *directoryTree; @@ -486,6 +489,6 @@ inline VDirectoryTree *VMainWindow::getDirectoryTree() const inline VNotebookSelector *VMainWindow::getNotebookSelector() const { - return notebookSelector; + return m_notebookSelector; } #endif // VMAINWINDOW_H diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index ee7fef05..95310130 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -15,7 +15,7 @@ VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent) m_recycleBinFolder = g_config->getRecycleBinFolder(); m_rootDir = new VDirectory(this, NULL, - VUtils::directoryNameFromPath(path), + VUtils::directoryNameFromPath(m_path), QDateTime::currentDateTimeUtc()); } @@ -132,6 +132,10 @@ void VNotebook::close() bool VNotebook::open() { + if (!m_valid) { + return false; + } + QString recycleBinPath = getRecycleBinFolderPath(); if (!QFileInfo::exists(recycleBinPath)) { QDir dir(m_path); @@ -386,3 +390,17 @@ QList VNotebook::collectFiles() return files; } + +void VNotebook::updatePath(const QString &p_path) +{ + Q_ASSERT(!isOpened()); + m_valid = false; + m_path = QDir::cleanPath(p_path); + delete m_rootDir; + m_rootDir = new VDirectory(this, + NULL, + VUtils::directoryNameFromPath(m_path), + QDateTime::currentDateTimeUtc()); + + readConfigNotebook(); +} diff --git a/src/vnotebook.h b/src/vnotebook.h index 71cc6533..9fd5359c 100644 --- a/src/vnotebook.h +++ b/src/vnotebook.h @@ -44,8 +44,11 @@ public: VDirectory *tryLoadDirectory(const QString &p_path); const QString &getName() const; + const QString &getPath() const; + void updatePath(const QString &p_path); + VDirectory *getRootDir() const; void rename(const QString &p_name); diff --git a/src/vnotebookselector.cpp b/src/vnotebookselector.cpp index c85bfaab..db15a885 100644 --- a/src/vnotebookselector.cpp +++ b/src/vnotebookselector.cpp @@ -160,8 +160,6 @@ void VNotebookSelector::updateComboBox() { m_muted = true; - int index = g_config->getCurNotebookIndex(); - clear(); m_listWidget->clear(); @@ -179,16 +177,24 @@ void VNotebookSelector::updateComboBox() if (m_notebooks.isEmpty()) { g_config->setCurNotebookIndex(-1); setCurrentIndex(0); - } else { - const VNotebook *nb = NULL; - if (index >= 0 && index < m_notebooks.size()) { - nb = m_notebooks[index]; - } + } +} - setCurrentItemToNotebook(nb); +void VNotebookSelector::restoreCurrentNotebook() +{ + int index = g_config->getCurNotebookIndex(); + if (index < 0 || index >= m_notebooks.size()) { + index = 0; } - qDebug() << "notebooks" << m_notebooks.size() << "current index" << index; + const VNotebook *nb = NULL; + if (index < m_notebooks.size()) { + nb = m_notebooks[index]; + } + + if (nb) { + setCurrentItemToNotebook(nb); + } } void VNotebookSelector::setCurrentItemToNotebook(const VNotebook *p_notebook) diff --git a/src/vnotebookselector.h b/src/vnotebookselector.h index 846c9c3e..cabc7403 100644 --- a/src/vnotebookselector.h +++ b/src/vnotebookselector.h @@ -29,6 +29,8 @@ public: VNotebook *currentNotebook() const; + void restoreCurrentNotebook(); + // Implementations for VNavigationMode. void registerNavigation(QChar p_majorKey) Q_DECL_OVERRIDE; void showNavigation() Q_DECL_OVERRIDE;