open available error URLs with double click or from context menu

This commit is contained in:
Axel Kohlmeyer
2025-04-28 18:25:40 -04:00
parent db3d93210d
commit 75d3d79fca
6 changed files with 68 additions and 3 deletions

View File

@ -308,7 +308,10 @@ of the *Output* window showing how many warnings and errors were
detected and how many lines the entire output has. By clicking on the detected and how many lines the entire output has. By clicking on the
button on the right with the warning symbol or by using the keyboard button on the right with the warning symbol or by using the keyboard
shortcut `Ctrl-N` (`Command-N` on macOS), you can jump to the next shortcut `Ctrl-N` (`Command-N` on macOS), you can jump to the next
line with a warning or error. line with a warning or error. If there is a URL pointing to additional
explanations in the online manual, that URL will be highlighted and
double-clicking on it shall open the corresponding manual page in
the web browser. The option is also available from the context menu.
By default, the *Output* window is replaced each time a run is started. By default, the *Output* window is replaced each time a run is started.
The runs are counted and the run number for the current run is displayed The runs are counted and the run number for the current run is displayed

View File

@ -2,7 +2,6 @@ LAMMPS-GUI TODO list:
# Short term goals (v1.x) # Short term goals (v1.x)
- open highlighted errorURL in web browser when clicking on it in the logfile viewer.
- add a "Colors" menu to the image viewer to adjust color settings for the - add a "Colors" menu to the image viewer to adjust color settings for the
current image (unlike the defaults in the perferences) including assigning current image (unlike the defaults in the perferences) including assigning
colors to individual atom types. colors to individual atom types.

View File

@ -23,7 +23,8 @@
// workaround for Qt-5.12 // workaround for Qt-5.12
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
namespace QColorConstants { namespace QColorConstants {
const QColor Red = QColor::fromRgb(0xff, 0x00, 0x00); const QColor Red = QColor::fromRgb(0xff, 0x00, 0x00);
const QColor Blue = QColor::fromRgb(0x00, 0x00, 0xff);
} // namespace QColorConstants } // namespace QColorConstants
#endif #endif

View File

@ -63,6 +63,8 @@
Add text fields for editing plot title and axis labels for charts Add text fields for editing plot title and axis labels for charts
Add option to automatically open tutorial websites (enabled by default) Add option to automatically open tutorial websites (enabled by default)
Add preferences tab for charts to set default for title, plot colors, smooth/raw plot, smooth params Add preferences tab for charts to set default for title, plot colors, smooth/raw plot, smooth params
Highlight error URLs with pointers to additional explanations in log window
Double-click on highlighted URL opens it in web browser. Also available via context menu.
</description> </description>
</release> </release>
<release version="1.6.12" timestamp="1734890080"> <release version="1.6.12" timestamp="1734890080">

View File

@ -18,6 +18,7 @@
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QDesktopServices>
#include <QFile> #include <QFile>
#include <QFileDialog> #include <QFileDialog>
#include <QGridLayout> #include <QGridLayout>
@ -37,6 +38,7 @@
const QString LogWindow::yaml_regex = const QString LogWindow::yaml_regex =
QStringLiteral("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)"); QStringLiteral("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)");
const QString LogWindow::url_regex = QStringLiteral("^.*(https://docs.lammps.org/err[0-9]+).*$");
LogWindow::LogWindow(const QString &_filename, QWidget *parent) : LogWindow::LogWindow(const QString &_filename, QWidget *parent) :
QPlainTextEdit(parent), filename(_filename), warnings(nullptr) QPlainTextEdit(parent), filename(_filename), warnings(nullptr)
@ -198,8 +200,53 @@ void LogWindow::extract_yaml()
file.close(); file.close();
} }
void LogWindow::open_errorurl()
{
if (!errorurl.isEmpty()) QDesktopServices::openUrl(QUrl(errorurl));
}
void LogWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
// select the entire word (non-space text) under the cursor
// we need to do it in this complicated way, since QTextCursor does not recognize
// special characters as part of a word.
auto cursor = textCursor();
auto line = cursor.block().text();
int begin = qMin(cursor.positionInBlock(), line.length() - 1);
while (begin >= 0) {
if (line[begin].isSpace()) break;
--begin;
}
int end = begin + 1;
while (end < line.length()) {
if (line[end].isSpace()) break;
++end;
}
cursor.setPosition(cursor.position() - cursor.positionInBlock() + begin + 1);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, end - begin - 1);
auto text = cursor.selectedText();
auto url = QRegularExpression(url_regex).match(text);
if (url.hasMatch()) {
errorurl = url.captured(1);
if (!errorurl.isEmpty()) {
QDesktopServices::openUrl(QUrl(errorurl));
return;
}
}
}
// forward event to parent class for all unhandled cases
QPlainTextEdit::mouseDoubleClickEvent(event);
}
void LogWindow::contextMenuEvent(QContextMenuEvent *event) void LogWindow::contextMenuEvent(QContextMenuEvent *event)
{ {
// reposition the cursor here, but only if there is no active selection
if (!textCursor().hasSelection()) setTextCursor(cursorForPosition(event->pos()));
// show augmented context menu // show augmented context menu
auto *menu = createStandardContextMenu(); auto *menu = createStandardContextMenu();
menu->addSeparator(); menu->addSeparator();
@ -214,6 +261,15 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event)
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y)); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y));
connect(action, &QAction::triggered, this, &LogWindow::extract_yaml); connect(action, &QAction::triggered, this, &LogWindow::extract_yaml);
} }
// process line of text where the cursor is
auto text = textCursor().block().text().replace('\t', ' ').trimmed();
auto url = QRegularExpression(url_regex).match(text);
if (url.hasMatch()) {
errorurl = url.captured(1);
action = menu->addAction("Open &URL in Web Browser", this, &LogWindow::open_errorurl);
action->setIcon(QIcon(":/icons/help-browser.png"));
}
action = menu->addAction("&Jump to next warning or error", this, &LogWindow::next_warning); action = menu->addAction("&Jump to next warning or error", this, &LogWindow::next_warning);
action->setIcon(QIcon(":/icons/warning.png")); action->setIcon(QIcon(":/icons/warning.png"));
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N));

View File

@ -32,16 +32,20 @@ private slots:
void save_as(); void save_as();
void stop_run(); void stop_run();
void next_warning(); void next_warning();
void open_errorurl();
protected: protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override;
bool check_yaml(); bool check_yaml();
private: private:
QString filename; QString filename;
QString errorurl;
static const QString yaml_regex; static const QString yaml_regex;
static const QString url_regex;
FlagWarnings *warnings; FlagWarnings *warnings;
QLabel *summary; QLabel *summary;
}; };