|
@@ -0,0 +1,575 @@
|
|
|
+#include "window-extra-browsers.hpp"
|
|
|
+#include "window-basic-main.hpp"
|
|
|
+#include "qt-wrappers.hpp"
|
|
|
+#include "window-dock.hpp"
|
|
|
+
|
|
|
+#include <QLineEdit>
|
|
|
+#include <QHBoxLayout>
|
|
|
+
|
|
|
+#include <json11.hpp>
|
|
|
+
|
|
|
+#include "ui_OBSExtraBrowsers.h"
|
|
|
+
|
|
|
+#include <browser-panel.hpp>
|
|
|
+extern QCef *cef;
|
|
|
+extern QCefCookieManager *panel_cookies;
|
|
|
+
|
|
|
+using namespace json11;
|
|
|
+
|
|
|
+#define OBJ_NAME_SUFFIX "_extraBrowser"
|
|
|
+
|
|
|
+enum class Column : int {
|
|
|
+ Title,
|
|
|
+ Url,
|
|
|
+ Delete,
|
|
|
+
|
|
|
+ Count,
|
|
|
+};
|
|
|
+
|
|
|
+class ExtraBrowser : public OBSDock {
|
|
|
+public:
|
|
|
+ inline ExtraBrowser() : OBSDock() {}
|
|
|
+
|
|
|
+ QScopedPointer<QCefWidget> cefWidget;
|
|
|
+
|
|
|
+ inline void SetWidget(QCefWidget *widget_)
|
|
|
+ {
|
|
|
+ setWidget(widget_);
|
|
|
+ cefWidget.reset(widget_);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------------- */
|
|
|
+
|
|
|
+void ExtraBrowsersModel::Reset()
|
|
|
+{
|
|
|
+ items.clear();
|
|
|
+
|
|
|
+ OBSBasic *main = OBSBasic::Get();
|
|
|
+
|
|
|
+ for (int i = 0; i < main->extraBrowserDocks.size(); i++) {
|
|
|
+ ExtraBrowser *dock = reinterpret_cast<ExtraBrowser *>(
|
|
|
+ main->extraBrowserDocks[i].data());
|
|
|
+
|
|
|
+ Item item;
|
|
|
+ item.prevIdx = i;
|
|
|
+ item.title = dock->windowTitle();
|
|
|
+ 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());
|
|
|
+
|
|
|
+ QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding,
|
|
|
+ QSizePolicy::PushButton);
|
|
|
+ policy.setWidthForHeight(true);
|
|
|
+
|
|
|
+ QModelIndex index = createIndex(idx, (int)Column::Delete, nullptr);
|
|
|
+
|
|
|
+ QPushButton *del = new DelButton(index);
|
|
|
+ del->setProperty("themeID", "trashIcon");
|
|
|
+ del->setSizePolicy(policy);
|
|
|
+ del->setFlat(true);
|
|
|
+ connect(del, &QPushButton::clicked, this,
|
|
|
+ &ExtraBrowsersModel::DeleteItem);
|
|
|
+
|
|
|
+ widget->setIndexWidget(index, del);
|
|
|
+}
|
|
|
+
|
|
|
+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();
|
|
|
+ ExtraBrowser *dock = reinterpret_cast<ExtraBrowser *>(
|
|
|
+ main->extraBrowserDocks[idx].data());
|
|
|
+ dock->setWindowTitle(item.title);
|
|
|
+ dock->setObjectName(item.title + OBJ_NAME_SUFFIX);
|
|
|
+ main->extraBrowserDockActions[idx]->setText(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 {
|
|
|
+ main->AddExtraBrowserDock(item.title, item.url, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = deleted.size() - 1; i >= 0; i--) {
|
|
|
+ int idx = deleted[i];
|
|
|
+ main->extraBrowserDockActions.removeAt(idx);
|
|
|
+ main->extraBrowserDockTargets.removeAt(idx);
|
|
|
+ main->extraBrowserDocks.removeAt(idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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()
|
|
|
+{
|
|
|
+ delete ui;
|
|
|
+}
|
|
|
+
|
|
|
+void OBSExtraBrowsers::closeEvent(QCloseEvent *event)
|
|
|
+{
|
|
|
+ QDialog::closeEvent(event);
|
|
|
+ model->Apply();
|
|
|
+}
|
|
|
+
|
|
|
+void OBSExtraBrowsers::on_apply_clicked()
|
|
|
+{
|
|
|
+ model->Apply();
|
|
|
+}
|
|
|
+
|
|
|
+/* ------------------------------------------------------------------------- */
|
|
|
+
|
|
|
+void OBSBasic::ClearExtraBrowserDocks()
|
|
|
+{
|
|
|
+ extraBrowserDockTargets.clear();
|
|
|
+ extraBrowserDockActions.clear();
|
|
|
+ extraBrowserDocks.clear();
|
|
|
+}
|
|
|
+
|
|
|
+void OBSBasic::LoadExtraBrowserDocks()
|
|
|
+{
|
|
|
+ const char *jsonStr = config_get_string(
|
|
|
+ App()->GlobalConfig(), "BasicWindow", "ExtraBrowserDocks");
|
|
|
+
|
|
|
+ std::string err;
|
|
|
+ Json json = Json::parse(jsonStr, err);
|
|
|
+ if (!err.empty())
|
|
|
+ return;
|
|
|
+
|
|
|
+ Json::array array = json.array_items();
|
|
|
+ for (Json &item : array) {
|
|
|
+ std::string title = item["title"].string_value();
|
|
|
+ std::string url = item["url"].string_value();
|
|
|
+
|
|
|
+ AddExtraBrowserDock(title.c_str(), url.c_str(), false);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void OBSBasic::SaveExtraBrowserDocks()
|
|
|
+{
|
|
|
+ Json::array array;
|
|
|
+ for (int i = 0; i < extraBrowserDocks.size(); i++) {
|
|
|
+ QAction *action = extraBrowserDockActions[i].data();
|
|
|
+ QString url = extraBrowserDockTargets[i];
|
|
|
+ Json::object obj{
|
|
|
+ {"title", QT_TO_UTF8(action->text())},
|
|
|
+ {"url", QT_TO_UTF8(url)},
|
|
|
+ };
|
|
|
+ array.push_back(obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string output = Json(array).dump();
|
|
|
+ config_set_string(App()->GlobalConfig(), "BasicWindow",
|
|
|
+ "ExtraBrowserDocks", output.c_str());
|
|
|
+}
|
|
|
+
|
|
|
+void OBSBasic::ManageExtraBrowserDocks()
|
|
|
+{
|
|
|
+ if (!extraBrowsers.isNull()) {
|
|
|
+ extraBrowsers->show();
|
|
|
+ extraBrowsers->raise();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ extraBrowsers = new OBSExtraBrowsers(this);
|
|
|
+ extraBrowsers->show();
|
|
|
+}
|
|
|
+
|
|
|
+void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url,
|
|
|
+ bool firstCreate)
|
|
|
+{
|
|
|
+ static int panel_version = -1;
|
|
|
+ if (panel_version == -1) {
|
|
|
+ panel_version = obs_browser_qcef_version();
|
|
|
+ }
|
|
|
+
|
|
|
+ ExtraBrowser *dock = new ExtraBrowser();
|
|
|
+ dock->setObjectName(title + OBJ_NAME_SUFFIX);
|
|
|
+ dock->resize(460, 600);
|
|
|
+ dock->setMinimumSize(150, 150);
|
|
|
+ dock->setWindowTitle(title);
|
|
|
+ dock->setAllowedAreas(Qt::AllDockWidgetAreas);
|
|
|
+
|
|
|
+ QCefWidget *browser =
|
|
|
+ cef->create_widget(nullptr, QT_TO_UTF8(url), nullptr);
|
|
|
+ if (browser && panel_version >= 1)
|
|
|
+ browser->allowAllPopups(true);
|
|
|
+
|
|
|
+ dock->SetWidget(browser);
|
|
|
+
|
|
|
+ addDockWidget(Qt::RightDockWidgetArea, dock);
|
|
|
+
|
|
|
+ if (firstCreate) {
|
|
|
+ dock->setFloating(true);
|
|
|
+
|
|
|
+ QPoint curPos = pos();
|
|
|
+ QSize wSizeD2 = size() / 2;
|
|
|
+ QSize dSizeD2 = dock->size() / 2;
|
|
|
+
|
|
|
+ curPos.setX(curPos.x() + wSizeD2.width() - dSizeD2.width());
|
|
|
+ curPos.setY(curPos.y() + wSizeD2.height() - dSizeD2.height());
|
|
|
+
|
|
|
+ dock->move(curPos);
|
|
|
+ dock->setVisible(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ extraBrowserDocks.push_back(QSharedPointer<QDockWidget>(dock));
|
|
|
+ extraBrowserDockActions.push_back(
|
|
|
+ QSharedPointer<QAction>(AddDockWidget(dock)));
|
|
|
+ extraBrowserDockTargets.push_back(url);
|
|
|
+}
|