- enhancement: delete a watch expression don't reload who watch var view

- enhancement: auto save/restore debug panel's current tab
  - fix: correctly restore left(explorer) panel's current tab
  - enhancement: auto close non-modified new editor after file/project openned;
  - fix: project files openned by double click in bookmark/breakpoint panel may cause app crash when closed.
  - fix: When open a project that's already openned, shouldn't close it.
  - enhancement: When open a project, let user choose weither open it in new window or replace the already openned project
This commit is contained in:
Roy Qu 2022-10-17 23:23:05 +08:00
parent 984d10eaf1
commit 3509c25fc8
23 changed files with 1260 additions and 768 deletions

View File

@ -19,6 +19,12 @@ Red Panda C++ Version 1.5
- enhancement: project and non-project files use different breakpoint and watchvar view (auto switch when not debugging and editor switched)
- enhancement: save project's breakpoint and watchvar in it's own debug file.
- enhancement: delete a watch expression don't reload who watch var view
- enhancement: auto save/restore debug panel's current tab
- fix: correctly restore left(explorer) panel's current tab
- enhancement: auto close non-modified new editor after file/project openned;
- fix: project files openned by double click in bookmark/breakpoint panel may cause app crash when closed.
- fix: When open a project that's already openned, shouldn't close it.
- enhancement: When open a project, let user choose weither open it in new window or replace the already openned project
Red Panda C++ Version 1.4

View File

@ -136,6 +136,7 @@ SOURCES += \
vcs/gitresetdialog.cpp \
vcs/gituserconfigdialog.cpp \
vcs/gitutils.cpp \
visithistorymanager.cpp \
widgets/aboutdialog.cpp \
widgets/bookmarkmodel.cpp \
widgets/choosethemedialog.cpp \
@ -188,6 +189,7 @@ SOURCES += \
widgets/newtemplatedialog.cpp \
widgets/ojproblempropertywidget.cpp \
widgets/ojproblemsetmodel.cpp \
widgets/projectalreadyopendialog.cpp \
widgets/qconsole.cpp \
widgets/qpatchedcombobox.cpp \
widgets/searchdialog.cpp \
@ -266,6 +268,7 @@ HEADERS += \
vcs/gitresetdialog.h \
vcs/gituserconfigdialog.h \
vcs/gitutils.h \
visithistorymanager.h \
widgets/aboutdialog.h \
widgets/bookmarkmodel.h \
widgets/choosethemedialog.h \
@ -318,6 +321,7 @@ HEADERS += \
widgets/newtemplatedialog.h \
widgets/ojproblempropertywidget.h \
widgets/ojproblemsetmodel.h \
widgets/projectalreadyopendialog.h \
widgets/qconsole.h \
widgets/qpatchedcombobox.h \
widgets/searchdialog.h \
@ -383,6 +387,7 @@ FORMS += \
widgets/newprojectunitdialog.ui \
widgets/newtemplatedialog.ui \
widgets/ojproblempropertywidget.ui \
widgets/projectalreadyopendialog.ui \
widgets/searchdialog.ui \
widgets/signalmessagedialog.ui

View File

@ -427,6 +427,7 @@ void Debugger::saveForProject(const QString &filename, const QString &projectFol
void Debugger::loadForNonproject(const QString &filename)
{
bool forProject = false;
mLastLoadtime = 0;
PDebugConfig pConfig = load(filename, forProject);
if (pConfig->timestamp>0) {
mBreakpointModel->setBreakpoints(pConfig->breakpoints,forProject);
@ -436,7 +437,8 @@ void Debugger::loadForNonproject(const QString &filename)
void Debugger::loadForProject(const QString &filename, const QString &projectFolder)
{
bool forProject = false;
bool forProject = true;
mProjectLastLoadtime = 0;
PDebugConfig pConfig = load(filename, forProject);
if (pConfig->timestamp>0) {
QDir dir(projectFolder);
@ -463,8 +465,7 @@ void Debugger::addWatchVar(const QString &expression)
var->hasMore = false;
var->timestamp = QDateTime::currentMSecsSinceEpoch();
mWatchModel->addWatchVar(var);
sendWatchCommand(var);
addWatchVar(var,isForProject());
}
void Debugger::modifyWatchVarExpression(const QString &oldExpr, const QString &newExpr)
@ -692,7 +693,7 @@ void Debugger::save(const QString &filename, const QString& projectFolder)
QString key = watchVar->expression;
if (!watchVarCompareSet.contains(key)) {
watchVarCompareSet.insert(key);
addWatchVar(key);
addWatchVar(watchVar,forProject);
}
}
qint64 saveTimestamp = QDateTime::currentMSecsSinceEpoch();;
@ -761,6 +762,13 @@ PDebugConfig Debugger::load(const QString &filename, bool forProject)
return pConfig;
}
void Debugger::addWatchVar(const PWatchVar &watchVar, bool forProject)
{
mWatchModel->addWatchVar(watchVar,forProject);
if (forProject == isForProject())
sendWatchCommand(watchVar);
}
void Debugger::syncFinishedParsing()
{
bool spawnedcpuform = false;
@ -1927,7 +1935,7 @@ QList<PBreakpoint> BreakpointModel::loadJson(const QJsonArray& jsonArray, qint64
if (ok && timestamp > criteriaTime) {
PBreakpoint breakpoint = std::make_shared<Breakpoint>();
breakpoint->filename = QFileInfo(obj["filename"].toString()).absoluteFilePath();
breakpoint->filename = obj["filename"].toString();
breakpoint->line = obj["line"].toInt();
breakpoint->condition = obj["condition"].toString();
breakpoint->enabled = obj["enabled"].toBool();
@ -2124,16 +2132,18 @@ int WatchModel::columnCount(const QModelIndex&) const
return 3;
}
void WatchModel::addWatchVar(PWatchVar watchVar)
void WatchModel::addWatchVar(PWatchVar watchVar, bool forProject)
{
QList<PWatchVar> &vars=(mIsForProject?mProjectWatchVars:mWatchVars);
QList<PWatchVar> &vars=(forProject?mProjectWatchVars:mWatchVars);
for (PWatchVar var:vars) {
if (watchVar->expression == var->expression) {
return;
}
}
if (forProject==mIsForProject)
beginInsertRows(QModelIndex(),vars.count(),vars.count());
vars.append(watchVar);
if (forProject==mIsForProject)
endInsertRows();
}

View File

@ -231,7 +231,7 @@ private:
QJsonArray toJson(bool forProject);
QList<PWatchVar> loadJson(const QJsonArray &jsonArray, qint64 criteriaTimestamp);
const QList<PWatchVar> &watchVars() const;
void addWatchVar(PWatchVar watchVar);
void addWatchVar(PWatchVar watchVar, bool forProject);
void setWatchVars(const QList<PWatchVar> list, bool forProject);
private:
@ -371,6 +371,7 @@ private:
void sendClearBreakpointCommand(PBreakpoint breakpoint);
void save(const QString& filename, const QString& projectFolder);
PDebugConfig load(const QString& filename, bool forProject);
void addWatchVar(const PWatchVar &watchVar, bool forProject);
private slots:
void syncFinishedParsing();

View File

@ -23,6 +23,7 @@
#include "settings.h"
#include "project.h"
#include "systemconsts.h"
#include "visithistorymanager.h"
#include <QApplication>
EditorList::EditorList(QTabWidget* leftPageWidget,
@ -174,7 +175,7 @@ bool EditorList::closeEditor(Editor* editor, bool transferFocus, bool force) {
PProjectUnit unit = pMainWindow->project()->findUnit(editor);
pMainWindow->project()->closeUnit(unit);
} else {
if (pSettings->history().addToOpenedFiles(editor->filename())) {
if (pMainWindow->visitHistoryManager()->addFile(editor->filename())) {
pMainWindow->rebuildOpenedFileHisotryMenu();
}
delete editor;
@ -358,20 +359,7 @@ Editor* EditorList::getOpenedEditorByFilename(QString filename)
Editor *EditorList::getEditorByFilename(QString filename)
{
if (filename.isEmpty())
return nullptr;
//check if an editor is already openned
Editor* e=getOpenedEditorByFilename(filename);
if (e!=nullptr)
return e;
//Todo: check if is in the project
//Create a new editor
QFileInfo fileInfo(filename);
QString fullname = fileInfo.absoluteFilePath();
if (fileInfo.exists() && fileInfo.isFile())
return newEditor(fullname,pSettings->editor().autoDetectFileEncoding()?ENCODING_AUTO_DETECT:pSettings->editor().defaultEncoding(),nullptr,false);
return nullptr;
return pMainWindow->openFile(filename,false);
}
bool EditorList::getContentFromOpenedEditor(const QString &filename, QStringList &buffer)

View File

@ -94,9 +94,6 @@ private:
QSplitter *mSplitter;
QWidget *mPanel;
int mUpdateCount;
};
#endif // EDITORLIST_H

View File

@ -263,6 +263,10 @@ int main(int argc, char *argv[])
openInSingleInstance = envSetting.value("open_files_in_single_instance",false).toBool();
} else if (!settingFilename.isEmpty() && firstRun)
openInSingleInstance = false;
if (app.arguments().contains("-ns")) {
openInSingleInstance = false;
} else if (app.arguments().contains("-s"))
openInSingleInstance = true;
if (openInSingleInstance) {
int openCount = 0;
while (true) {

View File

@ -48,6 +48,8 @@
#include "vcs/gituserconfigdialog.h"
#include "widgets/infomessagebox.h"
#include "widgets/newtemplatedialog.h"
#include "visithistorymanager.h"
#include "widgets/projectalreadyopendialog.h"
#include <QCloseEvent>
#include <QComboBox>
@ -149,6 +151,11 @@ MainWindow::MainWindow(QWidget *parent)
mProjectProxyModel->setDynamicSortFilter(false);
ui->EditorTabsRight->setVisible(false);
mVisitHistoryManager = std::make_shared<VisitHistoryManager>(
includeTrailingPathDelimiter(pSettings->dirs().config())
+DEV_HISTORY_FILE);
mVisitHistoryManager->load();
//toolbar takes the owner
mCompilerSet = new QComboBox();
mCompilerSet->setMinimumWidth(200);
@ -450,6 +457,14 @@ void MainWindow::updateEditorBookmarks()
}
}
void MainWindow::updateEditorBreakpoints()
{
for (int i=0;i<mEditorList->pageCount();i++) {
Editor * e=(*mEditorList)[i];
e->resetBreakpoints();
}
}
void MainWindow::updateEditorActions()
{
Editor* e = mEditorList->getEditor();
@ -1046,14 +1061,15 @@ void MainWindow::rebuildOpenedFileHisotryMenu()
{
mMenuRecentFiles->clear();
mMenuRecentProjects->clear();
if (pSettings->history().opennedFiles().size()==0) {
if (mVisitHistoryManager->files().count()==0) {
mMenuRecentFiles->setEnabled(false);
} else {
mMenuRecentFiles->setEnabled(true);
for (const QString& filename: pSettings->history().opennedFiles()) {
foreach (const PVisitRecord& record, mVisitHistoryManager->files()) {
QString filename = record->filename;
//menu takes the ownership
QAction* action = new QAction(filename,mMenuRecentFiles);
connect(action, &QAction::triggered, [&filename,this](bool){
connect(action, &QAction::triggered, [filename,this](bool){
openFile(filename);
});
mMenuRecentFiles->addAction(action);
@ -1061,20 +1077,21 @@ void MainWindow::rebuildOpenedFileHisotryMenu()
mMenuRecentFiles->addSeparator();
//menu takes the ownership
QAction *action = new QAction(tr("Clear History"),mMenuRecentFiles);
connect(action, &QAction::triggered, [](bool){
pSettings->history().clearOpennedFiles();
connect(action, &QAction::triggered, [this](bool){
mVisitHistoryManager->clearFiles();
});
mMenuRecentFiles->addAction(action);
}
if (pSettings->history().opennedProjects().size()==0) {
if (mVisitHistoryManager->projects().count()==0) {
mMenuRecentProjects->setEnabled(false);
} else {
mMenuRecentProjects->setEnabled(true);
for (const QString& filename: pSettings->history().opennedProjects()) {
foreach (const PVisitRecord& record, mVisitHistoryManager->projects()) {
QString filename = record->filename;
//menu takes the ownership
QAction* action = new QAction(filename,mMenuRecentProjects);
connect(action, &QAction::triggered, [&filename,this](bool){
connect(action, &QAction::triggered, [filename,this](bool){
this->openProject(filename);
});
mMenuRecentProjects->addAction(action);
@ -1082,8 +1099,8 @@ void MainWindow::rebuildOpenedFileHisotryMenu()
mMenuRecentProjects->addSeparator();
//menu takes the ownership
QAction *action = new QAction(tr("Clear History"),mMenuRecentProjects);
connect(action, &QAction::triggered, [](bool){
pSettings->history().clearOpennedProjects();
connect(action, &QAction::triggered, [this](bool){
mVisitHistoryManager->clearProjects();
});
mMenuRecentProjects->addAction(action);
}
@ -1216,17 +1233,24 @@ void MainWindow::openFiles(const QStringList &files)
e->activate();
}
void MainWindow::openFile(const QString &filename, bool activate, QTabWidget* page)
Editor* MainWindow::openFile(const QString &filename, bool activate, QTabWidget* page)
{
Editor* editor = mEditorList->getOpenedEditorByFilename(filename);
if (editor!=nullptr) {
if (activate) {
editor->activate();
}
return;
return editor;
}
try {
pSettings->history().removeFile(filename);
Editor* oldEditor=nullptr;
if (mEditorList->pageCount()==1) {
oldEditor = mEditorList->getEditor(0);
if (!oldEditor->isNew() || oldEditor->modified()) {
oldEditor = nullptr;
}
}
//mVisitHistoryManager->removeFile(filename);
PProjectUnit unit;
if (mProject) {
unit = mProject->findUnit(filename);
@ -1243,10 +1267,14 @@ void MainWindow::openFile(const QString &filename, bool activate, QTabWidget* pa
if (activate) {
editor->activate();
}
if (mEditorList->pageCount()>1 && oldEditor)
mEditorList->closeEditor(oldEditor);
// editor->activate();
return editor;
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
return nullptr;
}
void MainWindow::openProject(const QString &filename, bool openFiles)
@ -1254,26 +1282,39 @@ void MainWindow::openProject(const QString &filename, bool openFiles)
if (!fileExists(filename)) {
return;
}
Editor* oldEditor=nullptr;
if (mProject) {
QString s;
if (mProject->name().isEmpty())
s = mProject->filename();
else
s = mProject->name();
if (QMessageBox::question(this,
tr("Close project"),
tr("Are you sure you want to close %1?")
.arg(s),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes) == QMessageBox::Yes) {
if (mProject->filename() == filename)
return;
ProjectAlreadyOpenDialog dlg;
if (dlg.exec()!=QDialog::Accepted)
return;
if (dlg.openType()==ProjectAlreadyOpenDialog::OpenType::ThisWindow) {
closeProject(false);
} else {
QProcess process;
process.setProgram(QApplication::instance()->applicationFilePath());
process.setWorkingDirectory(QDir::currentPath());
QStringList args;
args.append("-ns");
args.append(filename);
process.setArguments(args);
process.startDetached();
return;
}
} else {
if (mEditorList->pageCount()==1) {
oldEditor = mEditorList->getEditor(0);
if (!oldEditor->isNew() || oldEditor->modified()) {
oldEditor = nullptr;
}
ui->tabProject->setVisible(true);
}
}
//ui->tabProject->setVisible(true);
//stretchExplorerPanel(true);
if (openFiles)
ui->tabExplorer->setCurrentWidget(ui->tabProject);
stretchExplorerPanel(true);
// {
// LeftPageControl.ActivePage := LeftProjectSheet;
// fLeftPageControlChanged := False;
@ -1287,7 +1328,7 @@ void MainWindow::openProject(const QString &filename, bool openFiles)
ui->projectView->expand(
mProjectProxyModel->mapFromSource(
mProject->model()->rootIndex()));
pSettings->history().removeProject(filename);
//mVisitHistoryManager->removeProject(filename);
// // if project manager isn't open then open it
// if not devData.ShowLeftPages then
@ -1329,7 +1370,8 @@ void MainWindow::openProject(const QString &filename, bool openFiles)
updateCompilerSet();
updateClassBrowserForEditor(e);
mClassBrowserModel.endUpdate();
if (oldEditor)
mEditorList->closeEditor(oldEditor);
//updateForEncodingInfo();
}
@ -2250,34 +2292,38 @@ void MainWindow::onBookmarkContextMenu(const QPoint &pos)
void MainWindow::saveLastOpens()
{
QString filename = includeTrailingPathDelimiter(pSettings->dirs().config()) + DEV_LASTOPENS_FILE;
if (fileExists(filename)) {
if (!QFile::remove(filename)) {
QFile file(filename);
if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
QMessageBox::critical(this,
tr("Save last open info error"),
tr("Can't remove old last open information file '%1'")
tr("Can't open last open information file '%1' for write!")
.arg(filename),
QMessageBox::Ok);
return;
}
}
SimpleIni lastOpenIni;
lastOpenIni.SetLongValue("LastOpens","Count", mEditorList->pageCount());
QJsonObject rootObj;
if (mProject) {
lastOpenIni.SetValue("LastOpens","Project",mProject->filename().toLocal8Bit());
rootObj["lastProject"]=mProject->filename();
}
QJsonArray filesArray;
for (int i=0;i<mEditorList->pageCount();i++) {
Editor * editor = (*mEditorList)[i];
QByteArray sectionName = QString("Editor_%1").arg(i).toLocal8Bit();
lastOpenIni.SetValue(sectionName,"FileName", editor->filename().toLocal8Bit());
lastOpenIni.SetBoolValue(sectionName, "OnLeft",editor->pageControl() != mEditorList->rightPageWidget());
lastOpenIni.SetBoolValue(sectionName, "Focused",editor->hasFocus());
lastOpenIni.SetLongValue(sectionName, "CursorCol", editor->caretX());
lastOpenIni.SetLongValue(sectionName, "CursorRow", editor->caretY());
lastOpenIni.SetLongValue(sectionName, "TopLine", editor->topLine());
lastOpenIni.SetLongValue(sectionName, "LeftChar", editor->leftChar());
QJsonObject fileObj;
fileObj["filename"] = editor->filename();
fileObj["onLeft"] = (editor->pageControl() != mEditorList->rightPageWidget());
fileObj["focused"] = editor->hasFocus();
fileObj["caretX"] = editor->caretX();
fileObj["caretY"] = editor->caretY();
fileObj["topLine"] = editor->topLine();
fileObj["leftChar"] = editor->leftChar();
filesArray.append(fileObj);
}
if (lastOpenIni.SaveFile(filename.toLocal8Bit())!=SI_Error::SI_OK) {
rootObj["files"]=filesArray;
QJsonDocument doc;
doc.setObject(rootObj);
QByteArray json = doc.toJson();
if (file.write(doc.toJson())!=json.count()) {
QMessageBox::critical(this,
tr("Save last open info error"),
tr("Can't save last open info file '%1'")
@ -2285,6 +2331,7 @@ void MainWindow::saveLastOpens()
QMessageBox::Ok);
return;
}
file.close();
}
void MainWindow::loadLastOpens()
@ -2292,8 +2339,8 @@ void MainWindow::loadLastOpens()
QString filename = includeTrailingPathDelimiter(pSettings->dirs().config()) + DEV_LASTOPENS_FILE;
if (!fileExists(filename))
return;
SimpleIni lastOpenIni;
if (lastOpenIni.LoadFile(filename.toLocal8Bit())!=SI_Error::SI_OK) {
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
QMessageBox::critical(this,
tr("Load last open info error"),
tr("Can't load last open info file '%1'")
@ -2301,19 +2348,31 @@ void MainWindow::loadLastOpens()
QMessageBox::Ok);
return;
}
QString projectFilename = QString::fromLocal8Bit((lastOpenIni.GetValue("LastOpens", "Project","")));
int count = lastOpenIni.GetLongValue("LastOpens","Count",0);
if (fileExists(projectFilename)) {
QJsonParseError error;
QJsonDocument doc=QJsonDocument::fromJson(file.readAll(),&error);
if (error.error != QJsonParseError::NoError) {
QMessageBox::critical(this,
tr("Load last open info error"),
tr("Can't load last open info file '%1'")
.arg(filename)+" : <BR/>"
+QString("%1").arg(error.errorString()),
QMessageBox::Ok);
return;
}
QJsonObject rootObj = doc.object();
QString projectFilename = rootObj["lastProject"].toString();
if (!projectFilename.isEmpty()) {
openProject(projectFilename, false);
}
QJsonArray filesArray = rootObj["files"].toArray();
Editor * focusedEditor = nullptr;
for (int i=0;i<count;i++) {
QByteArray sectionName = QString("Editor_%1").arg(i).toLocal8Bit();
QString editorFilename = QString::fromLocal8Bit(lastOpenIni.GetValue(sectionName,"FileName",""));
for (int i=0;i<filesArray.count();i++) {
QJsonObject fileObj = filesArray[i].toObject();
QString editorFilename = fileObj["filename"].toString("");
if (!fileExists(editorFilename))
continue;
editorFilename = QFileInfo(editorFilename).absoluteFilePath();
bool onLeft = lastOpenIni.GetBoolValue(sectionName,"OnLeft",true);
bool onLeft = fileObj["onLeft"].toBool();
QTabWidget* page;
if (onLeft)
page = mEditorList->leftPageWidget();
@ -2338,24 +2397,26 @@ void MainWindow::loadLastOpens()
if (!editor)
continue;
QSynedit::BufferCoord pos;
pos.ch = lastOpenIni.GetLongValue(sectionName,"CursorCol", 1);
pos.line = lastOpenIni.GetLongValue(sectionName,"CursorRow", 1);
pos.ch = fileObj["caretX"].toInt(1);
pos.line = fileObj["caretY"].toInt(1);
editor->setCaretXY(pos);
editor->setTopLine(
lastOpenIni.GetLongValue(sectionName,"TopLine", 1)
fileObj["topLine"].toInt(1)
);
editor->setLeftChar(
lastOpenIni.GetLongValue(sectionName,"LeftChar", 1)
fileObj["leftChar"].toInt(1)
);
if (lastOpenIni.GetBoolValue(sectionName,"Focused",false))
if (fileObj["focused"].toBool(false))
focusedEditor = editor;
pSettings->history().removeFile(editorFilename);
//mVisitHistoryManager->removeFile(editorFilename);
}
if (mProject && mEditorList->pageCount()==0) {
mProject->doAutoOpen();
updateEditorBookmarks();
updateEditorBreakpoints();
}
if (count>0) {
if (mEditorList->pageCount()>0) {
updateEditorActions();
//updateForEncodingInfo();
}
@ -4376,7 +4437,7 @@ void MainWindow::closeProject(bool refreshEditor)
mClassBrowserModel.beginUpdate();
// Remember it
pSettings->history().addToOpenedProjects(mProject->filename());
mVisitHistoryManager->addProject(mProject->filename());
mEditorList->beginUpdate();
mProject.reset();
@ -4421,7 +4482,7 @@ void MainWindow::updateProjectView()
//ui->projectView->expandAll();
stretchExplorerPanel(true);
ui->tabProject->setVisible(true);
ui->tabExplorer->setCurrentWidget(ui->tabProject);
//ui->tabExplorer->setCurrentWidget(ui->tabProject);
} else {
// Clear project browser
mProjectProxyModel->setSourceModel(nullptr);
@ -4576,6 +4637,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
settings.setMainWindowGeometry(saveGeometry());
settings.setBottomPanelIndex(ui->tabMessages->currentIndex());
settings.setLeftPanelIndex(ui->tabExplorer->currentIndex());
settings.setDebugPanelIndex(ui->debugViews->currentIndex());
settings.setShowStatusBar(ui->actionStatus_Bar->isChecked());
settings.setShowToolWindowBars(ui->actionTool_Window_Bars->isChecked());
@ -4670,13 +4732,14 @@ void MainWindow::showEvent(QShowEvent *)
const Settings::UI& settings = pSettings->ui();
ui->tabMessages->setCurrentIndex(settings.bottomPanelIndex());
ui->tabExplorer->setCurrentIndex(settings.leftPanelIndex());
ui->debugViews->setCurrentIndex(settings.debugPanelIndex());
}
void MainWindow::hideEvent(QHideEvent *)
{
Settings::UI& settings = pSettings->ui();
settings.setBottomPanelIndex(ui->tabMessages->currentIndex());
settings.setLeftPanelIndex(ui->tabExplorer->currentIndex());
// Settings::UI& settings = pSettings->ui();
// settings.setBottomPanelIndex(ui->tabMessages->currentIndex());
// settings.setLeftPanelIndex(ui->tabExplorer->currentIndex());
}
bool MainWindow::event(QEvent *event)
@ -8288,6 +8351,11 @@ void MainWindow::on_actionNew_Template_triggered()
}
}
const std::shared_ptr<VisitHistoryManager> &MainWindow::visitHistoryManager() const
{
return mVisitHistoryManager;
}
bool MainWindow::isQuitting() const
{
return mQuitting;

View File

@ -70,6 +70,7 @@ class Project;
class ProjectModelNode;
class ProjectUnit;
class ColorSchemeItem;
class VisitHistoryManager;
#define DPI_CHANGED_EVENT ((QEvent::Type)(QEvent::User+1))
@ -112,6 +113,7 @@ public:
void updateStatusbarMessage(const QString& s);
void updateEditorSettings();
void updateEditorBookmarks();
void updateEditorBreakpoints();
void updateEditorActions();
void updateProjectActions();
void updateCompileActions();
@ -194,7 +196,7 @@ public:
const PBookmarkModel &bookmarkModel() const;
void openFile(const QString& filename, bool activate=true, QTabWidget* page=nullptr);
Editor* openFile(const QString& filename, bool activate=true, QTabWidget* page=nullptr);
void openProject(const QString& filename, bool openFiles = true);
void changeOptions(const QString& widgetName=QString(), const QString& groupName=QString());
@ -737,6 +739,8 @@ private:
std::shared_ptr<HeaderCompletionPopup> mHeaderCompletionPopup;
std::shared_ptr<FunctionTooltipWidget> mFunctionTip;
std::shared_ptr<VisitHistoryManager> mVisitHistoryManager;
TodoModel mTodoModel;
SearchResultModel mSearchResultModel;
PBookmarkModel mBookmarkModel;
@ -855,6 +859,7 @@ public:
bool event(QEvent *event) override;
bool isClosingAll() const;
bool isQuitting() const;
const std::shared_ptr<VisitHistoryManager> &visitHistoryManager() const;
};
extern MainWindow* pMainWindow;

View File

@ -895,7 +895,7 @@
<enum>QTabWidget::South</enum>
</property>
<property name="currentIndex">
<number>5</number>
<number>2</number>
</property>
<property name="iconSize">
<size>

View File

@ -45,7 +45,6 @@ Settings::Settings(const QString &filename):
mDebugger(this),
mCodeCompletion(this),
mCodeFormatter(this),
mHistory(this),
mUI(this),
mVCS(this)
{
@ -106,7 +105,6 @@ void Settings::load()
mEditor.load();
mExecutor.load();
mDebugger.load();
mHistory.load();
mCodeCompletion.load();
mCodeFormatter.load();
mUI.load();
@ -164,11 +162,6 @@ Settings::VCS &Settings::vcs()
return mVCS;
}
Settings::History& Settings::history()
{
return mHistory;
}
Settings::Debugger& Settings::debugger()
{
return mDebugger;
@ -3671,106 +3664,6 @@ void Settings::Debugger::doLoad()
mMemoryViewColumns = intValue("memory_view_columns",8);
}
Settings::History::History(Settings *settings):_Base(settings, SETTING_HISTORY)
{
}
const QStringList &Settings::History::opennedFiles() const
{
return mOpenedFiles;
}
const QStringList &Settings::History::opennedProjects() const
{
return mOpenedProjects;
}
void Settings::History::clearOpennedFiles()
{
mOpenedFiles.clear();
}
void Settings::History::clearOpennedProjects()
{
mOpenedProjects.clear();
}
bool Settings::History::addToOpenedFiles(const QString &filename)
{
if (!QFile(filename).exists())
return false;
int index = mOpenedFiles.indexOf(filename);
if (index>=0) {
mOpenedFiles.removeAt(index);
}
if (mOpenedFiles.size()>=15) {
mOpenedFiles.pop_back();
}
mOpenedFiles.push_front(filename);
save();
return true;
}
void Settings::History::removeFile(const QString &filename)
{
int index = mOpenedFiles.indexOf(filename);
if (index>=0) {
mOpenedFiles.removeAt(index);
}
save();
return;
}
bool Settings::History::addToOpenedProjects(const QString &filename)
{
if (!QFile(filename).exists())
return false;
int index = mOpenedProjects.indexOf(filename);
if (index>=0) {
mOpenedProjects.removeAt(index);
}
if (mOpenedProjects.size()>=15) {
mOpenedProjects.pop_back();
}
mOpenedProjects.push_front(filename);
save();
return true;
}
void Settings::History::removeProject(const QString &filename)
{
int index = mOpenedProjects.indexOf(filename);
if (index>=0) {
mOpenedProjects.removeAt(index);
}
save();
return;
}
void Settings::History::doSave()
{
saveValue("opened_files", mOpenedFiles);
saveValue("opened_projects", mOpenedProjects);
}
static QStringList filterValidPathes(const QStringList& files) {
QStringList lst;
foreach (const QString& filePath, files) {
if (fileExists(filePath)) {
lst.append(QFileInfo(filePath).absoluteFilePath());
}
}
return lst;
}
void Settings::History::doLoad()
{
mOpenedFiles = filterValidPathes(stringListValue("opened_files"));
mOpenedProjects = filterValidPathes(stringListValue("opened_projects"));
}
Settings::CodeCompletion::CodeCompletion(Settings *settings):_Base(settings, SETTING_CODE_COMPLETION)
{
@ -4990,6 +4883,16 @@ void Settings::UI::setMessagesTabsSize(const QSize &newMessagesTabsSize)
mMessagesTabsSize = newMessagesTabsSize;
}
int Settings::UI::debugPanelIndex() const
{
return mDebugPanelIndex;
}
void Settings::UI::setDebugPanelIndex(int newDebugPanelIndex)
{
mDebugPanelIndex = newDebugPanelIndex;
}
const QSize &Settings::UI::explorerTabsSize() const
{
return mExplorerTabsSize;
@ -5256,6 +5159,7 @@ void Settings::UI::doSave()
saveValue("main_window_geometry",mMainWindowGeometry);
saveValue("bottom_panel_index",mBottomPanelIndex);
saveValue("left_panel_index",mLeftPanelIndex);
saveValue("debug_panel_index",mDebugPanelIndex);
saveValue("class_browser_sort_alphabetically",mClassBrowserSortAlpha);
saveValue("class_browser_sort_by_type",mClassBrowserSortType);
saveValue("class_browser_show_inherited",mClassBrowserShowInherited);
@ -5305,6 +5209,8 @@ void Settings::UI::doLoad()
mMainWindowGeometry = value("main_window_geometry",QByteArray()).toByteArray();
mBottomPanelIndex = intValue("bottom_panel_index",0);
mLeftPanelIndex = intValue("left_panel_index",0);
mDebugPanelIndex = intValue("debug_panel_index",0);
mClassBrowserSortAlpha = boolValue("class_browser_sort_alphabetically",true);
mClassBrowserSortType = boolValue("class_browser_sort_by_type",true);
mClassBrowserShowInherited = boolValue("class_browser_show_inherited",true);

View File

@ -817,28 +817,6 @@ public:
void doLoad() override;
};
class History: public _Base {
public:
explicit History(Settings *settings);
const QStringList& opennedFiles() const;
const QStringList& opennedProjects() const;
void clearOpennedFiles();
void clearOpennedProjects();
bool addToOpenedFiles(const QString& filename);
void removeFile(const QString& filename);
bool addToOpenedProjects(const QString& filename);
void removeProject(const QString& filename);
private:
QStringList mOpenedFiles;
QStringList mOpenedProjects;
// _Base interface
protected:
void doSave() override;
void doLoad() override;
};
class Executor: public _Base {
public:
explicit Executor(Settings * settings);
@ -1044,11 +1022,15 @@ public:
const QSize &messagesTabsSize() const;
void setMessagesTabsSize(const QSize &newMessagesTabsSize);
int debugPanelIndex() const;
void setDebugPanelIndex(int newDebugPanelIndex);
private:
QByteArray mMainWindowState;
QByteArray mMainWindowGeometry;
int mBottomPanelIndex;
int mLeftPanelIndex;
int mDebugPanelIndex;
bool mClassBrowserSortAlpha;
bool mClassBrowserSortType;
bool mClassBrowserShowInherited;
@ -1412,7 +1394,6 @@ public:
Environment& environment();
Executor& executor();
Debugger& debugger();
History& history();
CodeCompletion &codeCompletion();
CodeFormatter &codeFormatter();
UI &ui();
@ -1430,7 +1411,6 @@ private:
Debugger mDebugger;
CodeCompletion mCodeCompletion;
CodeFormatter mCodeFormatter;
History mHistory;
UI mUI;
VCS mVCS;
};

View File

@ -82,7 +82,7 @@
#define TEMPLATE_EXT "template"
#define TEMPLATE_INFO_FILE "info.template"
#define DEV_INTERNAL_OPEN "$__DEV_INTERNAL_OPEN"
#define DEV_LASTOPENS_FILE "lastopens.ini"
#define DEV_LASTOPENS_FILE "lastopens.json"
#define DEV_SYMBOLUSAGE_FILE "symbolusage.json"
#define DEV_CODESNIPPET_FILE "codesnippets.json"
#define DEV_NEWFILETEMPLATES_FILE "newfiletemplate.txt"
@ -91,6 +91,7 @@
#define DEV_TOOLS_FILE "tools.json"
#define DEV_BOOKMARK_FILE "bookmarks.json"
#define DEV_DEBUGGER_FILE "debugger.json"
#define DEV_HISTORY_FILE "history.json"
#ifdef Q_OS_WIN
# define PATH_SENSITIVITY Qt::CaseInsensitive

View File

@ -156,19 +156,19 @@
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation>Falha ao salvar arquivo &apos;%1&apos;.</translation>
<translation type="vanished">Falha ao salvar arquivo &apos;%1&apos;.</translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation>Impossível gravar arquivo &apos;%1&apos;.</translation>
<translation type="vanished">Impossível gravar arquivo &apos;%1&apos;.</translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation>Erro no arquivo json &apos;%1&apos;:%2 : %3</translation>
<translation type="vanished">Erro no arquivo json &apos;%1&apos;:%2 : %3</translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation>Impossível ler o arquivo &apos;%1&apos;.</translation>
<translation type="vanished">Impossível ler o arquivo &apos;%1&apos;.</translation>
</message>
</context>
<context>
@ -703,10 +703,6 @@
<source>Stop after the compilation proper stage</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Stop after the assembling stage</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Link and generate the executable </source>
<translation type="unfinished"></translation>
@ -715,10 +711,6 @@
<source>Preprocessing output suffix</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Assembling output suffix</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Compiling output suffix</source>
<translation type="unfinished"></translation>
@ -810,11 +802,11 @@
</message>
<message>
<source>Autosave breakpoints</source>
<translation>Salvar breakpoints automaticamente</translation>
<translation type="vanished">Salvar breakpoints automaticamente</translation>
</message>
<message>
<source>Autosave watches</source>
<translation>Salvar automaticamente as observações</translation>
<translation type="vanished">Salvar automaticamente as observações</translation>
</message>
<message>
<source>Show CPU Window when signal received</source>
@ -852,6 +844,10 @@
<source>Memory View Columns</source>
<translation>Colunas da memória</translation>
</message>
<message>
<source>Autosave breakpoints and watches</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Debugger</name>
@ -915,6 +911,22 @@
<source>Signal &quot;%1&quot; Received: </source>
<translation>Recebido sinal &quot;%1&quot;: </translation>
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation type="unfinished">Erro no arquivo json &apos;%1&apos;:%2 : %3</translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Editor</name>
@ -3898,11 +3910,11 @@
</message>
<message>
<source>Close project</source>
<translation>Fechar projeto</translation>
<translation type="vanished">Fechar projeto</translation>
</message>
<message>
<source>Are you sure you want to close %1?</source>
<translation>Quer mesmo fechar %1?</translation>
<translation type="vanished">Quer mesmo fechar %1?</translation>
</message>
<message>
<source>Confirm</source>
@ -3998,7 +4010,7 @@
</message>
<message>
<source>Can&apos;t remove old last open information file &apos;%1&apos;</source>
<translation>Impossível remover o arquivo aberto com a última informação &apos;%1&apos; </translation>
<translation type="vanished">Impossível remover o arquivo aberto com a última informação &apos;%1&apos; </translation>
</message>
<message>
<source>Can&apos;t save last open info file &apos;%1&apos;</source>
@ -4660,6 +4672,10 @@
<source>Please correct this before start debugging</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open last open information file &apos;%1&apos; for write!</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewClassDialog</name>
@ -5004,6 +5020,33 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ProjectAlreadyOpenDialog</name>
<message>
<source>Dialog</source>
<translation type="obsolete">Diálogo</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Projects can either be opened in a new window or replace the project in the existing window or be attached to the already opened projects. How would you like to open the project?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&amp;This Window</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New &amp;Window</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open Project</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ProjectCompileParamatersWidget</name>
<message>
@ -6716,19 +6759,19 @@
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation>Falha ao gravar o arquivo &apos;%1&apos;.</translation>
<translation type="vanished">Falha ao gravar o arquivo &apos;%1&apos;.</translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation>Impossível gravar no arquivo &apos;%1&apos;.</translation>
<translation type="vanished">Impossível gravar no arquivo &apos;%1&apos;.</translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation>Erro no arquivo json &apos;%1&apos;:%2 : %3</translation>
<translation type="vanished">Erro no arquivo json &apos;%1&apos;:%2 : %3</translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation>Impossível ler o arquivo &apos;%1&apos;</translation>
<translation type="vanished">Impossível ler o arquivo &apos;%1&apos;</translation>
</message>
<message>
<source>Expression</source>

File diff suppressed because it is too large Load Diff

View File

@ -150,22 +150,6 @@
<source>Condition</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CPUDialog</name>
@ -628,10 +612,6 @@
<source>Stop after the compilation proper stage</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Stop after the assembling stage</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Link and generate the executable </source>
<translation type="unfinished"></translation>
@ -640,10 +620,6 @@
<source>Preprocessing output suffix</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Assembling output suffix</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Compiling output suffix</source>
<translation type="unfinished"></translation>
@ -733,14 +709,6 @@
<source>Autosave</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Autosave breakpoints</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Autosave watches</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show CPU Window when signal received</source>
<translation type="unfinished"></translation>
@ -777,6 +745,10 @@
<source>Memory View Columns</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Autosave breakpoints and watches</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Debugger</name>
@ -840,6 +812,22 @@
<source>Signal &quot;%1&quot; Received: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Editor</name>
@ -3797,14 +3785,6 @@
<source>Overwrite</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Close project</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to close %1?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
@ -3897,10 +3877,6 @@
<source>Save last open info error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t remove old last open information file &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t save last open info file &apos;%1&apos;</source>
<translation type="unfinished"></translation>
@ -4549,6 +4525,10 @@
<source>Please correct this before start debugging</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open last open information file &apos;%1&apos; for write!</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NewClassDialog</name>
@ -4889,6 +4869,29 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ProjectAlreadyOpenDialog</name>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Projects can either be opened in a new window or replace the project in the existing window or be attached to the already opened projects. How would you like to open the project?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&amp;This Window</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New &amp;Window</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open Project</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ProjectCompileParamatersWidget</name>
<message>
@ -6529,22 +6532,6 @@
<source>Execute to evaluate</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Save file &apos;%1&apos; failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for write.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Error in json file &apos;%1&apos;:%2 : %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open file &apos;%1&apos; for read.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Expression</source>
<translation type="unfinished"></translation>

View File

@ -0,0 +1,183 @@
#include "visithistorymanager.h"
#include <QDateTime>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSet>
VisitHistoryManager::VisitHistoryManager(const QString& filename):
mLastLoadtime(0),
mSaveFilename(filename),
mMaxFileCount(15),
mMaxProjectCount(15)
{
}
const QList<PVisitRecord> &VisitHistoryManager::files() const
{
return mFiles;
}
const QList<PVisitRecord> &VisitHistoryManager::projects() const
{
return mProjects;
}
void VisitHistoryManager::clearFiles()
{
mFiles.clear();
}
void VisitHistoryManager::clearProjects()
{
mProjects.clear();
}
static int indexOf(const QList<PVisitRecord> &list, const QString& filename) {
for (int i=0;i<list.count();i++) {
if (list[i]->filename == filename)
return i;
}
return -1;
}
bool VisitHistoryManager::addFile(const QString &filename)
{
return doAdd(mFiles,filename,mMaxFileCount);
}
void VisitHistoryManager::removeFile(const QString &filename)
{
doRemove(mFiles,filename);
}
bool VisitHistoryManager::addProject(const QString &filename)
{
return doAdd(mProjects,filename,mMaxProjectCount);
}
void VisitHistoryManager::removeProject(const QString &filename)
{
return doRemove(mProjects,filename);
}
void VisitHistoryManager::save()
{
PVisitHistory pHistory = doLoad(mSaveFilename,mLastLoadtime);
mergeRead(mFiles,pHistory->files);
mergeRead(mProjects,pHistory->projects);
QJsonObject rootObj;
rootObj["files"] = toJson(mFiles);
rootObj["projects"] = toJson(mProjects);
rootObj["timestamp"] = QString("%1").arg(QDateTime::currentMSecsSinceEpoch());
QFile file(mSaveFilename);
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QJsonDocument doc;
doc.setObject(rootObj);
file.write(doc.toJson());
}
}
void VisitHistoryManager::load()
{
PVisitHistory pHistory = doLoad(mSaveFilename,0);
mFiles = pHistory->files;
mProjects = pHistory->projects;
}
PVisitHistory VisitHistoryManager::doLoad(const QString &filename, qint64 criteriaTime)
{
PVisitHistory pHistory=std::make_shared<VisitHistory>();
pHistory->timestamp=0;
QFile file(filename);
if (!file.open(QFile::ReadOnly))
return pHistory;
QJsonParseError error;
QJsonDocument doc=QJsonDocument::fromJson(file.readAll(),&error);
if (error.error!=QJsonParseError::NoError)
return pHistory;
bool ok;
QJsonObject rootObj = doc.object();
pHistory->timestamp = rootObj["timestamp"].toString().toLongLong(&ok);
if (!ok || pHistory->timestamp < criteriaTime)
return pHistory;
pHistory->files = fromJson(rootObj["files"].toArray(),criteriaTime);
pHistory->projects = fromJson(rootObj["projects"].toArray(),criteriaTime);
mLastLoadtime = QDateTime::currentMSecsSinceEpoch();
return pHistory;
}
QList<PVisitRecord> VisitHistoryManager::fromJson(const QJsonArray &array, qint64 criteriaTime)
{
QList<PVisitRecord> records;
for (int i=0;i<array.count();i++) {
QJsonObject recordObj = array[i].toObject();
bool ok;
qint64 timestamp = recordObj["timestamp"].toString().toLongLong(&ok);
if (ok && timestamp>criteriaTime) {
PVisitRecord record = std::make_shared<VisitRecord>();
record->timestamp = timestamp;
record->filename = recordObj["filename"].toString();
records.append(record);
}
}
return records;
}
void VisitHistoryManager::mergeRead(QList<PVisitRecord> &target, const QList<PVisitRecord> &readed)
{
QSet<QString> mergeCache;
foreach (const PVisitRecord& r, target) {
mergeCache.insert(r->filename);
}
for (int i=readed.count()-1;i>=0;i--) {
const PVisitRecord& r=readed[i];
if (!mergeCache.contains(r->filename)) {
mergeCache.insert(r->filename);
target.push_front(r);
}
}
}
QJsonArray VisitHistoryManager::toJson(const QList<PVisitRecord> &list)
{
QJsonArray array;
foreach(const PVisitRecord &record, list) {
QJsonObject recordObj;
recordObj["filename"]=record->filename;
recordObj["timestamp"]=QString("%1").arg(record->timestamp);
array.append(recordObj);
}
return array;
}
bool VisitHistoryManager::doAdd(QList<PVisitRecord> &list, const QString &filename, int maxCount)
{
if (!QFile(filename).exists())
return false;
int index = indexOf(list,filename);
if (index>=0) {
list.removeAt(index);
}
if (list.size()>=maxCount) {
list.pop_back();
}
PVisitRecord record = std::make_shared<VisitRecord>();
record->filename = filename;
record->timestamp = QDateTime::currentMSecsSinceEpoch();
list.push_front(record);
save();
return true;
}
void VisitHistoryManager::doRemove(QList<PVisitRecord> &list, const QString &filename)
{
int index = indexOf(mFiles,filename);
if (index>=0) {
list.removeAt(index);
}
save();
}

View File

@ -0,0 +1,56 @@
#ifndef VISITHISTORYMANAGER_H
#define VISITHISTORYMANAGER_H
#include <QJsonArray>
#include <QList>
#include <QString>
#include <memory>
struct VisitRecord {
QString filename;
qint64 timestamp;
};
using PVisitRecord = std::shared_ptr<VisitRecord>;
struct VisitHistory{
qint64 timestamp;
QList<PVisitRecord> files;
QList<PVisitRecord> projects;
};
using PVisitHistory = std::shared_ptr<VisitHistory>;
class VisitHistoryManager
{
public:
VisitHistoryManager(const QString& filename);
const QList<PVisitRecord> &files() const;
const QList<PVisitRecord> &projects() const;
void clearFiles();
void clearProjects();
bool addFile(const QString& filename);
void removeFile(const QString& filename);
bool addProject(const QString& filename);
void removeProject(const QString& filename);
void save();
void load();
private:
PVisitHistory doLoad(const QString& filename, qint64 criteriaTime);
QList<PVisitRecord> fromJson(const QJsonArray &array, qint64 criteriaTime);
void mergeRead(QList<PVisitRecord>& target, const QList<PVisitRecord>& readed);
QJsonArray toJson(const QList<PVisitRecord>& list);
bool doAdd(QList<PVisitRecord> &list, const QString& filename, int maxCount);
void doRemove(QList<PVisitRecord> &list, const QString& filename);
private:
QList<PVisitRecord> mFiles;
QList<PVisitRecord> mProjects;
qint64 mLastLoadtime;
QString mSaveFilename;
int mMaxFileCount;
int mMaxProjectCount;
};
#endif // VISITHISTORYMANAGER_H

View File

@ -210,44 +210,55 @@ void BookmarkModel::save(const QString &filename, const QString& projectFolder)
}
QList<PBookmark> fileBookmarks=load(filename, t,&fileTimestamp);
QFile file(filename);
int saveOrderCount=0;
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QHash<QString,PBookmark> compareHash;
QHash<QString,int> compareHash;
QList<PBookmark> saveBookmarks;
foreach (const PBookmark& bookmark, bookmarks) {
for (int i=0; i<bookmarks.count(); i++) {
PBookmark& bookmark=bookmarks[i];
QString key = QString("%1-%2").arg(bookmark->filename).arg(bookmark->line);
bookmark->saveOrder=saveOrderCount++;
compareHash.insert(key,bookmark);
compareHash.insert(key,i);;
}
QDir dir(projectFolder);
foreach (const PBookmark& bookmark, fileBookmarks) {
QString key = QString("%1-%2").arg(bookmark->filename).arg(bookmark->line);
bookmark->saveOrder=saveOrderCount++;
if (!compareHash.contains(key))
compareHash.insert(key,bookmark);
else {
PBookmark pTemp=compareHash.value(key);
if (pTemp->timestamp<=bookmark->timestamp)
compareHash.insert(key,bookmark);
int idx = compareHash.value(key,-1);
if (idx<0) {
int count=forProject?mProjectBookmarks.count():mBookmarks.count();
compareHash.insert(key,count);
if (forProject == mIsForProject) {
beginInsertRows(QModelIndex(),count,count);
}
}
QList<PBookmark> saveList;
foreach (const PBookmark& bookmark, compareHash) {
saveList.append(bookmark);
}
std::sort(saveList.begin(),saveList.end(), [](PBookmark b1,PBookmark b2) {
return b1->saveOrder - b2->saveOrder;
});
if (forProject) {
mProjectBookmarks=saveList;
mLastLoadProjectBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch();
bookmark->filename = dir.absoluteFilePath(bookmark->filename);
}
QList<PBookmark> &list=forProject?mProjectBookmarks:mBookmarks;
list.append(bookmark);
if (forProject == mIsForProject)
endInsertRows();
} else {
mBookmarks=saveList;
mLastLoadBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch();
const QList<PBookmark> &list=forProject?mProjectBookmarks:mBookmarks;
PBookmark pTemp = list[idx];
if (pTemp->timestamp<=bookmark->timestamp) {
bookmark->description = pTemp->timestamp;
bookmark->timestamp = pTemp->timestamp;
if (forProject == mIsForProject)
emit dataChanged(createIndex(idx,2),createIndex(idx,2));
}
}
}
qint64 saveTime = QDateTime::currentMSecsSinceEpoch();;
if (forProject) {
mLastLoadProjectBookmarksTimestamp = saveTime;
} else {
mLastLoadBookmarksTimestamp = saveTime;
}
QJsonObject rootObj;
rootObj["timestamp"]=QString("%1").arg(saveTime);
QJsonArray array;
foreach (const PBookmark& bookmark, saveList) {
const QList<PBookmark> &list=forProject?mProjectBookmarks:mBookmarks;
foreach (const PBookmark& bookmark, list) {
QJsonObject obj;
obj["filename"]=bookmark->filename;
obj["line"]=bookmark->line;
@ -255,8 +266,9 @@ void BookmarkModel::save(const QString &filename, const QString& projectFolder)
obj["timestamp"]=QString("%1").arg(bookmark->timestamp);
array.append(obj);
}
rootObj["bookmarks"]=array;
QJsonDocument doc;
doc.setArray(array);
doc.setObject(rootObj);
if (file.write(doc.toJson())<0) {
throw FileError(tr("Save file '%1' failed.")
.arg(filename));
@ -272,10 +284,6 @@ QList<PBookmark> BookmarkModel::load(const QString& filename, qint64 criteriaTim
//clear(forProject);
QList<PBookmark> bookmarks;
QFileInfo fileInfo(filename);
qint64 timestamp=fileInfo.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch();
*pFileTimestamp=timestamp;
if (timestamp<=criteriaTimestamp)
return bookmarks;
QFile file(filename);
if (!file.exists())
return bookmarks;
@ -289,13 +297,17 @@ QList<PBookmark> BookmarkModel::load(const QString& filename, qint64 criteriaTim
.arg(error.offset)
.arg(error.errorString()));
}
QJsonArray array = doc.array();
qint64 bookmarkTimestamp;
QJsonObject rootObj;
bool ok;
qint64 timestamp = rootObj["timestamp"].toString().toLongLong(&ok);
if (!ok || timestamp<=criteriaTimestamp)
return bookmarks;
*pFileTimestamp=timestamp;
QJsonArray array = rootObj["bookmarks"].toArray();
for (int i=0;i<array.count();i++) {
QJsonValue value = array[i];
QJsonObject obj=value.toObject();
bookmarkTimestamp = obj["timestamp"].toString().toULongLong(&ok);
qint64 bookmarkTimestamp = obj["timestamp"].toString().toULongLong(&ok);
if (ok && bookmarkTimestamp>criteriaTimestamp) {
PBookmark bookmark = std::make_shared<Bookmark>();
bookmark->filename = obj["filename"].toString();

View File

@ -26,7 +26,6 @@ struct Bookmark {
int line;
QString description;
qint64 timestamp;
int saveOrder;
};
using PBookmark=std::shared_ptr<Bookmark>;

View File

@ -0,0 +1,49 @@
#include "projectalreadyopendialog.h"
#include "ui_projectalreadyopendialog.h"
ProjectAlreadyOpenDialog::ProjectAlreadyOpenDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ProjectAlreadyOpenDialog)
{
ui->setupUi(this);
}
ProjectAlreadyOpenDialog::~ProjectAlreadyOpenDialog()
{
delete ui;
}
void ProjectAlreadyOpenDialog::on_btnCancel_clicked()
{
reject();
}
ProjectAlreadyOpenDialog::OpenType ProjectAlreadyOpenDialog::openType() const
{
return mOpenType;
}
void ProjectAlreadyOpenDialog::setOpenType(OpenType newOpenType)
{
mOpenType = newOpenType;
}
void ProjectAlreadyOpenDialog::closeEvent(QCloseEvent */*event*/)
{
reject();
}
void ProjectAlreadyOpenDialog::on_btnThisWindow_clicked()
{
mOpenType = OpenType::ThisWindow;
accept();
}
void ProjectAlreadyOpenDialog::on_btnNewWindow_clicked()
{
mOpenType = OpenType::NewWindow;
accept();
}

View File

@ -0,0 +1,43 @@
#ifndef PROJECTALREADOPENDIALOG_H
#define PROJECTALREADOPENDIALOG_H
#include <QDialog>
namespace Ui {
class ProjectAlreadyOpenDialog;
}
class ProjectAlreadyOpenDialog : public QDialog
{
Q_OBJECT
public:
explicit ProjectAlreadyOpenDialog(QWidget *parent = nullptr);
~ProjectAlreadyOpenDialog();
enum class OpenType {
ThisWindow,
NewWindow
};
OpenType openType() const;
void setOpenType(OpenType newOpenType);
private slots:
void on_btnCancel_clicked();
void on_btnThisWindow_clicked();
void on_btnNewWindow_clicked();
private:
Ui::ProjectAlreadyOpenDialog *ui;
OpenType mOpenType;
// QWidget interface
protected:
void closeEvent(QCloseEvent *event) override;
};
#endif // PROJECTALREADOPENDIALOG_H

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProjectAlreadyOpenDialog</class>
<widget class="QDialog" name="ProjectAlreadyOpenDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>652</width>
<height>254</height>
</rect>
</property>
<property name="windowTitle">
<string>Open Project</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Projects can either be opened in a new window or replace the project in the existing window or be attached to the already opened projects. How would you like to open the project?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>30</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnThisWindow">
<property name="text">
<string>&amp;This Window</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNewWindow">
<property name="text">
<string>New &amp;Window</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>Cancel</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>