mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-02-25 15:00:56 +00:00

* Debugger: Fix Importing Breakpoints CSV functionality This resolves a few issues with the Breakpoint CSV importing functionality. Makes the following changes/fixes: - Assembly instructions with commas caused part of the instruction text to be considered the start of a new column (comma is the CSV delimiter), resulting in "too many columns errors" and failing to import. Now puts values in quotes and detects the true start and end of the values, so that no extra columns are created. - The import function was using the incorrect columns to load since the Enabled column was moved to be the first one but the import function had not been updated. Fixed this by using the column enum values instead of hardcoded numbers, so if ordering in the model changes it will still import fine. - Updates the beginRemoveRows function to not remove an extra row. With this function you would want a "count" of 0 to remove 1, so "row, row" deletes one, "row, row+1" deletes 2. Updates it to subtract one so that the range is not including one more than it is intended to. - * Misc: Cleanup regex string & add explicit imports Uses raw string literal to make the regular expression easier to read since regex is ugly enough as it is, we really don't need escaping characters in a string on top. Also explicitly includes used Qt classes.
290 lines
8.0 KiB
C++
290 lines
8.0 KiB
C++
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: LGPL-3.0+
|
|
|
|
#include "QtUtils.h"
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
#include <QtCore/QMetaObject>
|
|
#include <QtGui/QAction>
|
|
#include <QtGui/QGuiApplication>
|
|
#include <QtGui/QDesktopServices>
|
|
#include <QtGui/QKeyEvent>
|
|
#include <QtGui/QScreen>
|
|
#include <QtWidgets/QComboBox>
|
|
#include <QtWidgets/QDialog>
|
|
#include <QtWidgets/QHeaderView>
|
|
#include <QtWidgets/QInputDialog>
|
|
#include <QtWidgets/QMainWindow>
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtWidgets/QScrollBar>
|
|
#include <QtWidgets/QStatusBar>
|
|
#include <QtWidgets/QStyle>
|
|
#include <QtWidgets/QTableView>
|
|
#include <QtWidgets/QTreeView>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <map>
|
|
|
|
#include "common/Console.h"
|
|
|
|
#if defined(_WIN32)
|
|
#include "common/RedtapeWindows.h"
|
|
#elif !defined(APPLE)
|
|
#include <qpa/qplatformnativeinterface.h>
|
|
#endif
|
|
|
|
namespace QtUtils
|
|
{
|
|
void MarkActionAsDefault(QAction* action)
|
|
{
|
|
QFont new_font(action->font());
|
|
new_font.setBold(true);
|
|
action->setFont(new_font);
|
|
}
|
|
|
|
QFrame* CreateHorizontalLine(QWidget* parent)
|
|
{
|
|
QFrame* line = new QFrame(parent);
|
|
line->setFrameShape(QFrame::HLine);
|
|
line->setFrameShadow(QFrame::Sunken);
|
|
return line;
|
|
}
|
|
|
|
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog)
|
|
{
|
|
QWidget* next_parent = widget->parentWidget();
|
|
while (next_parent)
|
|
{
|
|
if (stop_at_window_or_dialog && (widget->metaObject()->inherits(&QMainWindow::staticMetaObject) ||
|
|
widget->metaObject()->inherits(&QDialog::staticMetaObject)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
widget = next_parent;
|
|
next_parent = widget->parentWidget();
|
|
}
|
|
|
|
return widget;
|
|
}
|
|
|
|
template <typename T>
|
|
static void ResizeColumnsForView(T* view, const std::initializer_list<int>& widths)
|
|
{
|
|
QHeaderView* header;
|
|
if constexpr (std::is_same_v<T, QTableView>)
|
|
header = view->horizontalHeader();
|
|
else
|
|
header = view->header();
|
|
|
|
const int min_column_width = header->minimumSectionSize();
|
|
const int scrollbar_width = ((view->verticalScrollBar() && view->verticalScrollBar()->isVisible()) ||
|
|
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ?
|
|
view->verticalScrollBar()->width() :
|
|
0;
|
|
int num_flex_items = 0;
|
|
int total_width = 0;
|
|
int column_index = 0;
|
|
for (const int spec_width : widths)
|
|
{
|
|
if (!view->isColumnHidden(column_index))
|
|
{
|
|
if (spec_width < 0)
|
|
num_flex_items++;
|
|
else
|
|
total_width += std::max(spec_width, min_column_width);
|
|
}
|
|
|
|
column_index++;
|
|
}
|
|
|
|
const int flex_width =
|
|
(num_flex_items > 0) ?
|
|
std::max((view->contentsRect().width() - total_width - scrollbar_width) / num_flex_items, 1) :
|
|
0;
|
|
|
|
column_index = 0;
|
|
for (const int spec_width : widths)
|
|
{
|
|
if (view->isColumnHidden(column_index))
|
|
{
|
|
column_index++;
|
|
continue;
|
|
}
|
|
|
|
const int width = spec_width < 0 ? flex_width : (std::max(spec_width, min_column_width));
|
|
view->setColumnWidth(column_index, width);
|
|
column_index++;
|
|
}
|
|
}
|
|
|
|
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths)
|
|
{
|
|
ResizeColumnsForView(view, widths);
|
|
}
|
|
|
|
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths)
|
|
{
|
|
ResizeColumnsForView(view, widths);
|
|
}
|
|
|
|
void OpenURL(QWidget* parent, const QUrl& qurl)
|
|
{
|
|
if (!QDesktopServices::openUrl(qurl))
|
|
{
|
|
QMessageBox::critical(parent, QObject::tr("Failed to open URL"),
|
|
QObject::tr("Failed to open URL.\n\nThe URL was: %1").arg(qurl.toString()));
|
|
}
|
|
}
|
|
|
|
void OpenURL(QWidget* parent, const char* url)
|
|
{
|
|
return OpenURL(parent, QUrl::fromEncoded(QByteArray(url, static_cast<int>(std::strlen(url)))));
|
|
}
|
|
|
|
void OpenURL(QWidget* parent, const QString& url)
|
|
{
|
|
return OpenURL(parent, QUrl(url));
|
|
}
|
|
|
|
QString StringViewToQString(const std::string_view& str)
|
|
{
|
|
return str.empty() ? QString() : QString::fromUtf8(str.data(), str.size());
|
|
}
|
|
|
|
void SetWidgetFontForInheritedSetting(QWidget* widget, bool inherited)
|
|
{
|
|
if (widget->font().italic() != inherited)
|
|
{
|
|
QFont new_font(widget->font());
|
|
new_font.setItalic(inherited);
|
|
widget->setFont(new_font);
|
|
}
|
|
}
|
|
|
|
void SetWindowResizeable(QWidget* widget, bool resizeable)
|
|
{
|
|
if (QMainWindow* window = qobject_cast<QMainWindow*>(widget); window)
|
|
{
|
|
// update status bar grip if present
|
|
if (QStatusBar* sb = window->statusBar(); sb)
|
|
sb->setSizeGripEnabled(resizeable);
|
|
}
|
|
|
|
if ((widget->sizePolicy().horizontalPolicy() == QSizePolicy::Preferred) != resizeable)
|
|
{
|
|
if (resizeable)
|
|
{
|
|
// Min/max numbers come from uic.
|
|
widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
|
widget->setMinimumSize(1, 1);
|
|
widget->setMaximumSize(16777215, 16777215);
|
|
}
|
|
else
|
|
{
|
|
widget->setFixedSize(widget->size());
|
|
widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height)
|
|
{
|
|
width = std::max(width, 1);
|
|
height = std::max(height, 1);
|
|
if (widget->sizePolicy().horizontalPolicy() == QSizePolicy::Fixed)
|
|
widget->setFixedSize(width, height);
|
|
|
|
widget->resize(width, height);
|
|
}
|
|
|
|
qreal GetDevicePixelRatioForWidget(const QWidget* widget)
|
|
{
|
|
const QScreen* screen_for_ratio = widget->screen();
|
|
if (!screen_for_ratio)
|
|
screen_for_ratio = QGuiApplication::primaryScreen();
|
|
|
|
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
|
|
}
|
|
|
|
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget)
|
|
{
|
|
WindowInfo wi;
|
|
|
|
// Windows and Apple are easy here since there's no display connection.
|
|
#if defined(_WIN32)
|
|
wi.type = WindowInfo::Type::Win32;
|
|
wi.window_handle = reinterpret_cast<void*>(widget->winId());
|
|
#elif defined(__APPLE__)
|
|
wi.type = WindowInfo::Type::MacOS;
|
|
wi.window_handle = reinterpret_cast<void*>(widget->winId());
|
|
#else
|
|
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
|
const QString platform_name = QGuiApplication::platformName();
|
|
if (platform_name == QStringLiteral("xcb"))
|
|
{
|
|
// Can't get a handle for an unmapped window in X, it doesn't like it.
|
|
if (!widget->isVisible())
|
|
{
|
|
Console.WriteLn("Returning null window info for widget because it is not visible.");
|
|
return std::nullopt;
|
|
}
|
|
|
|
wi.type = WindowInfo::Type::X11;
|
|
wi.display_connection = pni->nativeResourceForWindow("display", widget->windowHandle());
|
|
wi.window_handle = reinterpret_cast<void*>(widget->winId());
|
|
}
|
|
else if (platform_name == QStringLiteral("wayland"))
|
|
{
|
|
wi.type = WindowInfo::Type::Wayland;
|
|
wi.display_connection = pni->nativeResourceForWindow("display", widget->windowHandle());
|
|
wi.window_handle = pni->nativeResourceForWindow("surface", widget->windowHandle());
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLn("Unknown PNI platform '%s'.", platform_name.toUtf8().constData());
|
|
return std::nullopt;
|
|
}
|
|
#endif
|
|
|
|
const qreal dpr = GetDevicePixelRatioForWidget(widget);
|
|
wi.surface_width = static_cast<u32>(static_cast<qreal>(widget->width()) * dpr);
|
|
wi.surface_height = static_cast<u32>(static_cast<qreal>(widget->height()) * dpr);
|
|
wi.surface_scale = static_cast<float>(dpr);
|
|
return wi;
|
|
}
|
|
|
|
QString AbstractItemModelToCSV(QAbstractItemModel* model, int role, bool useQuotes)
|
|
{
|
|
QString csv;
|
|
// Header
|
|
for (int col = 0; col < model->columnCount(); col++)
|
|
{
|
|
// Encapsulate value in quotes so that commas don't break the column count.
|
|
QString headerLine = model->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
|
|
csv += useQuotes ? QString("\"%1\"").arg(headerLine) : headerLine;
|
|
if (col < model->columnCount() - 1)
|
|
csv += ",";
|
|
}
|
|
|
|
csv += "\n";
|
|
|
|
// Data
|
|
for (int row = 0; row < model->rowCount(); row++)
|
|
{
|
|
for (int col = 0; col < model->columnCount(); col++)
|
|
{
|
|
// Encapsulate value in quotes so that commas don't break the column count.
|
|
QString dataLine = model->data(model->index(row, col), role).toString();
|
|
csv += useQuotes ? QString("\"%1\"").arg(dataLine) : dataLine;
|
|
|
|
if (col < model->columnCount() - 1)
|
|
csv += ",";
|
|
}
|
|
csv += "\n";
|
|
}
|
|
return csv;
|
|
}
|
|
} // namespace QtUtils
|