diff --git a/CHANGELOG b/CHANGELOG index ebff93645..278598ce1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,14 @@ -Version 0.12.7 +Version 0.12.8 ======================== -- added dialog to create license file (pops up when a license is in the user's clipboard and the "About GAMS" is opened) -- disabled top dockwidget area for all widgets as it should be used solely by the extended parameter editor -- fixed behavior of jumping to matching parenthesis ([Shift+]F8) -- fixed missing parenthesis highlighting for variables -- reduced flickering when minimizing/maximizing Studio -- removed online version check on Studio startup + +# General +- fixed Studio not popping up for warning when drag'n'droping many files +- disabled GoTo dialog for all non-applicable widgets +- fixed crash when opening files with certain parenthesis constructs +- added fullscreen mode (win/linux: ALT+Return, macos: META+CMD+F) +- fixed accidental closing of log tab when closing results page + +# Reference Viewer +- added auto resize when opening +- added context menu to let users auto resize after doing manual changes diff --git a/platform/macos/macoscocoabridge.h b/platform/macos/macoscocoabridge.h index d2fe88166..4e9b9c8ca 100644 --- a/platform/macos/macoscocoabridge.h +++ b/platform/macos/macoscocoabridge.h @@ -29,6 +29,7 @@ class MacOSCocoaBridge static void disableDictationMenuItem(bool flag); static void disableCharacterPaletteMenuItem(bool flag); static void setAllowsAutomaticWindowTabbing(bool flag); + static void setFullScreenMenuItemEverywhere(bool flag); }; #endif // MACOSCOCOABRIDGE_H diff --git a/platform/macos/macoscocoabridge.mm b/platform/macos/macoscocoabridge.mm index de357e569..185d4fa90 100644 --- a/platform/macos/macoscocoabridge.mm +++ b/platform/macos/macoscocoabridge.mm @@ -35,3 +35,8 @@ { [NSWindow setAllowsAutomaticWindowTabbing: flag]; } + +void MacOSCocoaBridge::setFullScreenMenuItemEverywhere(bool flag) +{ + [[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"NSFullScreenMenuItemEverywhere"]; +} diff --git a/src/main.cpp b/src/main.cpp index 71e4cb72a..0a472546b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ using gams::studio::Application; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseOpenGLES); QApplication::setApplicationVersion(STUDIO_VERSION); QCoreApplication::setAttribute(Qt::AA_UseOpenGLES); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 17a729d65..e18b1b15f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -74,7 +74,6 @@ MainWindow::MainWindow(QWidget *parent) { mTextMarkRepo.init(&mFileMetaRepo, &mProjectRepo); mSettings = SettingsLocator::settings(); - mHistory = new HistoryData(); // QFile css(":/data/style.css"); // if (css.open(QFile::ReadOnly | QFile::Text)) { // this->setStyleSheet(css.readAll()); @@ -98,6 +97,10 @@ MainWindow::MainWindow(QWidget *parent) MacOSCocoaBridge::disableDictationMenuItem(true); MacOSCocoaBridge::disableCharacterPaletteMenuItem(true); MacOSCocoaBridge::setAllowsAutomaticWindowTabbing(false); + MacOSCocoaBridge::setFullScreenMenuItemEverywhere(false); + ui->actionFull_Screen->setShortcut(QKeySequence::FullScreen); +#else + ui->actionFull_Screen->setShortcuts({QKeySequence("Alt+Enter"), QKeySequence("Alt+Return")}); #endif if (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::MacOS) { @@ -219,7 +222,6 @@ MainWindow::MainWindow(QWidget *parent) SearchLocator::provide(mSearchDialog); SettingsLocator::provide(mSettings); SysLogLocator::provide(mSyslog); - QTimer::singleShot(0, this, &MainWindow::openInitialFiles); } @@ -1644,7 +1646,10 @@ int MainWindow::showSaveChangesMsgBox(const QString &text) void MainWindow::on_logTabs_tabCloseRequested(int index) { bool isResults = ui->logTabs->widget(index) == mSearchDialog->resultsView(); - if (isResults) mSearchDialog->clearResults(); + if (isResults) { + mSearchDialog->clearResults(); + return; + } QWidget* edit = ui->logTabs->widget(index); if (edit) { @@ -1711,7 +1716,7 @@ void MainWindow::triggerGamsLibFileCreation(LibraryItem *item) HistoryData *MainWindow::history() { - return mHistory; + return &mHistory; } void MainWindow::addToOpenedFiles(QString filePath) @@ -1932,6 +1937,8 @@ void MainWindow::dropEvent(QDropEvent* e) int answer; if(pathList.size() > 25) { + raise(); + activateWindow(); QMessageBox msgBox; msgBox.setText("You are trying to open " + QString::number(pathList.size()) + " files at once. Depending on the file sizes this may take a long time."); @@ -2016,7 +2023,7 @@ void MainWindow::mouseMoveEvent(QMouseEvent* event) { if (event->buttons()) { QWidget* child = childAt(event->pos()); - Q_UNUSED(child); + Q_UNUSED(child) } QMainWindow::mouseMoveEvent(event); } @@ -2832,10 +2839,11 @@ void MainWindow::writeTabs(QJsonObject &json) const void MainWindow::on_actionGo_To_triggered() { - if ((ui->mainTab->currentWidget() == mWp)) - return; + if ((ui->mainTab->currentWidget() == mWp)) return; CodeEdit *codeEdit = ViewHelper::toCodeEdit(mRecent.editor()); TextView *tv = ViewHelper::toTextView(mRecent.editor()); + if (!codeEdit && !tv) return; + int maxLines = codeEdit ? codeEdit->blockCount() : tv ? tv->knownLines() : 1000000; GoToDialog dialog(this, maxLines, bool(tv)); int result = dialog.exec(); @@ -3377,6 +3385,19 @@ void MainWindow::setSearchWidgetPos(const QPoint& searchWidgetPos) mSearchWidgetPos = searchWidgetPos; } +void MainWindow::on_actionFull_Screen_triggered() +{ + if (isFullScreen()) { + if (mMaximizedBeforeFullScreen) + showMaximized(); + else + showNormal(); + } else { + mMaximizedBeforeFullScreen = isMaximized(); + showFullScreen(); + } +} + } } diff --git a/src/mainwindow.h b/src/mainwindow.h index 6204d174f..8bcf3b50d 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -239,6 +239,7 @@ private slots: void on_actionHelp_View_triggered(bool checked); void on_actionShow_System_Log_triggered(); void on_actionShow_Welcome_Page_triggered(); + void on_actionFull_Screen_triggered(); // Other void on_mainTab_tabCloseRequested(int index); void on_logTabs_tabCloseRequested(int index); @@ -351,7 +352,7 @@ private slots: QActionGroup *mCodecGroupSwitch; QActionGroup *mCodecGroupReload; RecentData mRecent; - HistoryData *mHistory; + HistoryData mHistory; StudioSettings* mSettings; std::unique_ptr mAutosaveHandler; ProjectContextMenu mProjectContextMenu; @@ -369,6 +370,7 @@ private slots: int mTimerID; QStringList mOpenTabsList; QVector mClosedTabsIndexes; + bool mMaximizedBeforeFullScreen; }; } diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 17adf5c1f..a0a50d71f 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -101,7 +101,7 @@ 0 0 1024 - 22 + 23 @@ -208,6 +208,8 @@ + + @@ -1127,6 +1129,17 @@ Delete leftover scratch directories in current working directory + + + true + + + Full Screen + + + Qt::WindowShortcut + + diff --git a/src/reference/symbolreferencewidget.cpp b/src/reference/symbolreferencewidget.cpp index f9ac6dd71..b7c1a8745 100644 --- a/src/reference/symbolreferencewidget.cpp +++ b/src/reference/symbolreferencewidget.cpp @@ -33,6 +33,7 @@ SymbolReferenceWidget::SymbolReferenceWidget(Reference* ref, SymbolDataType::Sym mReferenceViewer(parent) { ui->setupUi(this); + ui->symbolReferenceSplitter->setSizes(QList({2500,1500})); mSymbolTableModel = new SymbolTableModel(mType, this); ui->symbolView->setModel( mSymbolTableModel ); @@ -45,15 +46,23 @@ SymbolReferenceWidget::SymbolReferenceWidget(Reference* ref, SymbolDataType::Sym ui->symbolView->sortByColumn(1, Qt::AscendingOrder); ui->symbolView->setSortingEnabled(true); ui->symbolView->setAlternatingRowColors(true); + ui->symbolView->setContextMenuPolicy(Qt::CustomContextMenu); ui->symbolView->horizontalHeader()->setStretchLastSection(true); - ui->symbolView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + ui->symbolView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + ui->symbolView->horizontalHeader()->setSectionResizeMode( mSymbolTableModel->getLastSectionIndex(), QHeaderView::Stretch ); ui->symbolView->verticalHeader()->setMinimumSectionSize(1); ui->symbolView->verticalHeader()->setDefaultSectionSize(int(fontMetrics().height()*TABLE_ROW_HEIGHT)); + QAction* resizeColumn = mContextMenu.addAction("Auto Resize Columns", [this]() { resizeColumnToContents(); }, QKeySequence("Ctrl+R")); + resizeColumn->setShortcutContext(Qt::WidgetWithChildrenShortcut); + resizeColumn->setShortcutVisibleInContextMenu(true); + ui->symbolView->addAction(resizeColumn); + connect(mSymbolTableModel, &SymbolTableModel::symbolSelectionToBeUpdated, this, &SymbolReferenceWidget::updateSymbolSelection); connect(ui->symbolView, &QAbstractItemView::doubleClicked, this, &SymbolReferenceWidget::jumpToFile); connect(ui->symbolView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SymbolReferenceWidget::updateSelectedSymbol); + connect(ui->symbolView, &QTableView::customContextMenuRequested, this, &SymbolReferenceWidget::showContextMenu); connect(ui->symbolSearchLineEdit, &QLineEdit::textChanged, mSymbolTableModel, &SymbolTableModel::setFilterPattern); connect(ui->allColumnToggleSearch, &QCheckBox::toggled, mSymbolTableModel, &SymbolTableModel::toggleSearchColumns); @@ -63,11 +72,9 @@ SymbolReferenceWidget::SymbolReferenceWidget(Reference* ref, SymbolDataType::Sym ui->referenceView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->referenceView->setSelectionMode(QAbstractItemView::SingleSelection); ui->referenceView->setItemsExpandable(true); - ui->referenceView->expandAll(); - ui->referenceView->resizeColumnToContents(0); - ui->referenceView->resizeColumnToContents(1); ui->referenceView->setAlternatingRowColors(true); ui->referenceView->setColumnHidden(3, true); + expandResetModel(); connect(ui->referenceView, &QAbstractItemView::doubleClicked, this, &SymbolReferenceWidget::jumpToReferenceItem); connect( mReferenceTreeModel, &ReferenceTreeModel::modelReset, this, &SymbolReferenceWidget::expandResetModel); @@ -92,7 +99,7 @@ bool SymbolReferenceWidget::isModelLoaded() const void SymbolReferenceWidget::updateSelectedSymbol(QItemSelection selected, QItemSelection deselected) { - Q_UNUSED(deselected); + Q_UNUSED(deselected) if (selected.indexes().size() > 0) { if (mType == SymbolDataType::FileUsed) { mCurrentSymbolID = -1; @@ -142,8 +149,10 @@ void SymbolReferenceWidget::resetModel() void SymbolReferenceWidget::initModel() { - if (!mSymbolTableModel->isModelLoaded()) + if (!mSymbolTableModel->isModelLoaded()) { mSymbolTableModel->initModel(mReference); + resizeColumnToContents(); + } mReferenceTreeModel->resetModel(); } @@ -183,6 +192,28 @@ void SymbolReferenceWidget::updateSymbolSelection() } } +void SymbolReferenceWidget::resizeColumnToContents() +{ + ui->symbolView->resizeColumnsToContents(); + ui->symbolView->horizontalHeader()->setSectionResizeMode( mSymbolTableModel->getLastSectionIndex(), QHeaderView::Stretch ); +} + +void SymbolReferenceWidget::showContextMenu(QPoint p) +{ + QModelIndexList indexSelection = ui->symbolView->selectionModel()->selectedIndexes(); + if (indexSelection.size()<=0) + return; + + if (mSymbolTableModel->rowCount()>0 && ui->symbolView->horizontalHeader()->logicalIndexAt(p)>=0) { + QMenu m(this); + for(QAction* action : ui->symbolView->actions()) { + action->setEnabled(true); + m.addAction(action); + } + m.exec(ui->symbolView->viewport()->mapToGlobal(p)); + } +} + } // namespace reference } // namespace studio } // namespace gams diff --git a/src/reference/symbolreferencewidget.h b/src/reference/symbolreferencewidget.h index 37bebde6b..05bffbc10 100644 --- a/src/reference/symbolreferencewidget.h +++ b/src/reference/symbolreferencewidget.h @@ -21,6 +21,7 @@ #define SYMBOLREFERENCEWIDGET_H #include +#include #include #include @@ -59,9 +60,12 @@ public slots: void jumpToFile(const QModelIndex &index); void jumpToReferenceItem(const QModelIndex &index); void updateSymbolSelection(); + void resizeColumnToContents(); + void showContextMenu(QPoint p); private: Ui::SymbolReferenceWidget *ui; + QMenu mContextMenu; SymbolTableModel* mSymbolTableModel; ReferenceTreeModel* mReferenceTreeModel; diff --git a/src/reference/symbolreferencewidget.ui b/src/reference/symbolreferencewidget.ui index e41c667cd..70954705d 100644 --- a/src/reference/symbolreferencewidget.ui +++ b/src/reference/symbolreferencewidget.ui @@ -20,6 +20,21 @@ Form + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/src/reference/symboltablemodel.cpp b/src/reference/symboltablemodel.cpp index 10a083e71..4c448c83e 100644 --- a/src/reference/symboltablemodel.cpp +++ b/src/reference/symboltablemodel.cpp @@ -175,7 +175,7 @@ QVariant SymbolTableModel::data(const QModelIndex &index, int role) const case SymbolDataType::Model : switch(index.column()) { case 0: return QString::number( refList.at(idx)->id() ); - case 1: return refList.at(idx)->name();; + case 1: return refList.at(idx)->name(); case 2: return SymbolDataType::from( refList.at(idx)->type() ).name(); case 3: return refList.at(idx)->explanatoryText(); default: break; @@ -375,6 +375,28 @@ void SymbolTableModel::setFilterPattern(const QString &pattern) emit symbolSelectionToBeUpdated(); } +int SymbolTableModel::getLastSectionIndex() +{ + switch(mType) { + case SymbolDataType::Set : + case SymbolDataType::Acronym : + case SymbolDataType::Parameter : + case SymbolDataType::Variable : + case SymbolDataType::Equation : + return 4; + case SymbolDataType::Model : + case SymbolDataType::Funct : + case SymbolDataType::File : + return 2; + case SymbolDataType::FileUsed : + return 0; + case SymbolDataType::Unknown : + case SymbolDataType::Unused : + return 5; + } + return 0; +} + SymbolTableModel::SortType SymbolTableModel::getSortTypeOf(int column) const { switch(mType) { diff --git a/src/reference/symboltablemodel.h b/src/reference/symboltablemodel.h index 1826746be..25b1b29ce 100644 --- a/src/reference/symboltablemodel.h +++ b/src/reference/symboltablemodel.h @@ -51,6 +51,7 @@ class SymbolTableModel : public QAbstractTableModel int getSortedIndexOf(const QString &name) const; void toggleSearchColumns(bool checked); void setFilterPattern(const QString& pattern); + int getLastSectionIndex(); static const int COLUMN_SYMBOL_ID = 0; static const int COLUMN_SYMBOL_NAME = 1; diff --git a/src/studio.pro b/src/studio.pro index e3e17b2e5..79f24d174 100644 --- a/src/studio.pro +++ b/src/studio.pro @@ -363,4 +363,5 @@ OTHER_FILES += \ ../jenkinsfile \ ../jenkinsfile-ci \ ../gamsstudio.desktop \ + ../CHANGELOG \ ../version diff --git a/src/support/aboutgamsdialog.cpp b/src/support/aboutgamsdialog.cpp index f32876ff5..43eab2287 100644 --- a/src/support/aboutgamsdialog.cpp +++ b/src/support/aboutgamsdialog.cpp @@ -23,8 +23,12 @@ #include "checkforupdatewrapper.h" #include "solvertablemodel.h" #include "commonpaths.h" +#include "locators/abstractsystemlogger.h" +#include "locators/sysloglocator.h" +#include "gamslicenseinfo.h" #include +#include #include #include #include @@ -103,63 +107,47 @@ void AboutGAMSDialog::createLicenseFile(QWidget *parent) { auto clipboard = QGuiApplication::clipboard(); auto licenseLines = clipboard->text().split('\n', QString::SkipEmptyParts); - if (!isValidLicense(licenseLines)) + for (int i=0; iappend("Unable to open file " + + QDir::toNativeSeparators(licenseFile.fileName()) + + ": " + licenseFile.errorString(), + LogMsgType::Error); } } -bool AboutGAMSDialog::isValidLicense(QStringList &license) -{ - if (license.count() < 5) - return false; - - for (int i=0; iappend(InvalidGAMS, LogMsgType::Error); logger->append(message, LogMsgType::Error); diff --git a/src/support/gamslicenseinfo.h b/src/support/gamslicenseinfo.h index 760de38f8..eb668cbc3 100644 --- a/src/support/gamslicenseinfo.h +++ b/src/support/gamslicenseinfo.h @@ -54,6 +54,8 @@ class GamsLicenseInfo QString solverLicense(int solverId) const; + bool isLicenseValid(const QStringList &license); + private: char* solverCodes(int solverId) const; diff --git a/src/syntax/syntaxhighlighter.cpp b/src/syntax/syntaxhighlighter.cpp index 2234d2d43..c646f8c19 100644 --- a/src/syntax/syntaxhighlighter.cpp +++ b/src/syntax/syntaxhighlighter.cpp @@ -276,6 +276,8 @@ const QVector invalidParenthesesSyntax = { SyntaxKind::Title, SyntaxKind::String, SyntaxKind::Assignment, + SyntaxKind::AssignmentLabel, + SyntaxKind::AssignmentValue, SyntaxKind::CommentLine, SyntaxKind::CommentBlock, SyntaxKind::CommentEndline, diff --git a/src/syntax/textmarkrepo.cpp b/src/syntax/textmarkrepo.cpp index 92825c641..8417ffdfe 100644 --- a/src/syntax/textmarkrepo.cpp +++ b/src/syntax/textmarkrepo.cpp @@ -241,7 +241,7 @@ const LineMarks *TextMarkRepo::marks(FileId fileId) void TextMarkRepo::shiftMarks(FileId fileId, int firstLine, int lineShift) { LineMarks *marks = mMarks.value(fileId); - if (!marks->size() || !lineShift) return; + if (!marks || !marks->size() || !lineShift) return; QSet changedLines; changedLines.reserve(marks->size()*2); QMutableMapIterator it(*marks); diff --git a/version b/version index 8c0bb6467..a6abc7e98 100644 --- a/version +++ b/version @@ -21,7 +21,7 @@ # Current GAMS Studio version. STUDIO_MAJOR_VERSION=0 STUDIO_MINOR_VERSION=12 -STUDIO_PATCH_LEVEL=7 +STUDIO_PATCH_LEVEL=8 VERSION='$$STUDIO_MAJOR_VERSION'.'$$STUDIO_MINOR_VERSION'.'$$STUDIO_PATCH_LEVEL' # Minimum required GAMS Distribution version, which