add load script from URL support

This commit is contained in:
ZappoMan 2014-03-25 00:17:19 -07:00
parent a613da8032
commit c34b64e296
6 changed files with 112 additions and 30 deletions

View file

@ -28,6 +28,7 @@
#include <QDesktopWidget>
#include <QCheckBox>
#include <QImage>
#include <QInputDialog>
#include <QKeyEvent>
#include <QMainWindow>
#include <QMenuBar>
@ -3508,35 +3509,17 @@ void Application::cleanupScriptMenuItem(const QString& scriptMenuName) {
Menu::getInstance()->removeAction(Menu::getInstance()->getActiveScriptsMenu(), scriptMenuName);
}
void Application::loadScript(const QString& fileNameString) {
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
const char* fileName = fileNameAscii.data();
std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate);
if(!file.is_open()) {
qDebug("Error loading file %s", fileName);
return;
}
qDebug("Loading file %s...", fileName);
_activeScripts.append(fileNameString);
// get file length....
unsigned long fileLength = file.tellg();
file.seekg( 0, std::ios::beg );
// read the entire file into a buffer, WHAT!? Why not.
char* entireFile = new char[fileLength+1];
file.read((char*)entireFile, fileLength);
file.close();
entireFile[fileLength] = 0;// null terminate
QString script(entireFile);
delete[] entireFile;
void Application::loadScript(const QString& scriptName) {
// start the script on a new thread...
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), wantMenuItems, &_controllerScriptingInterface);
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, &_controllerScriptingInterface);
if (!scriptEngine->hasScript()) {
qDebug() << "Application::loadScript(), script failed to load...";
return;
}
_activeScripts.append(scriptName);
// add a stop menu item
Menu::getInstance()->addActionToQMenuAndActionHash(Menu::getInstance()->getActiveScriptsMenu(),
@ -3599,6 +3582,31 @@ void Application::loadDialog() {
loadScript(fileNameString);
}
void Application::loadScriptURLDialog() {
QInputDialog scriptURLDialog(Application::getInstance()->getWindow());
scriptURLDialog.setWindowTitle("Open and Run Script URL");
scriptURLDialog.setLabelText("Script:");
scriptURLDialog.setWindowFlags(Qt::Sheet);
const float DIALOG_RATIO_OF_WINDOW = 0.30f;
scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
scriptURLDialog.size().height());
int dialogReturn = scriptURLDialog.exec();
QString newScript;
if (dialogReturn == QDialog::Accepted) {
if (scriptURLDialog.textValue().size() > 0) {
// the user input a new hostname, use that
newScript = scriptURLDialog.textValue();
}
loadScript(newScript);
}
sendFakeEnterEvent();
}
void Application::toggleLogDialog() {
if (! _logDialog) {
_logDialog = new LogDialog(_glWidget, getLogger());

View file

@ -254,6 +254,7 @@ public slots:
void setRenderVoxels(bool renderVoxels);
void doKillLocalVoxels();
void loadDialog();
void loadScriptURLDialog();
void toggleLogDialog();
void initAvatarAndViewFrustum();
void stopAllScripts();

View file

@ -107,6 +107,8 @@ Menu::Menu() :
addDisabledActionAndSeparator(fileMenu, "Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts()));
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");

View file

@ -272,7 +272,8 @@ namespace MenuOption {
const QString OffAxisProjection = "Off-Axis Projection";
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
const QString TurnWithHead = "Turn using Head";
const QString LoadScript = "Open and Run Script...";
const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL...";
const QString Oscilloscope = "Audio Oscilloscope";
const QString Pair = "Pair";
const QString Particles = "Particles";
@ -304,4 +305,6 @@ namespace MenuOption {
const QString VoxelTextures = "Voxel Textures";
}
void sendFakeEnterEvent();
#endif /* defined(__hifi__Menu__) */

View file

@ -64,13 +64,10 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co
_quatLibrary(),
_vec3Library()
{
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
const char* scriptMenuName = fileNameAscii.data();
// some clients will use these menu features
if (!fileNameString.isEmpty()) {
_scriptMenuName = "Stop ";
_scriptMenuName.append(scriptMenuName);
_scriptMenuName.append(qPrintable(fileNameString));
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
} else {
_scriptMenuName = "Stop Script ";
@ -79,6 +76,72 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co
_scriptNumber++;
}
ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
_scriptContents(),
_isFinished(false),
_isRunning(false),
_isInitialized(false),
_engine(),
_isAvatar(false),
_avatarIdentityTimer(NULL),
_avatarBillboardTimer(NULL),
_timerFunctionMap(),
_isListeningToAudioStream(false),
_avatarSound(NULL),
_numAvatarSoundSentBytes(0),
_controllerScriptingInterface(controllerScriptingInterface),
_avatarData(NULL),
_wantMenuItems(wantMenuItems),
_scriptMenuName(),
_fileNameString(),
_quatLibrary(),
_vec3Library()
{
QString scriptURLString = scriptURL.toString();
_fileNameString = scriptURLString;
// some clients will use these menu features
if (!scriptURLString.isEmpty()) {
_scriptMenuName = "Stop ";
_scriptMenuName.append(qPrintable(scriptURLString));
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
} else {
_scriptMenuName = "Stop Script ";
_scriptMenuName.append(_scriptNumber);
}
_scriptNumber++;
QUrl url(scriptURL);
// if the scheme is empty, maybe they typed in a file, let's try
if (url.scheme().isEmpty()) {
url = QUrl::fromLocalFile(scriptURLString);
}
// ok, let's see if it's valid... and if so, load it
if (url.isValid()) {
if (url.scheme() == "file") {
QString fileName = url.toLocalFile();
QFile scriptFile(fileName);
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
qDebug() << "Loading file:" << fileName;
QTextStream in(&scriptFile);
_scriptContents = in.readAll();
} else {
qDebug() << "ERROR Loading file:" << fileName;
}
} else {
QNetworkAccessManager* networkManager = new QNetworkAccessManager(this);
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
qDebug() << "Downloading included script at" << url;
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
_scriptContents = reply->readAll();
}
}
}
void ScriptEngine::setIsAvatar(bool isAvatar) {
_isAvatar = isAvatar;

View file

@ -33,6 +33,9 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10
class ScriptEngine : public QObject {
Q_OBJECT
public:
ScriptEngine(const QUrl& scriptURL, bool wantMenuItems = false,
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
@ -68,6 +71,8 @@ public:
void timerFired();
bool hasScript() const { return !_scriptContents.isEmpty(); }
public slots:
void stop();