//// RunningScriptsWidget.cpp// interface/src/ui//// Created by Mohammed Nafees on 03/28/2014.// Updated by Ryan Huffman on 05/13/2014.// Copyright 2014 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "ui_runningScriptsWidget.h"#include "RunningScriptsWidget.h" #include <QAbstractProxyModel>#include <QFileInfo>#include <QKeyEvent>#include <QPainter>#include <QScreen>#include <QTableWidgetItem>#include <QWindow> #include <PathUtils.h> #include "Application.h"#include "Menu.h"#include "ScriptsModel.h"#include "UIUtil.h" RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : QWidget(parent, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint), ui(new Ui::RunningScriptsWidget), _signalMapper(this), _scriptsModelFilter(this), _scriptsModel(this) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, false); ui->filterLineEdit->installEventFilter(this); connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset, this, &RunningScriptsWidget::selectFirstInList); // FIXME: menu isn't prepared at this point. //QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText); //ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts."); _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); _scriptsModelFilter.setDynamicSortFilter(true); ui->scriptTreeView->setModel(&_scriptsModelFilter); connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); connect(ui->reloadAllButton, &QPushButton::clicked, Application::getInstance(), &Application::reloadAllScripts); connect(ui->stopAllButton, &QPushButton::clicked, this, &RunningScriptsWidget::allScriptsStopped); connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, Application::getInstance(), &Application::loadDialog); connect(ui->loadScriptFromURLButton, &QPushButton::clicked, Application::getInstance(), &Application::loadScriptURLDialog); connect(&_signalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&))); UIUtil::scaleWidgetFontSizes(this);} RunningScriptsWidget::~RunningScriptsWidget() { delete ui; _scriptsModel.deleteLater();} void RunningScriptsWidget::updateFileFilter(const QString& filter) { QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive); _scriptsModelFilter.setFilterRegExp(regex); selectFirstInList();} void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) { QVariant scriptFile = _scriptsModelFilter.data(index, ScriptsModel::ScriptPath); Application::getInstance()->loadScript(scriptFile.toString());} void RunningScriptsWidget::loadSelectedScript() { QModelIndex selectedIndex = ui->scriptTreeView->currentIndex(); if (selectedIndex.isValid()) { loadScriptFromList(selectedIndex); }} void RunningScriptsWidget::setRunningScripts(const QStringList& list) { setUpdatesEnabled(false); QLayoutItem* widget; while ((widget = ui->scriptListWidget->layout()->takeAt(0)) != NULL) { delete widget->widget(); delete widget; } QHash<QString, int> hash; const int CLOSE_ICON_HEIGHT = 12; for (int i = 0; i < list.size(); i++) { if (!hash.contains(list.at(i))) { hash.insert(list.at(i), 1); } QWidget* row = new QWidget(ui->scriptListWidget); row->setFont(ui->scriptListWidget->font()); row->setLayout(new QHBoxLayout(row)); QUrl url = QUrl(list.at(i)); QLabel* name = new QLabel(url.fileName(), row); if (hash.find(list.at(i)).value() != 1) { name->setText(name->text() + "(" + QString::number(hash.find(list.at(i)).value()) + ")"); } ++hash[list.at(i)]; QPushButton* closeButton = new QPushButton(row); closeButton->setFlat(true); closeButton->setIcon( QIcon(QPixmap(PathUtils::resourcesPath() + "images/kill-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT))); closeButton->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred)); closeButton->setStyleSheet("border: 0;"); closeButton->setCursor(Qt::PointingHandCursor); connect(closeButton, SIGNAL(clicked()), &_signalMapper, SLOT(map())); _signalMapper.setMapping(closeButton, url.toString()); row->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); row->layout()->setContentsMargins(4, 4, 4, 4); row->layout()->setSpacing(0); row->layout()->addWidget(name); row->layout()->addWidget(closeButton); row->setToolTip(url.toString()); QFrame* line = new QFrame(row); line->setFrameShape(QFrame::HLine); line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;"); ui->scriptListWidget->layout()->addWidget(row); ui->scriptListWidget->layout()->addWidget(line); } ui->noRunningScriptsLabel->setVisible(list.isEmpty()); ui->reloadAllButton->setVisible(!list.isEmpty()); ui->stopAllButton->setVisible(!list.isEmpty()); ui->scriptListWidget->updateGeometry(); setUpdatesEnabled(true); Application::processEvents(); repaint();} void RunningScriptsWidget::showEvent(QShowEvent* event) { if (!event->spontaneous()) { ui->filterLineEdit->setFocus(); } QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); int topMargin = titleBarHeight; setGeometry(parentGeometry.topLeft().x(), parentGeometry.topLeft().y() + topMargin, size().width(), parentWidget()->height() - topMargin); QWidget::showEvent(event);} void RunningScriptsWidget::selectFirstInList() { if (_scriptsModelFilter.rowCount() > 0) { ui->scriptTreeView->setCurrentIndex(_scriptsModelFilter.index(0, 0)); }} bool RunningScriptsWidget::eventFilter(QObject* sender, QEvent* event) { if (sender == ui->filterLineEdit) { if (event->type() != QEvent::KeyPress) { return false; } QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { QModelIndex selectedIndex = ui->scriptTreeView->currentIndex(); if (selectedIndex.isValid()) { loadScriptFromList(selectedIndex); } event->accept(); return true; } return false; } return QWidget::eventFilter(sender, event);} void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) { if (keyEvent->key() == Qt::Key_Escape) { return; } else { QWidget::keyPressEvent(keyEvent); }} void RunningScriptsWidget::scriptStopped(const QString& scriptName) {} void RunningScriptsWidget::allScriptsStopped() { Application::getInstance()->stopAllScripts();} QVariantList RunningScriptsWidget::getRunning() { const int WINDOWS_DRIVE_LETTER_SIZE = 1; QVariantList result; QStringList runningScripts = Application::getInstance()->getRunningScripts(); for (int i = 0; i < runningScripts.size(); i++) { QUrl runningScriptURL = QUrl(runningScripts.at(i)); if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); } QVariantMap resultNode; resultNode.insert("name", runningScriptURL.fileName()); resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); resultNode.insert("local", runningScriptURL.isLocalFile()); result.append(resultNode); } return result;} QVariantList RunningScriptsWidget::getPublic() { return getPublicChildNodes(NULL);} QVariantList RunningScriptsWidget::getPublicChildNodes(TreeNodeFolder* parent) { QVariantList result; QList<TreeNodeBase*> treeNodes = Application::getInstance()->getRunningScriptsWidget()->getScriptsModel() ->getFolderNodes(parent); for (int i = 0; i < treeNodes.size(); i++) { TreeNodeBase* node = treeNodes.at(i); if (node->getType() == TREE_NODE_TYPE_FOLDER) { TreeNodeFolder* folder = static_cast<TreeNodeFolder*>(node); QVariantMap resultNode; resultNode.insert("name", node->getName()); resultNode.insert("type", "folder"); resultNode.insert("children", getPublicChildNodes(folder)); result.append(resultNode); continue; } TreeNodeScript* script = static_cast<TreeNodeScript*>(node); if (script->getOrigin() == ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { continue; } QVariantMap resultNode; resultNode.insert("name", node->getName()); resultNode.insert("type", "script"); resultNode.insert("url", script->getFullPath()); result.append(resultNode); } return result;} QVariantList RunningScriptsWidget::getLocal() { QVariantList result; QList<TreeNodeBase*> treeNodes = Application::getInstance()->getRunningScriptsWidget()->getScriptsModel() ->getFolderNodes(NULL); for (int i = 0; i < treeNodes.size(); i++) { TreeNodeBase* node = treeNodes.at(i); if (node->getType() != TREE_NODE_TYPE_SCRIPT) { continue; } TreeNodeScript* script = static_cast<TreeNodeScript*>(node); if (script->getOrigin() != ScriptOrigin::SCRIPT_ORIGIN_LOCAL) { continue; } QVariantMap resultNode; resultNode.insert("name", node->getName()); resultNode.insert("path", script->getFullPath()); result.append(resultNode); } return result;}
//
// RunningScriptsWidget.cpp
// interface/src/ui
//
// Created by Mohammed Nafees on 03/28/2014.
// Updated by Ryan Huffman on 05/13/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ui_runningScriptsWidget.h"
#include "RunningScriptsWidget.h"
#include <QAbstractProxyModel>
#include <QFileInfo>
#include <QKeyEvent>
#include <QPainter>
#include <QScreen>
#include <QTableWidgetItem>
#include <QWindow>
#include <PathUtils.h>
#include "Application.h"
#include "Menu.h"
#include "ScriptsModel.h"
#include "UIUtil.h"
RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
QWidget(parent, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint |
Qt::WindowCloseButtonHint),
ui(new Ui::RunningScriptsWidget),
_signalMapper(this),
_scriptsModelFilter(this),
_scriptsModel(this) {
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, false);
ui->filterLineEdit->installEventFilter(this);
connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset,
this, &RunningScriptsWidget::selectFirstInList);
// FIXME: menu isn't prepared at this point.
//QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText);
//ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts.");
_scriptsModelFilter.setSourceModel(&_scriptsModel);
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
_scriptsModelFilter.setDynamicSortFilter(true);
ui->scriptTreeView->setModel(&_scriptsModelFilter);
connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter);
connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList);
connect(ui->reloadAllButton, &QPushButton::clicked,
Application::getInstance(), &Application::reloadAllScripts);
connect(ui->stopAllButton, &QPushButton::clicked,
this, &RunningScriptsWidget::allScriptsStopped);
connect(ui->loadScriptFromDiskButton, &QPushButton::clicked,
Application::getInstance(), &Application::loadDialog);
connect(ui->loadScriptFromURLButton, &QPushButton::clicked,
Application::getInstance(), &Application::loadScriptURLDialog);
connect(&_signalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&)));
UIUtil::scaleWidgetFontSizes(this);
}
RunningScriptsWidget::~RunningScriptsWidget() {
delete ui;
_scriptsModel.deleteLater();
}
void RunningScriptsWidget::updateFileFilter(const QString& filter) {
QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive);
_scriptsModelFilter.setFilterRegExp(regex);
selectFirstInList();
}
void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) {
QVariant scriptFile = _scriptsModelFilter.data(index, ScriptsModel::ScriptPath);
Application::getInstance()->loadScript(scriptFile.toString());
}
void RunningScriptsWidget::loadSelectedScript() {
QModelIndex selectedIndex = ui->scriptTreeView->currentIndex();
if (selectedIndex.isValid()) {
loadScriptFromList(selectedIndex);
}
}
void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
setUpdatesEnabled(false);
QLayoutItem* widget;
while ((widget = ui->scriptListWidget->layout()->takeAt(0)) != NULL) {
delete widget->widget();
delete widget;
}
QHash<QString, int> hash;
const int CLOSE_ICON_HEIGHT = 12;
for (int i = 0; i < list.size(); i++) {
if (!hash.contains(list.at(i))) {
hash.insert(list.at(i), 1);
}
QWidget* row = new QWidget(ui->scriptListWidget);
row->setFont(ui->scriptListWidget->font());
row->setLayout(new QHBoxLayout(row));
QUrl url = QUrl(list.at(i));
QLabel* name = new QLabel(url.fileName(), row);
if (hash.find(list.at(i)).value() != 1) {
name->setText(name->text() + "(" + QString::number(hash.find(list.at(i)).value()) + ")");
}
++hash[list.at(i)];
QPushButton* closeButton = new QPushButton(row);
closeButton->setFlat(true);
closeButton->setIcon(
QIcon(QPixmap(PathUtils::resourcesPath() + "images/kill-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT)));
closeButton->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
closeButton->setStyleSheet("border: 0;");
closeButton->setCursor(Qt::PointingHandCursor);
connect(closeButton, SIGNAL(clicked()), &_signalMapper, SLOT(map()));
_signalMapper.setMapping(closeButton, url.toString());
row->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
row->layout()->setContentsMargins(4, 4, 4, 4);
row->layout()->setSpacing(0);
row->layout()->addWidget(name);
row->layout()->addWidget(closeButton);
row->setToolTip(url.toString());
QFrame* line = new QFrame(row);
line->setFrameShape(QFrame::HLine);
line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;");
ui->scriptListWidget->layout()->addWidget(row);
ui->scriptListWidget->layout()->addWidget(line);
}
ui->noRunningScriptsLabel->setVisible(list.isEmpty());
ui->reloadAllButton->setVisible(!list.isEmpty());
ui->stopAllButton->setVisible(!list.isEmpty());
ui->scriptListWidget->updateGeometry();
setUpdatesEnabled(true);
Application::processEvents();
repaint();
}
void RunningScriptsWidget::showEvent(QShowEvent* event) {
if (!event->spontaneous()) {
ui->filterLineEdit->setFocus();
}
QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry();
int titleBarHeight = UIUtil::getWindowTitleBarHeight(this);
int topMargin = titleBarHeight;
setGeometry(parentGeometry.topLeft().x(), parentGeometry.topLeft().y() + topMargin,
size().width(), parentWidget()->height() - topMargin);
QWidget::showEvent(event);
}
void RunningScriptsWidget::selectFirstInList() {
if (_scriptsModelFilter.rowCount() > 0) {
ui->scriptTreeView->setCurrentIndex(_scriptsModelFilter.index(0, 0));
}
}
bool RunningScriptsWidget::eventFilter(QObject* sender, QEvent* event) {
if (sender == ui->filterLineEdit) {
if (event->type() != QEvent::KeyPress) {
return false;
}
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
QModelIndex selectedIndex = ui->scriptTreeView->currentIndex();
if (selectedIndex.isValid()) {
loadScriptFromList(selectedIndex);
}
event->accept();
return true;
}
return false;
}
return QWidget::eventFilter(sender, event);
}
void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) {
if (keyEvent->key() == Qt::Key_Escape) {
return;
} else {
QWidget::keyPressEvent(keyEvent);
}
}
void RunningScriptsWidget::scriptStopped(const QString& scriptName) {
}
void RunningScriptsWidget::allScriptsStopped() {
Application::getInstance()->stopAllScripts();
}
QVariantList RunningScriptsWidget::getRunning() {
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
QVariantList result;
QStringList runningScripts = Application::getInstance()->getRunningScripts();
for (int i = 0; i < runningScripts.size(); i++) {
QUrl runningScriptURL = QUrl(runningScripts.at(i));
if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
}
QVariantMap resultNode;
resultNode.insert("name", runningScriptURL.fileName());
resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
resultNode.insert("local", runningScriptURL.isLocalFile());
result.append(resultNode);
}
return result;
}
QVariantList RunningScriptsWidget::getPublic() {
return getPublicChildNodes(NULL);
}
QVariantList RunningScriptsWidget::getPublicChildNodes(TreeNodeFolder* parent) {
QVariantList result;
QList<TreeNodeBase*> treeNodes = Application::getInstance()->getRunningScriptsWidget()->getScriptsModel()
->getFolderNodes(parent);
for (int i = 0; i < treeNodes.size(); i++) {
TreeNodeBase* node = treeNodes.at(i);
if (node->getType() == TREE_NODE_TYPE_FOLDER) {
TreeNodeFolder* folder = static_cast<TreeNodeFolder*>(node);
QVariantMap resultNode;
resultNode.insert("name", node->getName());
resultNode.insert("type", "folder");
resultNode.insert("children", getPublicChildNodes(folder));
result.append(resultNode);
continue;
}
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
if (script->getOrigin() == ScriptOrigin::SCRIPT_ORIGIN_LOCAL) {
continue;
}
QVariantMap resultNode;
resultNode.insert("name", node->getName());
resultNode.insert("type", "script");
resultNode.insert("url", script->getFullPath());
result.append(resultNode);
}
return result;
}
QVariantList RunningScriptsWidget::getLocal() {
QVariantList result;
QList<TreeNodeBase*> treeNodes = Application::getInstance()->getRunningScriptsWidget()->getScriptsModel()
->getFolderNodes(NULL);
for (int i = 0; i < treeNodes.size(); i++) {
TreeNodeBase* node = treeNodes.at(i);
if (node->getType() != TREE_NODE_TYPE_SCRIPT) {
continue;
}
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
if (script->getOrigin() != ScriptOrigin::SCRIPT_ORIGIN_LOCAL) {
continue;
}
QVariantMap resultNode;
resultNode.insert("name", node->getName());
resultNode.insert("path", script->getFullPath());
result.append(resultNode);
}
return result;
}