fix: 优化界面提示;修复与工作区相关的若干个问题;

This commit is contained in:
寂静的羽夏 2025-01-23 20:39:04 +08:00
parent 5d78503b58
commit bef7f232f3
27 changed files with 904 additions and 698 deletions

View File

@ -15,6 +15,7 @@ void AppendCommand::undo() {
m_doc->insertBookMarkAdjustRevert(offset, m_length);
m_doc->metadata()->insertAdjustRevert(offset, m_length);
m_cursor->setPos(offset, m_nibbleindex);
HexCommand::undo();
}
void AppendCommand::redo() {
@ -27,4 +28,5 @@ void AppendCommand::redo() {
} else {
m_cursor->setPos(offset + m_length, m_nibbleindex);
}
HexCommand::redo();
}

View File

@ -4,3 +4,10 @@ HexCommand::HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent)
: QUndoCommand(parent), m_doc(doc), m_cursor(cursor), m_offset(0),
m_length(0), m_nibbleindex(nibbleindex) {}
void HexCommand::undo() {
Q_ASSERT(m_doc->m_bytesModFlag > 0);
m_doc->m_bytesModFlag--;
}
void HexCommand::redo() { m_doc->m_bytesModFlag++; }

View File

@ -11,6 +11,9 @@ public:
HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
protected:
QHexDocument *m_doc;
QHexCursor *m_cursor;

View File

@ -14,6 +14,7 @@ void InsertCommand::undo() {
m_doc->insertBookMarkAdjustRevert(m_offset, m_length);
m_doc->metadata()->insertAdjustRevert(m_offset, m_length);
m_cursor->setPos(m_offset, m_nibbleindex);
HexCommand::undo();
}
void InsertCommand::redo() {
m_doc->_insert(m_offset, m_data);
@ -24,4 +25,5 @@ void InsertCommand::redo() {
} else {
m_cursor->setPos(m_offset + m_length, m_nibbleindex);
}
HexCommand::redo();
}

View File

@ -22,6 +22,7 @@ void RemoveCommand::undo() {
m_cursor->setPos(m_offset, 0);
}
}
HexCommand::undo();
}
void RemoveCommand::redo() {
@ -29,4 +30,5 @@ void RemoveCommand::redo() {
m_doc->_remove(m_offset, m_length);
_rmbms = m_doc->removeBookMarkAdjust(m_offset, m_length);
_rmMetas = m_doc->metadata()->removeAdjust(m_offset, m_length);
HexCommand::redo();
}

View File

@ -5,7 +5,6 @@ ReplaceCommand::ReplaceCommand(QHexDocument *doc, qsizetype offset,
const QByteArray &data, QHexCursor *cursor,
int nibbleindex, QUndoCommand *parent)
: HexCommand(doc, cursor, nibbleindex, parent) {
m_offset = offset;
m_data = data;
m_length = data.length();
@ -15,6 +14,7 @@ ReplaceCommand::ReplaceCommand(QHexDocument *doc, qsizetype offset,
void ReplaceCommand::undo() {
m_doc->_replace(m_offset, m_olddata);
m_cursor->setPos(m_offset, m_nibbleindex);
HexCommand::undo();
}
void ReplaceCommand::redo() {
@ -24,4 +24,5 @@ void ReplaceCommand::redo() {
} else {
m_cursor->setPos(m_offset + m_length, !m_nibbleindex);
}
HexCommand::redo();
}

View File

@ -6,6 +6,6 @@ MetaReplaceCommand::MetaReplaceCommand(QHexMetadata *hexmeta,
QUndoCommand *parent)
: MetaCommand(hexmeta, meta, parent), m_old(oldmeta) {}
void MetaReplaceCommand::undo() { m_hexmeta->modifyMetadata(m_meta, m_old); }
void MetaReplaceCommand::undo() { m_hexmeta->modifyMetadata(m_old, m_meta); }
void MetaReplaceCommand::redo() { m_hexmeta->modifyMetadata(m_old, m_meta); }
void MetaReplaceCommand::redo() { m_hexmeta->modifyMetadata(m_meta, m_old); }

View File

@ -115,8 +115,6 @@ public:
qsizetype currentSelectionLength() const;
bool atEnd() const;
bool isLineSelected(qsizetype line) const;
bool isSelected(const QHexPosition &pos) const;
bool hasSelection() const;

View File

@ -205,6 +205,8 @@ void QHexDocument::removeBookMarkAdjustRevert(
bool QHexDocument::isDocSaved() { return m_isSaved; }
bool QHexDocument::isUndoByteModified() { return m_bytesModFlag > 0; }
void QHexDocument::setDocSaved(bool b) {
if (b) {
m_undostack->setClean();

View File

@ -12,6 +12,8 @@
class QHexDocument : public QObject {
Q_OBJECT
friend class HexCommand;
private:
explicit QHexDocument(QHexBuffer *buffer,
bool readonly = false); // modified by wingsummer
@ -79,7 +81,9 @@ public:
void findAllBytes(
qsizetype begin, qsizetype end, QByteArray b, QList<qsizetype> &results,
const std::function<bool()> &pred = [] { return true; });
bool isDocSaved();
bool isUndoByteModified();
void setDocSaved(bool b = true);
void setMetafgVisible(bool b);
@ -222,7 +226,10 @@ signals:
private:
QHexBuffer *m_buffer;
QHexMetadata *m_metadata;
QUndoStack *m_undostack;
size_t m_bytesModFlag = 0;
quintptr m_baseaddress;
quint8 m_areaindent;
quint8 m_hexlinewidth;

View File

@ -272,6 +272,10 @@ void QHexMetadata::applyMetas(const QVector<QHexMetadataItem> &metas) {
for (auto &meta : metas) {
m_metadata.mergeAdd(meta);
}
for (auto &meta : m_metadata) {
addMetaLines(meta);
}
emit metadataChanged();
}
bool QHexMetadata::hasMetadata() { return m_metadata.count() > 0; }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,9 @@
"Id": "WingAngelAPI",
"Name": "WingAngelAPI",
"Author": "wingsummer",
"Version": "0.0.1",
"Version": "2.1.0",
"Vendor": "WingCloudStudio",
"Copyright": "wingsummer",
"License": "AGPL-3.0"
"License": "AGPL-3.0",
"Url": "https://github.com/Wing-summer/WingHexExplorer2"
}

View File

@ -85,25 +85,26 @@ bool WorkSpaceManager::loadWorkSpace(const QString &filename, QString &file,
auto nend = end.toString().toLongLong(&b);
if (!b || nend >= maxbytes || nend < 0)
continue;
auto nf = fgcolor.toString().toUInt(&b, 16);
if (!b)
continue;
auto nb = bgcolor.toString().toUInt(&b, 16);
if (!b)
continue;
auto fcolor = QColor::fromRgba(nf);
auto bcolor = QColor::fromRgba(nb);
static auto NO_COLOR = QStringLiteral("-");
QColor fcolor, bcolor;
auto fgn = fgcolor.toString();
if (fgn != NO_COLOR) {
fcolor = QColor(fgn);
}
auto bgn = bgcolor.toString();
if (bgn != NO_COLOR) {
bcolor = QColor(bgn);
}
QHexMetadataItem metaitem;
metaitem.begin = nbegin;
metaitem.end = nend;
metaitem.comment = comment.toString();
metaitem.foreground = fcolor.alpha() > 0
? fcolor.toHsv()
: fcolor;
metaitem.background = bcolor.alpha() > 0
? fcolor.toHsv()
: bcolor;
metaitem.foreground = fcolor;
metaitem.background = bcolor;
metas.append(metaitem);
}
}
@ -164,6 +165,14 @@ bool WorkSpaceManager::loadWorkSpace(const QString &filename, QString &file,
return false;
}
QString WorkSpaceManager::getColorString(const QColor &color) {
static auto NO_COLOR = QStringLiteral("-");
if (color.isValid()) {
return color.name();
}
return NO_COLOR;
}
bool WorkSpaceManager::saveWorkSpace(
const QString &filename, const QString &file,
const QMap<qsizetype, QString> &bookmarklist,
@ -190,8 +199,8 @@ bool WorkSpaceManager::saveWorkSpace(
obj.insert("begin", QString::number(meta.begin));
obj.insert("end", QString::number(meta.end));
obj.insert("comment", meta.comment);
obj.insert("fgcolor", QString::number(meta.foreground.rgba(), 16));
obj.insert("bgcolor", QString::number(meta.background.rgba(), 16));
obj.insert("fgcolor", getColorString(meta.foreground));
obj.insert("bgcolor", getColorString(meta.background));
metas.append(obj);
}
jobj.insert("metas", metas);

View File

@ -47,6 +47,9 @@ public:
QMap<qsizetype, QString> &bookmarks,
QVector<QHexMetadataItem> &metas,
WorkSpaceInfo &infos);
private:
QString static getColorString(const QColor &color);
};
#endif // WORKSPACEMANAGER_H

View File

@ -465,24 +465,6 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
}
}
QFile file(fileName);
switch (m_docType) {
case DocumentType::RegionFile: {
if (!ignoreMd5 && Utilities::getMd5(m_fileName) != m_md5) {
return ErrFile::SourceFileChanged;
}
if (!file.open(QFile::ReadWrite)) {
return ErrFile::Permission;
}
} break;
default: {
if (!file.open(QFile::WriteOnly)) {
return ErrFile::Permission;
}
} break;
}
if (workSpaceAttr == SaveWorkSpaceAttr::ForceWorkSpace ||
(workSpaceAttr == SaveWorkSpaceAttr::AutoWorkSpace &&
(m_isWorkSpace || hasMeta()))) {
@ -499,18 +481,43 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
}
}
if (doc->saveTo(&file, true)) {
file.close();
if (doc->isUndoByteModified()) {
QFile file(fileName);
if (!isExport) {
m_fileName = QFileInfo(fileName).absoluteFilePath();
doc->setDocSaved();
switch (m_docType) {
case DocumentType::RegionFile: {
if (!ignoreMd5 && Utilities::getMd5(m_fileName) != m_md5) {
return ErrFile::SourceFileChanged;
}
if (!file.open(QFile::ReadWrite)) {
return ErrFile::Permission;
}
} break;
default: {
if (!file.open(QFile::WriteOnly)) {
return ErrFile::Permission;
}
} break;
}
return ErrFile::Success;
if (doc->saveTo(&file, true)) {
file.close();
if (!isExport) {
m_fileName = QFileInfo(fileName).absoluteFilePath();
doc->setDocSaved();
}
return ErrFile::Success;
}
return ErrFile::Permission;
} else {
doc->setDocSaved();
}
return ErrFile::Permission;
return ErrFile::Success;
}
ErrFile EditorView::reload() {

View File

@ -49,4 +49,6 @@ void QListViewExt::setModel(QAbstractItemModel *model) {
vbar->blockSignals(false);
QListView::setModel(model);
emit modelChanged();
}

View File

@ -26,6 +26,9 @@ public:
explicit QListViewExt(QWidget *parent = nullptr);
void setModel(QAbstractItemModel *model) override;
signals:
void modelChanged();
};
#endif // QLISTVIEWEXT_H

View File

@ -49,4 +49,6 @@ void QTableViewExt::setModel(QAbstractItemModel *model) {
vbar->blockSignals(false);
QTableView::setModel(model);
emit modelChanged();
}

View File

@ -26,6 +26,9 @@ public:
explicit QTableViewExt(QWidget *parent = nullptr);
void setModel(QAbstractItemModel *model) override;
signals:
void modelChanged();
};
#endif // QTABLEVIEWEXT_H

View File

@ -127,6 +127,14 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
m_status->addWidget(l);
m_status->addWidget(m_lblsellen);
_status = new QLabel(m_status);
m_status->addPermanentWidget(_status);
auto separator = new QFrame(m_status);
separator->setFrameShape(QFrame::VLine);
separator->setFrameShadow(QFrame::Sunken);
m_status->addPermanentWidget(separator);
auto disableStyle =
QStringLiteral("border:none;background:transparent;");
@ -547,6 +555,14 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->setContextMenuPolicy(
Qt::ContextMenuPolicy::CustomContextMenu);
auto se = [=]() {
auto model = qobject_cast<FindResultModel *>(m_findresult->model());
if (model) {
m_find->setWindowTitle(tr("FindResult") + QStringLiteral(" (") +
model->encoding() + QStringLiteral(")"));
}
};
auto menu = new QMenu(tr("Encoding"), this);
menu->setIcon(ICONRES(QStringLiteral("encoding")));
auto aGroup = new QActionGroup(this);
@ -556,6 +572,7 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
auto model = qobject_cast<FindResultModel *>(m_findresult->model());
if (model) {
model->setEncoding(l);
se();
}
});
aGroup->addAction(a);
@ -620,8 +637,10 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
});
auto dw = buildDockWidget(dock, QStringLiteral("FindResult"),
tr("FindResult"), m_findresult);
tr("FindResult") + QStringLiteral(" (ASCII)"),
m_findresult);
m_find = dw;
connect(m_findresult, &QTableViewExt::modelChanged, this, se);
return dock->addDockWidget(area, dw, areaw);
}
@ -857,6 +876,20 @@ MainWindow::buildUpDecodingStrShowDock(ads::CDockManager *dock,
auto dw = buildDockWidget(dock, QStringLiteral("DecodeText"),
tr("DecodeText") + QStringLiteral(" (ASCII)"),
m_txtDecode);
auto menu = m_txtDecode->createStandardContextMenu();
menu->addSeparator();
auto a = new QAction(tr("Encoding"), this);
a->setIcon(ICONRES(QStringLiteral("encoding")));
connect(a, &QAction::triggered, this, &MainWindow::on_encoding);
menu->addAction(a);
m_txtDecode->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_txtDecode, &QTextBrowser::customContextMenuRequested, this,
[=](const QPoint &pos) {
menu->popup(m_txtDecode->viewport()->mapToGlobal(pos));
});
connect(m_txtDecode, &QTextBrowser::windowTitleChanged, dw,
&QDockWidget::setWindowTitle);
return dock->addDockWidget(area, dw, areaw);
@ -1332,10 +1365,6 @@ RibbonTabContent *MainWindow::buildEditPage(RibbonTabContent *tab) {
pannel, QStringLiteral("jmp"), tr("Goto"), &MainWindow::on_gotoline,
shortcuts.keySequence(QKeySequences::Key::GOTO));
addPannelAction(pannel, QStringLiteral("encoding"), tr("Encoding"),
&MainWindow::on_encoding,
shortcuts.keySequence(QKeySequences::Key::ENCODING));
m_editStateWidgets << addPannelAction(pannel, QStringLiteral("sum"),
tr("CheckSum"),
&MainWindow::on_checksum);
@ -1873,6 +1902,8 @@ void MainWindow::installPluginEditorWidgets() {
m_editorViewWidgets.clear();
}
void MainWindow::showStatus(const QString &status) { _status->setText(status); }
EditorView *MainWindow::newfileGUI() {
if (!newOpenFileSafeCheck()) {
return nullptr;
@ -2263,6 +2294,7 @@ void MainWindow::on_findfile() {
ExecAsync<EditorView::FindError>(
[this, r]() -> EditorView::FindError {
this->showStatus(tr("Finding..."));
return currentEditor()->find(r);
},
[this](EditorView::FindError err) {
@ -2287,6 +2319,8 @@ void MainWindow::on_findfile() {
m_findEncoding.value(result->encoding())->setChecked(true);
}
m_find->raise();
this->showStatus({});
});
}
}
@ -3077,7 +3111,7 @@ bool MainWindow::newOpenFileSafeCheck() {
return true;
}
void MainWindow::registerEditorView(EditorView *editor) {
void MainWindow::registerEditorView(EditorView *editor, const QString &ws) {
for (auto &w : m_editorViewWidgetsBuffer) {
editor->registerView(w->id(), w->create(editor));
}
@ -3090,7 +3124,7 @@ void MainWindow::registerEditorView(EditorView *editor) {
editor->setFontSize(set.editorfontSize());
connectEditorView(editor);
m_views.insert(editor, {});
m_views.insert(editor, ws);
auto ev = m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS);
auto menu = ev->menu();
Q_ASSERT(menu);
@ -3155,7 +3189,7 @@ void MainWindow::connectEditorView(EditorView *editor) {
o.foreground = m.foreGroundColor();
o.background = m.backGroundColor();
o.comment = m.comment();
mi->ModifyMetadata(meta, o);
mi->ModifyMetadata(o, meta);
}
} else {
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
@ -3178,8 +3212,47 @@ void MainWindow::connectEditorView(EditorView *editor) {
if (ret == QMessageBox::Cancel) {
return;
} else if (ret == QMessageBox::Yes) {
if (saveEditor(editor, {}, false) == ErrFile::Success) {
auto ret = saveEditor(editor, {}, false);
switch (ret) {
case WingHex::Success:
// ok, no need to report
closeEditor(editor, m_isOnClosing);
break;
case WingHex::Permission: {
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("FilePermissionSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
case WingHex::Error:
case WingHex::UnSaved:
case WingHex::NotExist:
case WingHex::AlreadyOpened:
case WingHex::IsNewFile:
case WingHex::IsDirver:
case WingHex::SourceFileChanged:
case WingHex::ClonedFile:
case WingHex::InvalidFormat:
case WingHex::TooManyOpenedFile:
case WingHex::NotAllowedInNoneGUIThread: {
// unknown error
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("UnknownErrorSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
case WingHex::WorkSpaceUnSaved: {
auto btn = WingMessageBox::critical(
this, tr("Error"), tr("WorkSpaceUnSavedSure2Quit"),
QMessageBox::Yes | QMessageBox::No);
if (btn == QMessageBox::Yes) {
closeEditor(editor, true);
}
} break;
}
} else {
closeEditor(editor, true);
@ -3423,8 +3496,7 @@ ErrFile MainWindow::openWorkSpace(const QString &file, EditorView **editor) {
return res;
}
m_views.insert(ev, file);
registerEditorView(ev);
registerEditorView(ev, file);
if (editor) {
*editor = ev;
}

View File

@ -138,6 +138,8 @@ private:
void buildUpSettingDialog();
void installPluginEditorWidgets();
void showStatus(const QString &status);
private:
EditorView *newfileGUI();
@ -238,7 +240,7 @@ private:
EditorView *findEditorView(const QString &filename);
bool newOpenFileSafeCheck();
void registerEditorView(EditorView *editor);
void registerEditorView(EditorView *editor, const QString &ws = {});
void connectEditorView(EditorView *editor);
void swapEditor(EditorView *old, EditorView *cur);
@ -497,6 +499,7 @@ private:
private:
Ribbon *m_ribbon = nullptr;
ads::CDockManager *m_dock = nullptr;
QLabel *_status = nullptr;
QString m_encoding;

View File

@ -122,14 +122,14 @@ QColor MetaDialog::foreGroundColor() {
if (cforeground->isChecked())
return _foreground;
else
return QColor(qRgba(0, 0, 0, 0));
return QColor();
}
QColor MetaDialog::backGroundColor() {
if (cbackground->isChecked())
return _background;
else
return QColor::fromRgba(qRgba(0, 0, 0, 0));
return QColor();
}
void MetaDialog::setComment(QString comment) {

View File

@ -112,14 +112,18 @@ void PluginSettingDialog::on_devlist_currentRowChanged(int currentRow) {
auto info = plgsys.getPluginInfo(plg);
ui->txtd->clear();
ui->txtd->append(tr("ID") + " : " + info.id);
ui->txtd->append(tr("Name") + " : " + plg->pluginName());
ui->txtd->append(tr("License") + " : " + info.license);
ui->txtd->append(tr("Author") + " : " + info.author);
ui->txtd->append(tr("Vendor") + " : " + info.vendor);
ui->txtd->append(tr("Version") + " : " + info.version.toString());
ui->txtd->append(tr("Comment") + " : " + plg->pluginComment());
ui->txtd->append(tr("URL") + " : " + info.url);
ui->txtd->append(getWrappedText(tr("ID") + " : " + info.id));
ui->txtd->append(getWrappedText(tr("Name") + " : " + plg->pluginName()));
ui->txtd->append(getWrappedText(tr("License") + " : " + info.license));
ui->txtd->append(getWrappedText(tr("Author") + " : " + info.author));
ui->txtd->append(getWrappedText(tr("Vendor") + " : " + info.vendor));
ui->txtd->append(
getWrappedText(tr("Version") + " : " + info.version.toString()));
ui->txtd->append(
getWrappedText(tr("Comment") + " : " + plg->pluginComment()));
ui->txtd->append(getWrappedText(
tr("URL") + " : " + QStringLiteral("<a href=\"") + info.url +
QStringLiteral("\">") + info.url + QStringLiteral("</a>")));
}
void PluginSettingDialog::on_plglist_currentRowChanged(int currentRow) {
@ -132,20 +136,30 @@ void PluginSettingDialog::on_plglist_currentRowChanged(int currentRow) {
auto info = plgsys.getPluginInfo(plg);
ui->txtc->clear();
ui->txtc->append(tr("ID") + " : " + info.id);
ui->txtc->append(tr("Name") + " : " + plg->pluginName());
ui->txtc->append(tr("License") + " : " + info.license);
ui->txtc->append(tr("Author") + " : " + info.author);
ui->txtc->append(tr("Vendor") + " : " + info.vendor);
ui->txtc->append(tr("Version") + " : " + info.version.toString());
ui->txtc->append(tr("Comment") + " : " + plg->pluginComment());
ui->txtc->append(getWrappedText(tr("ID") + " : " + info.id));
ui->txtc->append(getWrappedText(tr("Name") + " : " + plg->pluginName()));
ui->txtc->append(getWrappedText(tr("License") + " : " + info.license));
ui->txtc->append(getWrappedText(tr("Author") + " : " + info.author));
ui->txtc->append(getWrappedText(tr("Vendor") + " : " + info.vendor));
ui->txtc->append(
getWrappedText(tr("Version") + " : " + info.version.toString()));
ui->txtc->append(
getWrappedText(tr("Comment") + " : " + plg->pluginComment()));
if (!info.dependencies.isEmpty()) {
ui->txtc->append(tr("pluginDependencies:"));
ui->txtc->append(getWrappedText(tr("pluginDependencies:")));
for (auto &d : info.dependencies) {
ui->txtc->append(QString(4, ' ') + tr("PUID:") + d.puid);
ui->txtc->append(QString(4, ' ') + tr("Version:") +
d.version.toString());
ui->txtc->append(
getWrappedText(QString(4, ' ') + tr("PUID:") + d.puid));
ui->txtc->append(getWrappedText(QString(4, ' ') + tr("Version:") +
d.version.toString()));
}
}
ui->txtc->append(tr("URL") + " : " + info.url);
ui->txtc->append(getWrappedText(
tr("URL") + " : " + QStringLiteral("<a href=\"") + info.url +
QStringLiteral("\">") + info.url + QStringLiteral("</a> ")));
}
QString PluginSettingDialog::getWrappedText(const QString &str) {
return QStringLiteral("<a>") + str + QStringLiteral("</a>");
}

View File

@ -51,6 +51,9 @@ public:
private slots:
void on_devlist_currentRowChanged(int currentRow);
void on_plglist_currentRowChanged(int currentRow);
private:
QString getWrappedText(const QString &str);
};
#endif // PLUGINSETTINGDIALOG_H

View File

@ -118,7 +118,11 @@
</item>
</layout>
</widget>
<widget class="QTextBrowser" name="txtc"/>
<widget class="QTextBrowser" name="txtc">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
@ -154,7 +158,11 @@
</item>
</layout>
</widget>
<widget class="QTextBrowser" name="txtd"/>
<widget class="QTextBrowser" name="txtd">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>