mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-29 02:03:03 +08:00
frontend: Finalize merge of OBSBasic Sources with module sources
This commit is contained in:
@@ -1,446 +1,44 @@
|
||||
#include "moc_window-extra-browsers.cpp"
|
||||
#include "window-dock-browser.hpp"
|
||||
#include "window-basic-main.hpp"
|
||||
/******************************************************************************
|
||||
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
|
||||
|
||||
#include <qt-wrappers.hpp>
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QUuid>
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "OBSBasic.hpp"
|
||||
|
||||
#ifdef BROWSER_AVAILABLE
|
||||
#include <dialogs/OBSExtraBrowsers.hpp>
|
||||
#include <docks/BrowserDock.hpp>
|
||||
|
||||
#include <json11.hpp>
|
||||
#include <qt-wrappers.hpp>
|
||||
|
||||
#include "ui_OBSExtraBrowsers.h"
|
||||
#include <QDir>
|
||||
|
||||
using namespace json11;
|
||||
#endif
|
||||
|
||||
#define OBJ_NAME_SUFFIX "_extraBrowser"
|
||||
#include <random>
|
||||
|
||||
enum class Column : int {
|
||||
Title,
|
||||
Url,
|
||||
Delete,
|
||||
struct QCef;
|
||||
struct QCefCookieManager;
|
||||
|
||||
Count,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void ExtraBrowsersModel::Reset()
|
||||
{
|
||||
items.clear();
|
||||
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
for (int i = 0; i < main->extraBrowserDocks.size(); i++) {
|
||||
Item item;
|
||||
item.prevIdx = i;
|
||||
item.title = main->extraBrowserDockNames[i];
|
||||
item.url = main->extraBrowserDockTargets[i];
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtraBrowsersModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
int count = items.size() + 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
int ExtraBrowsersModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return (int)Column::Count;
|
||||
}
|
||||
|
||||
QVariant ExtraBrowsersModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
int column = index.column();
|
||||
int idx = index.row();
|
||||
int count = items.size();
|
||||
bool validRole = role == Qt::DisplayRole || role == Qt::AccessibleTextRole;
|
||||
|
||||
if (!validRole)
|
||||
return QVariant();
|
||||
|
||||
if (idx >= 0 && idx < count) {
|
||||
switch (column) {
|
||||
case (int)Column::Title:
|
||||
return items[idx].title;
|
||||
case (int)Column::Url:
|
||||
return items[idx].url;
|
||||
}
|
||||
} else if (idx == count) {
|
||||
switch (column) {
|
||||
case (int)Column::Title:
|
||||
return newTitle;
|
||||
case (int)Column::Url:
|
||||
return newURL;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ExtraBrowsersModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
bool validRole = role == Qt::DisplayRole || role == Qt::AccessibleTextRole;
|
||||
|
||||
if (validRole && orientation == Qt::Orientation::Horizontal) {
|
||||
switch (section) {
|
||||
case (int)Column::Title:
|
||||
return QTStr("ExtraBrowsers.DockName");
|
||||
case (int)Column::Url:
|
||||
return QStringLiteral("URL");
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags ExtraBrowsersModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||
|
||||
if (index.column() != (int)Column::Delete)
|
||||
flags |= Qt::ItemIsEditable;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
class DelButton : public QPushButton {
|
||||
public:
|
||||
inline DelButton(QModelIndex index_) : QPushButton(), index(index_) {}
|
||||
|
||||
QPersistentModelIndex index;
|
||||
};
|
||||
|
||||
class EditWidget : public QLineEdit {
|
||||
public:
|
||||
inline EditWidget(QWidget *parent, QModelIndex index_) : QLineEdit(parent), index(index_) {}
|
||||
|
||||
QPersistentModelIndex index;
|
||||
};
|
||||
|
||||
void ExtraBrowsersModel::AddDeleteButton(int idx)
|
||||
{
|
||||
QTableView *widget = reinterpret_cast<QTableView *>(parent());
|
||||
|
||||
QModelIndex index = createIndex(idx, (int)Column::Delete, nullptr);
|
||||
|
||||
QPushButton *del = new DelButton(index);
|
||||
del->setProperty("class", "icon-trash");
|
||||
del->setObjectName("extraPanelDelete");
|
||||
del->setMinimumSize(QSize(20, 20));
|
||||
connect(del, &QPushButton::clicked, this, &ExtraBrowsersModel::DeleteItem);
|
||||
|
||||
widget->setIndexWidget(index, del);
|
||||
widget->setRowHeight(idx, 20);
|
||||
widget->setColumnWidth(idx, 20);
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::CheckToAdd()
|
||||
{
|
||||
if (newTitle.isEmpty() || newURL.isEmpty())
|
||||
return;
|
||||
|
||||
int idx = items.size() + 1;
|
||||
beginInsertRows(QModelIndex(), idx, idx);
|
||||
|
||||
Item item;
|
||||
item.prevIdx = -1;
|
||||
item.title = newTitle;
|
||||
item.url = newURL;
|
||||
items.push_back(item);
|
||||
|
||||
newTitle = "";
|
||||
newURL = "";
|
||||
|
||||
endInsertRows();
|
||||
|
||||
AddDeleteButton(idx - 1);
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::UpdateItem(Item &item)
|
||||
{
|
||||
int idx = item.prevIdx;
|
||||
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
BrowserDock *dock = reinterpret_cast<BrowserDock *>(main->extraBrowserDocks[idx].get());
|
||||
dock->setWindowTitle(item.title);
|
||||
dock->setObjectName(item.title + OBJ_NAME_SUFFIX);
|
||||
|
||||
if (main->extraBrowserDockNames[idx] != item.title) {
|
||||
main->extraBrowserDockNames[idx] = item.title;
|
||||
dock->toggleViewAction()->setText(item.title);
|
||||
dock->setTitle(item.title);
|
||||
}
|
||||
|
||||
if (main->extraBrowserDockTargets[idx] != item.url) {
|
||||
dock->cefWidget->setURL(QT_TO_UTF8(item.url));
|
||||
main->extraBrowserDockTargets[idx] = item.url;
|
||||
}
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::DeleteItem()
|
||||
{
|
||||
QTableView *widget = reinterpret_cast<QTableView *>(parent());
|
||||
|
||||
DelButton *del = reinterpret_cast<DelButton *>(sender());
|
||||
int row = del->index.row();
|
||||
|
||||
/* there's some sort of internal bug in Qt and deleting certain index
|
||||
* widgets or "editors" that can cause a crash inside Qt if the widget
|
||||
* is not manually removed, at least on 5.7 */
|
||||
widget->setIndexWidget(del->index, nullptr);
|
||||
del->deleteLater();
|
||||
|
||||
/* --------- */
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
|
||||
int prevIdx = items[row].prevIdx;
|
||||
items.removeAt(row);
|
||||
|
||||
if (prevIdx != -1) {
|
||||
int i = 0;
|
||||
for (; i < deleted.size() && deleted[i] < prevIdx; i++)
|
||||
;
|
||||
deleted.insert(i, prevIdx);
|
||||
}
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::Apply()
|
||||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
for (Item &item : items) {
|
||||
if (item.prevIdx != -1) {
|
||||
UpdateItem(item);
|
||||
} else {
|
||||
QString uuid = QUuid::createUuid().toString();
|
||||
uuid.replace(QRegularExpression("[{}-]"), "");
|
||||
main->AddExtraBrowserDock(item.title, item.url, uuid, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = deleted.size() - 1; i >= 0; i--) {
|
||||
int idx = deleted[i];
|
||||
main->extraBrowserDockTargets.removeAt(idx);
|
||||
main->extraBrowserDockNames.removeAt(idx);
|
||||
main->extraBrowserDocks.removeAt(idx);
|
||||
}
|
||||
|
||||
if (main->extraBrowserDocks.empty())
|
||||
main->extraBrowserMenuDocksSeparator.clear();
|
||||
|
||||
deleted.clear();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::TabSelection(bool forward)
|
||||
{
|
||||
QListView *widget = reinterpret_cast<QListView *>(parent());
|
||||
QItemSelectionModel *selModel = widget->selectionModel();
|
||||
|
||||
QModelIndex sel = selModel->currentIndex();
|
||||
int row = sel.row();
|
||||
int col = sel.column();
|
||||
|
||||
switch (sel.column()) {
|
||||
case (int)Column::Title:
|
||||
if (!forward) {
|
||||
if (row == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
row -= 1;
|
||||
}
|
||||
|
||||
col += 1;
|
||||
break;
|
||||
|
||||
case (int)Column::Url:
|
||||
if (forward) {
|
||||
if (row == items.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
row += 1;
|
||||
}
|
||||
|
||||
col -= 1;
|
||||
}
|
||||
|
||||
sel = createIndex(row, col, nullptr);
|
||||
selModel->setCurrentIndex(sel, QItemSelectionModel::Clear);
|
||||
}
|
||||
|
||||
void ExtraBrowsersModel::Init()
|
||||
{
|
||||
for (int i = 0; i < items.count(); i++)
|
||||
AddDeleteButton(i);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
QWidget *ExtraBrowsersDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QLineEdit *text = new EditWidget(parent, index);
|
||||
text->installEventFilter(const_cast<ExtraBrowsersDelegate *>(this));
|
||||
text->setSizePolicy(QSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding,
|
||||
QSizePolicy::ControlType::LineEdit));
|
||||
return text;
|
||||
}
|
||||
|
||||
void ExtraBrowsersDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
QLineEdit *text = reinterpret_cast<QLineEdit *>(editor);
|
||||
text->blockSignals(true);
|
||||
text->setText(index.data().toString());
|
||||
text->blockSignals(false);
|
||||
}
|
||||
|
||||
bool ExtraBrowsersDelegate::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
QLineEdit *edit = qobject_cast<QLineEdit *>(object);
|
||||
if (!edit)
|
||||
return false;
|
||||
|
||||
if (LineEditCanceled(event)) {
|
||||
RevertText(edit);
|
||||
}
|
||||
if (LineEditChanged(event)) {
|
||||
UpdateText(edit);
|
||||
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if (keyEvent->key() == Qt::Key_Tab) {
|
||||
model->TabSelection(true);
|
||||
} else if (keyEvent->key() == Qt::Key_Backtab) {
|
||||
model->TabSelection(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExtraBrowsersDelegate::ValidName(const QString &name) const
|
||||
{
|
||||
for (auto &item : model->items) {
|
||||
if (name.compare(item.title, Qt::CaseInsensitive) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExtraBrowsersDelegate::RevertText(QLineEdit *edit_)
|
||||
{
|
||||
EditWidget *edit = reinterpret_cast<EditWidget *>(edit_);
|
||||
int row = edit->index.row();
|
||||
int col = edit->index.column();
|
||||
bool newItem = (row == model->items.size());
|
||||
|
||||
QString oldText;
|
||||
if (col == (int)Column::Title) {
|
||||
oldText = newItem ? model->newTitle : model->items[row].title;
|
||||
} else {
|
||||
oldText = newItem ? model->newURL : model->items[row].url;
|
||||
}
|
||||
|
||||
edit->setText(oldText);
|
||||
}
|
||||
|
||||
bool ExtraBrowsersDelegate::UpdateText(QLineEdit *edit_)
|
||||
{
|
||||
EditWidget *edit = reinterpret_cast<EditWidget *>(edit_);
|
||||
int row = edit->index.row();
|
||||
int col = edit->index.column();
|
||||
bool newItem = (row == model->items.size());
|
||||
|
||||
QString text = edit->text().trimmed();
|
||||
|
||||
if (!newItem && text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (col == (int)Column::Title) {
|
||||
QString oldText = newItem ? model->newTitle : model->items[row].title;
|
||||
bool same = oldText.compare(text, Qt::CaseInsensitive) == 0;
|
||||
|
||||
if (!same && !ValidName(text)) {
|
||||
edit->setText(oldText);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newItem) {
|
||||
/* if edited existing item, update it*/
|
||||
switch (col) {
|
||||
case (int)Column::Title:
|
||||
model->items[row].title = text;
|
||||
break;
|
||||
case (int)Column::Url:
|
||||
model->items[row].url = text;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* if both new values filled out, create new one */
|
||||
switch (col) {
|
||||
case (int)Column::Title:
|
||||
model->newTitle = text;
|
||||
break;
|
||||
case (int)Column::Url:
|
||||
model->newURL = text;
|
||||
break;
|
||||
}
|
||||
|
||||
model->CheckToAdd();
|
||||
}
|
||||
|
||||
emit commitData(edit);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
OBSExtraBrowsers::OBSExtraBrowsers(QWidget *parent) : QDialog(parent), ui(new Ui::OBSExtraBrowsers)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
model = new ExtraBrowsersModel(ui->table);
|
||||
|
||||
ui->table->setModel(model);
|
||||
ui->table->setItemDelegateForColumn((int)Column::Title, new ExtraBrowsersDelegate(model));
|
||||
ui->table->setItemDelegateForColumn((int)Column::Url, new ExtraBrowsersDelegate(model));
|
||||
ui->table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch);
|
||||
ui->table->horizontalHeader()->setSectionResizeMode((int)Column::Delete, QHeaderView::ResizeMode::Fixed);
|
||||
ui->table->setEditTriggers(QAbstractItemView::EditTrigger::CurrentChanged);
|
||||
}
|
||||
|
||||
OBSExtraBrowsers::~OBSExtraBrowsers() {}
|
||||
|
||||
void OBSExtraBrowsers::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
QDialog::closeEvent(event);
|
||||
model->Apply();
|
||||
}
|
||||
|
||||
void OBSExtraBrowsers::on_apply_clicked()
|
||||
{
|
||||
model->Apply();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
QCef *cef = nullptr;
|
||||
QCefCookieManager *panel_cookies = nullptr;
|
||||
bool cef_js_avail = false;
|
||||
|
||||
#ifdef BROWSER_AVAILABLE
|
||||
void OBSBasic::ClearExtraBrowserDocks()
|
||||
{
|
||||
extraBrowserDockTargets.clear();
|
||||
@@ -560,46 +158,8 @@ void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url, con
|
||||
dock->setVisible(true);
|
||||
}
|
||||
}
|
||||
/******************************************************************************
|
||||
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "OBSBasic.hpp"
|
||||
|
||||
#ifdef BROWSER_AVAILABLE
|
||||
#include <dialogs/OBSExtraBrowsers.hpp>
|
||||
#include <docks/BrowserDock.hpp>
|
||||
|
||||
#include <json11.hpp>
|
||||
#include <qt-wrappers.hpp>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
using namespace json11;
|
||||
#endif
|
||||
|
||||
#include <random>
|
||||
|
||||
struct QCef;
|
||||
struct QCefCookieManager;
|
||||
|
||||
QCef *cef = nullptr;
|
||||
QCefCookieManager *panel_cookies = nullptr;
|
||||
bool cef_js_avail = false;
|
||||
|
||||
static std::string GenId()
|
||||
{
|
||||
std::random_device rd;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user