<commit_before>
#include <gloperate-qt/viewer/Viewer.h>

#include <cassert>

#include <reflectionzeug/Object.h>

#include <gloperate/ext-includes-begin.h>

#include <QDockWidget>
#include <QDebug>
#include <QSettings>

#include <propertyguizeug/PropertyBrowser.h>
#include <widgetzeug/MessageHandler.h>
#include <widgetzeug/MessageStatusWidget.h>
#include <widgetzeug/MessageWidget.h>
#include <widgetzeug/ScriptPromptWidget.h>
#include <widgetzeug/ECMA26251_SyntaxHighlighter.h>
#include <widgetzeug/ECMA26251_Completer.h>

#include "ui_Viewer.h"

#include <gloperate/ext-includes-end.h>

#include <gloperate/resources/ResourceManager.h>
#include <gloperate/plugin/PluginManager.h>
#include <gloperate/plugin/Plugin.h>

#ifdef GLOPERATE_ASSIMP_FOUND
    #include <gloperate-assimp/AssimpMeshLoader.h>
    #include <gloperate-assimp/AssimpSceneLoader.h>
#endif

#include <gloperate-qt/viewer/QtOpenGLWindow.h>
#include <gloperate-qt/viewer/QtTextureLoader.h>
#include <gloperate-qt/viewer/QtTextureStorer.h>
#include <gloperate-qt/viewer/QtKeyEventProvider.h>
#include <gloperate-qt/viewer/QtMouseEventProvider.h>
#include <gloperate-qt/viewer/QtWheelEventProvider.h>
#include <gloperate-qt/viewer/DefaultMapping.h>
#include <gloperate-qt/widgets/ImageExporterWidget.h>
#include <gloperate-qt/scripting/SystemApi.h>
#include <gloperate-qt/scripting/TimerApi.h>
#include <gloperate-qt/scripting/ViewerApi.h>
#include <gloperate-qt/scripting/PluginApi.h>

using namespace widgetzeug;
using namespace gloperate;

#ifdef GLOPERATE_ASSIMP_FOUND
    using namespace gloperate_assimp;
#endif

namespace
{
    const QString SETTINGS_GEOMETRY("Geometry");
    const QString SETTINGS_STATE("State");
}

namespace gloperate_qt
{

Viewer::Viewer(QWidget * parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
, m_ui{new Ui_Viewer}
, m_resourceManager{nullptr}
, m_pluginManager{nullptr}
, m_canvas{nullptr}
, m_painter{nullptr}
, m_mapping{nullptr}
, m_messagesStatus{new MessageStatusWidget()}
, m_messagesLog{new MessageWidget()}
, m_scriptPrompt{new ScriptPromptWidget()}
, m_messagLogDockWidget{nullptr}
, m_scriptPromptDockWidget{nullptr}
, m_propertyDockWidget{nullptr}
, m_systemApi{nullptr}
, m_timerApi{nullptr}
, m_viewerApi{nullptr}
, m_pluginApi{nullptr}
{
    // Initialize resource manager (must be done BEFORE setupCanvas)
    m_resourceManager.reset(new ResourceManager());

    // Add default texture loaders/storers
    m_resourceManager->addLoader(new QtTextureLoader());
    m_resourceManager->addStorer(new QtTextureStorer());

    // Add assimp loaders (if available)
#ifdef GLOPERATE_ASSIMP_FOUND
    m_resourceManager->addLoader(new AssimpMeshLoader());
    m_resourceManager->addLoader(new AssimpSceneLoader());
#endif

    // Setup UI
    m_ui->setupUi(this);
    setupMessageWidgets();
    setupCommandPrompt();
    setupPropertyWidget();
    setupDockArea();
    setupCanvas();

    // Load settings
    QSettings::setDefaultFormat(QSettings::IniFormat);
    QSettings settings;

    // Restore GUI state from settings
    restoreGeometry(settings.value(SETTINGS_GEOMETRY).toByteArray());
    restoreState(settings.value(SETTINGS_STATE).toByteArray());

    // Initialize plugin manager
    m_pluginManager.reset(new PluginManager());
    m_pluginManager->pluginsChanged.connect(this, &Viewer::updatePainterMenu);

    // Add default plugin directories
    m_pluginManager->addPath(QCoreApplication::applicationDirPath().toStdString());
#ifdef NDEBUG
    m_pluginManager->addPath("plugins");
#else
    m_pluginManager->addPath("plugins/debug");
#endif

    // Scan all plugins with name component 'painter'
    m_pluginManager->scan("painter");

    // Setup scripting context
    setupScripting();
}

Viewer::~Viewer()
{
    // Save settings
    QSettings settings;
    settings.setValue(SETTINGS_GEOMETRY, saveGeometry());
    settings.setValue(SETTINGS_STATE, saveState());

    // Disconnect message handlers
    MessageHandler::dettach(*m_messagesLog);
    MessageHandler::dettach(*m_messagesStatus);
}

QtOpenGLWindow * Viewer::canvas() const
{
    return m_canvas.get();
}

void Viewer::loadPainter(const std::string & name)
{
    // Get plugin by name
    Plugin * plugin = m_pluginManager->plugin(name);
    if (!plugin) {
        return;
    }

    // Unload old painter
    if (m_painter.get()) {
        m_scriptContext->unregisterObject(m_painter.get());
    }

    // Create new painter
    m_painter.reset(plugin->createPainter(*m_resourceManager));

    // [TODO] Check for painter context format requirements

    // Setup new painter
    m_canvas->setPainter(m_painter.get());
    m_mapping->setPainter(m_painter.get());
    m_canvas->initialize();

    // Register painter in scripting
    m_scriptContext->registerObject(m_painter.get());

    // Update property browser
    if (m_painter.get())
    {
        QWidget * old = m_propertyDockWidget->widget();
        delete old;

        m_propertyDockWidget->setWidget(new propertyguizeug::PropertyBrowser(m_painter.get()));
        m_propertyDockWidget->show();
    }
    else
    {
        m_propertyDockWidget->hide();
    }

    // Update rendering
    m_canvas->updateGL();
}

const scriptzeug::ScriptContext * Viewer::scriptContext() const
{
    return m_scriptContext.get();
}

scriptzeug::ScriptContext * Viewer::scriptContext()
{
    return m_scriptContext.get();
}

void Viewer::addScriptApi(reflectionzeug::Object * api)
{
    // Connect object to scripting engine
    m_scriptContext->registerObject(api);

    // Register name as extra word for word completion
    widgetzeug::ScriptCompleter * completer = static_cast<widgetzeug::ScriptCompleter *>(m_scriptPrompt->completer());
    assert(completer);
    completer->registerWord(QString::fromStdString(api->name()));
}

void Viewer::setupMessageWidgets()
{
    // Widgets have to be created beforehand
    assert(m_messagesStatus);
    assert(m_messagesLog);

    // Attach message handlers to log widgets
    MessageHandler::attach(*m_messagesStatus);
    MessageHandler::attach(*m_messagesLog);

    // Additionally write log to file
    MessageHandler::printsToFile(QtMsgType::QtWarningMsg);
    MessageHandler::printsToFile(QtMsgType::QtCriticalMsg);
    MessageHandler::printsToFile(QtMsgType::QtFatalMsg);

    // Announce log initialization
    qDebug("Initialize message log.");
    const QString fileLog(QString("Messages are also written to file://%1.").arg(MessageHandler::fileName()));
    qDebug("%s", qPrintable(fileLog));

    // Create dock window for message log
    m_messagLogDockWidget = new QDockWidget(tr("Message Log"));
    m_messagLogDockWidget->setWidget(m_messagesLog.get());
    m_messagLogDockWidget->setObjectName("MessageLogDockWidget");
    addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, m_messagLogDockWidget);
    m_messagesLog->setFrameShape(QFrame::NoFrame);

    // Add item to status bar and connect to window
    statusBar()->addPermanentWidget(m_messagesStatus.get());
    m_messagesStatus->attachWidget(m_messagLogDockWidget);
}

void Viewer::setupCommandPrompt()
{
    // Widgets have to be created beforehand
    assert(m_scriptPrompt);

    // Setup syntax highlighting and auto-completion
    m_scriptPrompt->setSyntaxHighlighter(new ECMA26251SyntaxHighlight);
    m_scriptPrompt->setCompleter(new ECMA26251Completer);

    // Create dock window for scripting console
    m_scriptPromptDockWidget = new QDockWidget(tr("Script Prompt"));
    m_scriptPromptDockWidget->setWidget(m_scriptPrompt.get());
    m_scriptPromptDockWidget->setObjectName("ScriptPromptWidget");
    addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, m_scriptPromptDockWidget);
    m_scriptPrompt->setFrameShape(QFrame::NoFrame);
}

void Viewer::setupPropertyWidget()
{
    // Create dock window for property browser
    m_propertyDockWidget = new QDockWidget("Properties", this);
    m_propertyDockWidget->setObjectName("PropertyDockWidget");
    m_propertyDockWidget->setAllowedAreas(Qt::DockWidgetArea::LeftDockWidgetArea);
    addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, m_propertyDockWidget, Qt::Orientation::Horizontal);
}

void Viewer::setupDockArea()
{
    // Define order of widgets in dock area
    tabifyDockWidget(m_messagLogDockWidget, m_scriptPromptDockWidget);
}

void Viewer::setupCanvas()
{
    // Setup OpenGL context format
    QSurfaceFormat format;
#ifdef __APPLE__
    // Get OpenGL 3.2/4.1 core context
    format.setVersion(3, 2);
#else
    // Get newest available core context
#endif
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setDepthBufferSize(16);

    // Create OpenGL context and window
    m_canvas.reset(new QtOpenGLWindow(*m_resourceManager, format));

    // Create widget container
    setCentralWidget(QWidget::createWindowContainer(m_canvas.get()));
    centralWidget()->setFocusPolicy(Qt::StrongFocus);

    // Setup event provider to rranslate Qt messages into gloperate events
    QtKeyEventProvider * keyProvider = new QtKeyEventProvider();
    keyProvider->setParent(m_canvas.get());
    QtMouseEventProvider * mouseProvider = new QtMouseEventProvider();
    mouseProvider->setParent(m_canvas.get());
    QtWheelEventProvider * wheelProvider = new QtWheelEventProvider();
    wheelProvider->setParent(m_canvas.get());

    m_canvas->installEventFilter(keyProvider);
    m_canvas->installEventFilter(mouseProvider);
    m_canvas->installEventFilter(wheelProvider);

    // Create input mapping for gloperate interaction techniques
    m_mapping.reset(new DefaultMapping(m_canvas.get()));
    m_mapping->addProvider(keyProvider);
    m_mapping->addProvider(mouseProvider);
    m_mapping->addProvider(wheelProvider);
}

void Viewer::setupScripting()
{
    // Widgets have to be created beforehand
    assert(m_scriptPrompt);

    // Create scripting context
    m_scriptContext.reset(new scriptzeug::ScriptContext("javascript"));

    // Register default scripting APIs
    m_systemApi.reset(new SystemApi(this));
    addScriptApi(m_systemApi.get());

    m_timerApi.reset(new TimerApi);
    addScriptApi(m_timerApi.get());

    m_viewerApi.reset(new ViewerApi(this));
    addScriptApi(m_viewerApi.get());

    m_pluginApi.reset(new PluginApi(m_pluginManager.get()));
    addScriptApi(m_pluginApi.get());

    // Connect to input from scripting console
    connect(m_scriptPrompt.get(), &widgetzeug::ScriptPromptWidget::evaluate, [this] (const QString & cmd) {
        // Substitute shortcut commands
        QString command = cmd;
        if (cmd == "help") {
            command = "help()";
        } else if (cmd == "exit" || cmd == "quit") {
            command = "exit()";
        }

        // Execute commands that have been typed on the scripting console
        m_scriptContext->evaluate(command.toStdString());
    });

    // Connect commands that have been loaded by API functions (e.g., system.load)
    m_systemApi->command.connect([this] (const std::string & cmd) {
        // Execute code
        m_scriptContext->evaluate(cmd);
    });

    // Connect script output (system.print)
    m_systemApi->output.connect([this] (const std::string & msg) {
        // Print message onto the scripting console
        m_scriptPrompt->print(QString::fromStdString(msg));
    });

    // Connect keyboard events to scripting api
    m_canvas->installEventFilter(m_systemApi.get());

    // Add global functions
    std::string script =
        "function help() {\n"
        "  system.print('Available commands:');\n"
        "  system.print('  help():     Print this help message');\n"
        "  system.print('  print():    Print the content of a variable');\n"
        "  system.print('  toString(): Convert a variable into a string');\n"
        "  system.print('  exit():     Exit the application');\n"
        "  system.print('');\n"
        "  system.print('APIs:');\n"
        "  system.print('  system: System API (e.g., file io, keyboard handling)');\n"
        "  system.print('  timer:  Timer API');\n"
        "  system.print('  viewer: Viewer main window control');\n"
        "  system.print('  plugin: Plugin management');\n"
        "  system.print('');\n"
        "  system.print('Examples:');\n"
        "  system.print('  print(system);');\n"
        "  system.print('  timer.start(1000, function() { print(\"Hello Scripting World.\"); } );');\n"
        "  system.print('  timer.stopAll();');\n"
        "}\n"
        "\n"
        "function load(filename) {\n"
        "  system.load(filename);\n"
        "}\n"
        "\n"
        "function print(value) {\n"
        "  system.print(value);\n"
        "};\n"
        "\n"
        "function exit() {\n"
        "  system.exit();\n"
        "};\n"
        "\n"
        "function quit() {\n"
        "  system.exit();\n"
        "};\n";
    m_scriptContext->evaluate(script);

    // Register extra words for word completion
    widgetzeug::ScriptCompleter * completer = static_cast<widgetzeug::ScriptCompleter *>(m_scriptPrompt->completer());
    assert(completer);
    completer->registerWords(QStringList() << "help" << "load" << "print" << "exit");
}

void Viewer::updatePainterMenu()
{
    // Clear painter menu
    QMenu * menu = m_ui->painterMenu;
    menu->clear();

    // Add all loaded plugins
    for (auto plugin : m_pluginManager->plugins())
    {
        // Add action
        QAction * action = new QAction(QString::fromStdString(plugin->name()), menu);
        action->setData(QString::fromStdString(plugin->name()));
        connect(action, SIGNAL(toggled(bool)), this, SLOT(onPainterSelected(bool)));
        connect(action, SIGNAL(triggered(bool)), this, SLOT(onPainterSelected(bool)));

        // Add to menu
        menu->addAction(action);
    }
}

void Viewer::on_captureImageAction_triggered()
{
    // Screenshot dialog needs an active painter
    if (m_painter)
    {
        // Show image exporter dialog
        ImageExporterWidget * ie{ new ImageExporterWidget(*m_resourceManager, m_canvas->painter(), m_canvas.get()) };
        ie->setWindowModality(Qt::NonModal);
        ie->show();
    }
}

void Viewer::on_managePluginsAction_triggered()
{
    assert(m_pluginManager);

    // [TODO] Show plugin manager widget
}

void Viewer::onPainterSelected(bool /*checked*/)
{
    // Get selected menu action
    QAction * action = dynamic_cast<QAction*>(QObject::sender());
    Q_ASSERT(action != nullptr);

    // Get painter name
    QString name = action->data().toString();
    loadPainter(name.toStdString());
}

} // namespace gloperate_qt
<commit_msg>Save plugin search paths in configuration for gloperate-viewer<commit_after>
#include <gloperate-qt/viewer/Viewer.h>

#include <cassert>

#include <reflectionzeug/Object.h>

#include <gloperate/ext-includes-begin.h>

#include <QDockWidget>
#include <QDebug>
#include <QSettings>

#include <propertyguizeug/PropertyBrowser.h>
#include <widgetzeug/MessageHandler.h>
#include <widgetzeug/MessageStatusWidget.h>
#include <widgetzeug/MessageWidget.h>
#include <widgetzeug/ScriptPromptWidget.h>
#include <widgetzeug/ECMA26251_SyntaxHighlighter.h>
#include <widgetzeug/ECMA26251_Completer.h>

#include "ui_Viewer.h"

#include <gloperate/ext-includes-end.h>

#include <gloperate/resources/ResourceManager.h>
#include <gloperate/plugin/PluginManager.h>
#include <gloperate/plugin/Plugin.h>

#ifdef GLOPERATE_ASSIMP_FOUND
    #include <gloperate-assimp/AssimpMeshLoader.h>
    #include <gloperate-assimp/AssimpSceneLoader.h>
#endif

#include <gloperate-qt/viewer/QtOpenGLWindow.h>
#include <gloperate-qt/viewer/QtTextureLoader.h>
#include <gloperate-qt/viewer/QtTextureStorer.h>
#include <gloperate-qt/viewer/QtKeyEventProvider.h>
#include <gloperate-qt/viewer/QtMouseEventProvider.h>
#include <gloperate-qt/viewer/QtWheelEventProvider.h>
#include <gloperate-qt/viewer/DefaultMapping.h>
#include <gloperate-qt/widgets/ImageExporterWidget.h>
#include <gloperate-qt/scripting/SystemApi.h>
#include <gloperate-qt/scripting/TimerApi.h>
#include <gloperate-qt/scripting/ViewerApi.h>
#include <gloperate-qt/scripting/PluginApi.h>

using namespace widgetzeug;
using namespace gloperate;

#ifdef GLOPERATE_ASSIMP_FOUND
    using namespace gloperate_assimp;
#endif

namespace
{
    const QString SETTINGS_GEOMETRY("Geometry");
    const QString SETTINGS_STATE("State");
    const QString SETTINGS_PLUGINS("Plugins");

    QStringList toQStringList(const std::vector<std::string> & list)
    {
        QStringList qlist;
        for (auto s : list) {
            qlist << QString::fromStdString(s);
        }
        return qlist;
    }

    std::vector<std::string> fromQStringList(const QStringList & qlist)
    {
        std::vector<std::string> list;
        for (QString s : qlist) {
            list.push_back(s.toStdString());
        }
        return list;
    }
}

namespace gloperate_qt
{

Viewer::Viewer(QWidget * parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
, m_ui{new Ui_Viewer}
, m_resourceManager{nullptr}
, m_pluginManager{nullptr}
, m_canvas{nullptr}
, m_painter{nullptr}
, m_mapping{nullptr}
, m_messagesStatus{new MessageStatusWidget()}
, m_messagesLog{new MessageWidget()}
, m_scriptPrompt{new ScriptPromptWidget()}
, m_messagLogDockWidget{nullptr}
, m_scriptPromptDockWidget{nullptr}
, m_propertyDockWidget{nullptr}
, m_systemApi{nullptr}
, m_timerApi{nullptr}
, m_viewerApi{nullptr}
, m_pluginApi{nullptr}
{
    // Initialize resource manager (must be done BEFORE setupCanvas)
    m_resourceManager.reset(new ResourceManager());

    // Add default texture loaders/storers
    m_resourceManager->addLoader(new QtTextureLoader());
    m_resourceManager->addStorer(new QtTextureStorer());

    // Add assimp loaders (if available)
#ifdef GLOPERATE_ASSIMP_FOUND
    m_resourceManager->addLoader(new AssimpMeshLoader());
    m_resourceManager->addLoader(new AssimpSceneLoader());
#endif

    // Setup UI
    m_ui->setupUi(this);
    setupMessageWidgets();
    setupCommandPrompt();
    setupPropertyWidget();
    setupDockArea();
    setupCanvas();

    // Load settings
    QSettings::setDefaultFormat(QSettings::IniFormat);
    QSettings settings;

    // Restore GUI state from settings
    restoreGeometry(settings.value(SETTINGS_GEOMETRY).toByteArray());
    restoreState(settings.value(SETTINGS_STATE).toByteArray());

    // Initialize plugin manager
    m_pluginManager.reset(new PluginManager());
    m_pluginManager->pluginsChanged.connect(this, &Viewer::updatePainterMenu);

    // Restore plugin paths from settings
    auto paths = fromQStringList(settings.value(SETTINGS_PLUGINS).toStringList());
    if (paths.size() > 0) {
        // Restore plugin paths
        m_pluginManager->setPaths(paths);
    } else {
        // Add default plugin directories
        m_pluginManager->addPath(QCoreApplication::applicationDirPath().toStdString());
        #ifdef NDEBUG
            m_pluginManager->addPath("plugins");
        #else
            m_pluginManager->addPath("plugins/debug");
        #endif
    }

    // Scan all plugins with name component 'painter'
    m_pluginManager->scan("painter");

    // Setup scripting context
    setupScripting();
}

Viewer::~Viewer()
{
    // Save settings
    QSettings settings;
    settings.setValue(SETTINGS_GEOMETRY, saveGeometry());
    settings.setValue(SETTINGS_STATE, saveState());
    settings.setValue(SETTINGS_PLUGINS, toQStringList(m_pluginManager->paths()));

    // Disconnect message handlers
    MessageHandler::dettach(*m_messagesLog);
    MessageHandler::dettach(*m_messagesStatus);
}

QtOpenGLWindow * Viewer::canvas() const
{
    return m_canvas.get();
}

void Viewer::loadPainter(const std::string & name)
{
    // Get plugin by name
    Plugin * plugin = m_pluginManager->plugin(name);
    if (!plugin) {
        return;
    }

    // Unload old painter
    if (m_painter.get()) {
        m_scriptContext->unregisterObject(m_painter.get());
    }

    // Create new painter
    m_painter.reset(plugin->createPainter(*m_resourceManager));

    // [TODO] Check for painter context format requirements

    // Setup new painter
    m_canvas->setPainter(m_painter.get());
    m_mapping->setPainter(m_painter.get());
    m_canvas->initialize();

    // Register painter in scripting
    m_scriptContext->registerObject(m_painter.get());

    // Update property browser
    if (m_painter.get())
    {
        QWidget * old = m_propertyDockWidget->widget();
        delete old;

        m_propertyDockWidget->setWidget(new propertyguizeug::PropertyBrowser(m_painter.get()));
        m_propertyDockWidget->show();
    }
    else
    {
        m_propertyDockWidget->hide();
    }

    // Update rendering
    m_canvas->updateGL();
}

const scriptzeug::ScriptContext * Viewer::scriptContext() const
{
    return m_scriptContext.get();
}

scriptzeug::ScriptContext * Viewer::scriptContext()
{
    return m_scriptContext.get();
}

void Viewer::addScriptApi(reflectionzeug::Object * api)
{
    // Connect object to scripting engine
    m_scriptContext->registerObject(api);

    // Register name as extra word for word completion
    widgetzeug::ScriptCompleter * completer = static_cast<widgetzeug::ScriptCompleter *>(m_scriptPrompt->completer());
    assert(completer);
    completer->registerWord(QString::fromStdString(api->name()));
}

void Viewer::setupMessageWidgets()
{
    // Widgets have to be created beforehand
    assert(m_messagesStatus);
    assert(m_messagesLog);

    // Attach message handlers to log widgets
    MessageHandler::attach(*m_messagesStatus);
    MessageHandler::attach(*m_messagesLog);

    // Additionally write log to file
    MessageHandler::printsToFile(QtMsgType::QtWarningMsg);
    MessageHandler::printsToFile(QtMsgType::QtCriticalMsg);
    MessageHandler::printsToFile(QtMsgType::QtFatalMsg);

    // Announce log initialization
    qDebug("Initialize message log.");
    const QString fileLog(QString("Messages are also written to file://%1.").arg(MessageHandler::fileName()));
    qDebug("%s", qPrintable(fileLog));

    // Create dock window for message log
    m_messagLogDockWidget = new QDockWidget(tr("Message Log"));
    m_messagLogDockWidget->setWidget(m_messagesLog.get());
    m_messagLogDockWidget->setObjectName("MessageLogDockWidget");
    addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, m_messagLogDockWidget);
    m_messagesLog->setFrameShape(QFrame::NoFrame);

    // Add item to status bar and connect to window
    statusBar()->addPermanentWidget(m_messagesStatus.get());
    m_messagesStatus->attachWidget(m_messagLogDockWidget);
}

void Viewer::setupCommandPrompt()
{
    // Widgets have to be created beforehand
    assert(m_scriptPrompt);

    // Setup syntax highlighting and auto-completion
    m_scriptPrompt->setSyntaxHighlighter(new ECMA26251SyntaxHighlight);
    m_scriptPrompt->setCompleter(new ECMA26251Completer);

    // Create dock window for scripting console
    m_scriptPromptDockWidget = new QDockWidget(tr("Script Prompt"));
    m_scriptPromptDockWidget->setWidget(m_scriptPrompt.get());
    m_scriptPromptDockWidget->setObjectName("ScriptPromptWidget");
    addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, m_scriptPromptDockWidget);
    m_scriptPrompt->setFrameShape(QFrame::NoFrame);
}

void Viewer::setupPropertyWidget()
{
    // Create dock window for property browser
    m_propertyDockWidget = new QDockWidget("Properties", this);
    m_propertyDockWidget->setObjectName("PropertyDockWidget");
    m_propertyDockWidget->setAllowedAreas(Qt::DockWidgetArea::LeftDockWidgetArea);
    addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, m_propertyDockWidget, Qt::Orientation::Horizontal);
}

void Viewer::setupDockArea()
{
    // Define order of widgets in dock area
    tabifyDockWidget(m_messagLogDockWidget, m_scriptPromptDockWidget);
}

void Viewer::setupCanvas()
{
    // Setup OpenGL context format
    QSurfaceFormat format;
#ifdef __APPLE__
    // Get OpenGL 3.2/4.1 core context
    format.setVersion(3, 2);
#else
    // Get newest available core context
#endif
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setDepthBufferSize(16);

    // Create OpenGL context and window
    m_canvas.reset(new QtOpenGLWindow(*m_resourceManager, format));

    // Create widget container
    setCentralWidget(QWidget::createWindowContainer(m_canvas.get()));
    centralWidget()->setFocusPolicy(Qt::StrongFocus);

    // Setup event provider to rranslate Qt messages into gloperate events
    QtKeyEventProvider * keyProvider = new QtKeyEventProvider();
    keyProvider->setParent(m_canvas.get());
    QtMouseEventProvider * mouseProvider = new QtMouseEventProvider();
    mouseProvider->setParent(m_canvas.get());
    QtWheelEventProvider * wheelProvider = new QtWheelEventProvider();
    wheelProvider->setParent(m_canvas.get());

    m_canvas->installEventFilter(keyProvider);
    m_canvas->installEventFilter(mouseProvider);
    m_canvas->installEventFilter(wheelProvider);

    // Create input mapping for gloperate interaction techniques
    m_mapping.reset(new DefaultMapping(m_canvas.get()));
    m_mapping->addProvider(keyProvider);
    m_mapping->addProvider(mouseProvider);
    m_mapping->addProvider(wheelProvider);
}

void Viewer::setupScripting()
{
    // Widgets have to be created beforehand
    assert(m_scriptPrompt);

    // Create scripting context
    m_scriptContext.reset(new scriptzeug::ScriptContext("javascript"));

    // Register default scripting APIs
    m_systemApi.reset(new SystemApi(this));
    addScriptApi(m_systemApi.get());

    m_timerApi.reset(new TimerApi);
    addScriptApi(m_timerApi.get());

    m_viewerApi.reset(new ViewerApi(this));
    addScriptApi(m_viewerApi.get());

    m_pluginApi.reset(new PluginApi(m_pluginManager.get()));
    addScriptApi(m_pluginApi.get());

    // Connect to input from scripting console
    connect(m_scriptPrompt.get(), &widgetzeug::ScriptPromptWidget::evaluate, [this] (const QString & cmd) {
        // Substitute shortcut commands
        QString command = cmd;
        if (cmd == "help") {
            command = "help()";
        } else if (cmd == "exit" || cmd == "quit") {
            command = "exit()";
        }

        // Execute commands that have been typed on the scripting console
        m_scriptContext->evaluate(command.toStdString());
    });

    // Connect commands that have been loaded by API functions (e.g., system.load)
    m_systemApi->command.connect([this] (const std::string & cmd) {
        // Execute code
        m_scriptContext->evaluate(cmd);
    });

    // Connect script output (system.print)
    m_systemApi->output.connect([this] (const std::string & msg) {
        // Print message onto the scripting console
        m_scriptPrompt->print(QString::fromStdString(msg));
    });

    // Connect keyboard events to scripting api
    m_canvas->installEventFilter(m_systemApi.get());

    // Add global functions
    std::string script =
        "function help() {\n"
        "  system.print('Available commands:');\n"
        "  system.print('  help():     Print this help message');\n"
        "  system.print('  print():    Print the content of a variable');\n"
        "  system.print('  toString(): Convert a variable into a string');\n"
        "  system.print('  exit():     Exit the application');\n"
        "  system.print('');\n"
        "  system.print('APIs:');\n"
        "  system.print('  system: System API (e.g., file io, keyboard handling)');\n"
        "  system.print('  timer:  Timer API');\n"
        "  system.print('  viewer: Viewer main window control');\n"
        "  system.print('  plugin: Plugin management');\n"
        "  system.print('');\n"
        "  system.print('Examples:');\n"
        "  system.print('  print(system);');\n"
        "  system.print('  timer.start(1000, function() { print(\"Hello Scripting World.\"); } );');\n"
        "  system.print('  timer.stopAll();');\n"
        "}\n"
        "\n"
        "function load(filename) {\n"
        "  system.load(filename);\n"
        "}\n"
        "\n"
        "function print(value) {\n"
        "  system.print(value);\n"
        "};\n"
        "\n"
        "function exit() {\n"
        "  system.exit();\n"
        "};\n"
        "\n"
        "function quit() {\n"
        "  system.exit();\n"
        "};\n";
    m_scriptContext->evaluate(script);

    // Register extra words for word completion
    widgetzeug::ScriptCompleter * completer = static_cast<widgetzeug::ScriptCompleter *>(m_scriptPrompt->completer());
    assert(completer);
    completer->registerWords(QStringList() << "help" << "load" << "print" << "exit");
}

void Viewer::updatePainterMenu()
{
    // Clear painter menu
    QMenu * menu = m_ui->painterMenu;
    menu->clear();

    // Add all loaded plugins
    for (auto plugin : m_pluginManager->plugins())
    {
        // Add action
        QAction * action = new QAction(QString::fromStdString(plugin->name()), menu);
        action->setData(QString::fromStdString(plugin->name()));
        connect(action, SIGNAL(toggled(bool)), this, SLOT(onPainterSelected(bool)));
        connect(action, SIGNAL(triggered(bool)), this, SLOT(onPainterSelected(bool)));

        // Add to menu
        menu->addAction(action);
    }
}

void Viewer::on_captureImageAction_triggered()
{
    // Screenshot dialog needs an active painter
    if (m_painter)
    {
        // Show image exporter dialog
        ImageExporterWidget * ie{ new ImageExporterWidget(*m_resourceManager, m_canvas->painter(), m_canvas.get()) };
        ie->setWindowModality(Qt::NonModal);
        ie->show();
    }
}

void Viewer::on_managePluginsAction_triggered()
{
    assert(m_pluginManager);

    // [TODO] Show plugin manager widget
}

void Viewer::onPainterSelected(bool /*checked*/)
{
    // Get selected menu action
    QAction * action = dynamic_cast<QAction*>(QObject::sender());
    Q_ASSERT(action != nullptr);

    // Get painter name
    QString name = action->data().toString();
    loadPainter(name.toStdString());
}

} // namespace gloperate_qt
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//		E L E N A   P r o j e c t:  ELENA RT Engine
//
//                                              (C)2009-2017, by Alexei Rakov
//---------------------------------------------------------------------------

#include "elena.h"
// -------------------------------------------------------------------
#include "elenart.h"
#include "instance.h"
#include "linux32/elfhelper.h"

#define ROOT_PATH          "/usr/lib/elena"
#define CONFIG_PATH        "/etc/elena/elenart.config"
#define IMAGE_BASE         0x08048000

using namespace _ELENA_;

static Instance* instance = NULL;

void* init()
{
   instance = new Instance(CONFIG_PATH);

   void* debugSection = NULL;
   void* messageSection = NULL;
   Instance::ImageSection section;
   section.init((void*)IMAGE_BASE, 0x1000);

   size_t ptr = 0;
   MemoryReader reader(&section);

   ELFHelper::seekDebugSegment(reader, ptr);
   debugSection = (void*)ptr;

   PEHelper::seekSection(MemoryReader(&section), ".mdata", ptr);
   messageSection = (void*)ptr;

   instance->init(debugSection, messageSection, CONFIG_PATH);

   return instance;
}

int ReadCallStack(size_t framePosition, size_t currentAddress, size_t startLevel, int* buffer, size_t maxLength)
{
   //return ((Instance*)instance)->readCallStack(framePosition, currentAddress, startLevel, buffer, maxLength);
   return 0;
}

int LoadAddressInfo(void* retPoint, char* lineInfo, size_t length)
{
   if (instance == NULL)
      init();

   return instance->loadAddressInfo((size_t)retPoint, lineInfo, length);
}

int LoadClassName(void* object, char* buffer, size_t length)
{
   if (instance == NULL)
      init();

   return instance->loadClassName((size_t)object, buffer, length);
}

void* Interpreter(void* tape)
{
   // !! terminator code
   return NULL;
}

void* GetVMLastError(void* retVal)
{
   // !! terminator code
   return NULL;
}

int LoadSubjectName(void* subject, char* lineInfo, size_t length)
{
   if (instance == NULL)
      init();

   return instance->loadSubjectName((size_t)subject, lineInfo, length);
}

void* LoadSubject(void* subjectName)
{
   if (instance == NULL)
      init();

   return instance->loadSubject((const char*)subjectName);
}

void* LoadMessage(void* messageName)
{
   return instance->loadMessage((const char*)messageName);
}

int LoadMessageName(void* subject, char* lineInfo, size_t length)
{
   if (instance == NULL)
      init();

   return instance->loadMessageName((size_t)subject, lineInfo, length);
}

void* LoadSymbol(void* referenceName)
{
   if (instance == NULL)
      init();

   return instance->loadSymbol((const char*)referenceName);
}

<commit_msg>#319 : (re)implementing elenart<commit_after>//---------------------------------------------------------------------------
//		E L E N A   P r o j e c t:  ELENA RT Engine
//
//                                              (C)2009-2020, by Alexei Rakov
//---------------------------------------------------------------------------

#include "elena.h"
// -------------------------------------------------------------------
#include "elenart.h"
#include "instance.h"
#include "linux32/elfhelper.h"

#define ROOT_PATH          "/usr/lib/elena"
#define CONFIG_PATH        "/etc/elena/elenart.config"
#define IMAGE_BASE         0x08048000

using namespace _ELENA_;

static ELENARTMachine* _Instance = NULL;
static void* _SystemEnv = NULL;

EXTERN_DLL_EXPORT void InitializeSTA(void* systemEnv, void* exceptionHandler, void* criticalHandler, void* entryPoint)
{
   ProgramHeader header;
   // initialize the exception handler
   __asm {
      mov header.root_exception_struct.core_catch_frame, ebp
      mov header.root_exception_struct.core_catch_level, esp
   }
   header.root_exception_struct.core_catch_addr = (pos_t)exceptionHandler;

   // initialize the critical exception handler
   __routineProvider.InitCriticalStruct(&header.root_critical_struct, (pos_t)criticalHandler);

   // initialize system env variable
   _SystemEnv = systemEnv;

   // start the system
   _Instance->startSTA(&header, (SystemEnv*)systemEnv, entryPoint);
}

EXTERN_DLL_EXPORT void InitializeMTA(void* systemEnv, void* exceptionHandler, void* criticalHandler, void* entryPoint)
{
   ProgramHeader header;
   // initialize the exception handler
   __asm {
      mov header.root_exception_struct.core_catch_frame, ebp
      mov header.root_exception_struct.core_catch_level, esp
   }
   header.root_exception_struct.core_catch_addr = (pos_t)exceptionHandler;

   // initialize the critical exception handler
   __routineProvider.InitCriticalStruct(&header.root_critical_struct, (pos_t)criticalHandler);

   // initialize system env variable
   _SystemEnv = systemEnv;

   // start the system
   _Instance->startMTA(&header, (SystemEnv*)systemEnv, entryPoint);
}

EXTERN_DLL_EXPORT int StartThread(void* systemEnv, void* exceptionHandler, void* entryPoint, int index)
{
   ProgramHeader header;
   // initialize the exception handler
   __asm {
      mov header.root_exception_struct.core_catch_frame, ebp
      mov header.root_exception_struct.core_catch_level, esp
   }
   header.root_exception_struct.core_catch_addr = (pos_t)exceptionHandler;

   _Instance->startThread(&header, (SystemEnv*)systemEnv, entryPoint, index);

   return 0;
}

EXTERN_DLL_EXPORT void OpenFrame(void* systemEnv, void* frameHeader)
{
   SystemRoutineProvider::OpenFrame((SystemEnv*)systemEnv, (FrameHeader*)frameHeader);
}

EXTERN_DLL_EXPORT void CloseFrame(void* systemEnv, void* frameHeader)
{
   SystemRoutineProvider::CloseFrame((SystemEnv*)systemEnv, (FrameHeader*)frameHeader);
}

EXTERN_DLL_EXPORT void Exit(int exitCode)
{
   _Instance->Exit(exitCode);
}

EXTERN_DLL_EXPORT void StopThread(int exitCode)
{
   _Instance->ExitThread((SystemEnv*)_SystemEnv, exitCode);
}

void loadModulePath(HMODULE hModule, Path& rootPath, bool includeName)
{
   TCHAR path[MAX_PATH + 1];

   ::GetModuleFileName(hModule, path, MAX_PATH);

   if (includeName) {
      rootPath.copy(path);
   }
   else rootPath.copySubPath(path);
   rootPath.lower();
}

// ==== DLL entries ====

void init(HMODULE hModule)
{
   //// get DLL path
   //Path rootPath;
   //loadModulePath(hModule, rootPath, false);

   //// get EXE path
   //Path execPath;
   //loadModulePath(0, execPath, true);

   _Instance = new ELENARTMachine(rootPath.c_str(), execPath.c_str());

   void* messageSection = nullptr;
   void* mattributeSection = nullptr;
   ELENARTMachine::ImageSection section;
   section.init((void*)IMAGE_BASE, 0x1000);

   PEHelper::seekSection(MemoryReader(&section), ".mdata", ptr);
   messageSection = (void*)ptr;

   PEHelper::seekSection(MemoryReader(&section), ".adata", ptr);
   mattributeSection = (void*)ptr;

   _Instance->init(messageSection, mattributeSection, CONFIG_PATH);
}

EXTERN_DLL_EXPORT int ReadCallStack(void* instance, size_t framePosition, size_t currentAddress, size_t startLevel, int* buffer, size_t maxLength)
{
   return ((ELENARTMachine*)instance)->readCallStack(framePosition, currentAddress, startLevel, buffer, maxLength);
}

EXTERN_DLL_EXPORT int LoadAddressInfo(size_t retPoint, char* lineInfo, int length)
{
   return _Instance->loadAddressInfo(retPoint, lineInfo, length);
}

EXTERN_DLL_EXPORT int LoadClassName(void* object, char* buffer, int length)
{
   return _Instance->loadClassName((size_t)object, buffer, length);
}

EXTERN_DLL_EXPORT void* EvaluateTape(void* tape)
{
   // !! terminator code
   return NULL;
}

EXTERN_DLL_EXPORT void* InterpretTape(void* tape)
{
   // !! terminator code
   return NULL;
}

EXTERN_DLL_EXPORT void* GetVMLastError(void* retVal)
{
   return NULL;
}

EXTERN_DLL_EXPORT int LoadSubjectName(void* subject, char* lineInfo, int length)
{
   return _Instance->loadSubjectName((size_t)subject, lineInfo, length);
}

EXTERN_DLL_EXPORT void* LoadSubject(void* subjectName)
{
   return _Instance->loadSubject((const char*)subjectName);
}

EXTERN_DLL_EXPORT int LoadMessageName(void* message, char* lineInfo, int length)
{
   return _Instance->loadMessageName((ref_t)message, lineInfo, length);
}

EXTERN_DLL_EXPORT void* LoadMessage(void* messageName)
{
   return _Instance->loadMessage((const char*)messageName);
}

EXTERN_DLL_EXPORT void* LoadClassByString(void* systemEnv, void* referenceName)
{
   throw InternalError("Not yet implemented"); // !! temporal

   //return _Instance->loadMetaAttribute((const char*)referenceName, caSerializable);
}

EXTERN_DLL_EXPORT void* LoadClassByBuffer(void* systemEnv, void* referenceName, size_t index, size_t length)
{
   if (length < 0x100) {
      IdentifierString str((const char*)referenceName, index, length);

      return LoadClassByString(systemEnv, (void*)str.c_str());
   }
   else {
      DynamicString<char> str((const char*)referenceName, index, length);

      return LoadClassByString(systemEnv, (void*)str.str());
   }
}

EXTERN_DLL_EXPORT void* LoadSymbolByString(void* systemEnv, void* referenceName)
{
   throw InternalError("Not yet implemented"); // !! temporal

   //return _Instance->loadMetaAttribute((const char*)referenceName, caSymbolSerializable);
}

EXTERN_DLL_EXPORT void* LoadSymbolByBuffer(void* systemEnv, void* referenceName, size_t index, size_t length)
{
   if (length < 0x100) {
      IdentifierString str((const char*)referenceName, index, length);

      return LoadSymbolByString(systemEnv, (void*)str.c_str());
   }
   else {
      DynamicString<char> str((const char*)referenceName, index, length);

      return LoadSymbolByString(systemEnv, (void*)str.str());
   }
}
<|endoftext|>


<commit_before>/// @file   mobile.cpp
/// @brief  Implements mobile methods.
/// @author Enrico Fraccaroli
/// @date   Aug 23 2014
/// @copyright
/// Copyright (c) 2016 Enrico Fraccaroli <enrico.fraccaroli@gmail.com>
/// Permission is hereby granted, free of charge, to any person obtaining a
/// copy of this software and associated documentation files (the "Software"),
/// to deal in the Software without restriction, including without limitation
/// the rights to use, copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit persons to whom the
/// Software is furnished to do so, subject to the following conditions:
///     The above copyright notice and this permission notice shall be included
///     in all copies or substantial portions of the Software.
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.

#include "mobile.hpp"

#include "generalBehaviour.hpp"
#include "lua_script.hpp"
#include "logger.hpp"
#include "mud.hpp"

Mobile::Mobile() :
    id(),
    respawnRoom(),
    keys(),
    shortdesc(),
    staticdesc(),
    actions(),
    message_buffer(),
    nextRespawn(),
    controller(),
    lua_script(),
    managedItem(),
    behaviourQueue(),
    behaviourTimer(std::chrono::system_clock::now()),
    behaviourDelay(500000)
{
    // Nothing to do.
}

Mobile::~Mobile()
{
    // Delete only the temporary items.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    if (this->isAlive())
    {
        room->removeCharacter(this);
    }
    Logger::log(LogLevel::Debug,
                "Deleted mobile\t\t\t\t(%s)",
                this->getNameCapital());
}

bool Mobile::setAbilities(const std::string & source)
{
    if (source.empty()) return false;
    std::vector<std::string> charList = SplitString(source, ";");
    if (charList.size() != 5) return false;
    if (!this->setAbility(Ability::Strength,
                          ToNumber<unsigned int>(charList[0])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Agility,
                          ToNumber<unsigned int>(charList[1])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Perception,
                          ToNumber<unsigned int>(charList[2])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Constitution,
                          ToNumber<unsigned int>(charList[3])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Intelligence,
                          ToNumber<unsigned int>(charList[4])))
    {
        return false;
    }
    return true;
}

void Mobile::respawn()
{
    // Delete the models loaded as equipment.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    equipment.clear();
    // Delete the models loaded in the inventory.
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    inventory.clear();
    // Intialize the lua state.
    L = luaL_newstate();
    // Load the lua environment.
    LoadLuaEnvironmet(L, lua_script);
    // Set the mobile to Alive.
    this->setHealth(this->getMaxHealth(), true);
    this->setStamina(this->getMaxStamina(), true);
    // Trigger the init lua function.
    this->triggerEventInit();
    // Add the mobile to the respawn room.
    this->respawnRoom->addCharacter(this);
    // Set the list of exceptions.
    std::vector<Character *> exceptions;
    exceptions.push_back(this);
    // Send the message inside the room.
    this->room->sendToAll("%s apear from somewhere.\n",
                          exceptions,
                          this->getNameCapital());
    // Set the next action time.
    behaviourTimer = std::chrono::system_clock::now() +
                     std::chrono::seconds(level);
    // Log to the mud.
    //Logger::log(LogLevel::Debug, "Respawning " + this->id);
}

bool Mobile::isAlive() const
{
    return (this->room != nullptr);
}

bool Mobile::check() const
{
    bool safe = Character::check();
    safe &= CorrectAssert(!id.empty());
    safe &= CorrectAssert(respawnRoom != nullptr);
    safe &= CorrectAssert(!keys.empty());
    safe &= CorrectAssert(!shortdesc.empty());
    safe &= CorrectAssert(!staticdesc.empty());
    safe &= CorrectAssert(!actions.empty());
    safe &= CorrectAssert(!lua_script.empty());
    return safe;
}

bool Mobile::isMobile() const
{
    return true;
}

void Mobile::getSheet(Table & sheet) const
{
    // Call the function of the father class.
    Character::getSheet(sheet);
    // Add a divider.
    sheet.addDivider();
    // Set the values.
    sheet.addRow({"Id", this->id});
    sheet.addRow({"Respawn Room", ToString(this->respawnRoom->vnum)});
    std::string keyGroup;
    for (auto it : this->keys)
    {
        keyGroup += " " + it;
    }
    sheet.addRow({"Keys", keyGroup});
    sheet.addRow({"Short Desc.", this->shortdesc});
    sheet.addRow({"Static Desc.", this->staticdesc});
    std::string actionGroup;
    for (auto it : this->actions)
    {
        actionGroup += " " + it;
    }
    sheet.addRow({"Actions", actionGroup});
    sheet.addRow({"Is Alive", ToString(this->isAlive())});
    if (!this->isAlive())
    {
        sheet.addRow({"Respawn Time", ToString(this->getRespawnTime())});

    }
    if (this->controller != nullptr)
    {
        sheet.addRow({"Controller", this->controller->getName()});
    }
    sheet.addRow({"Lua Script", this->lua_script});
}

std::string Mobile::getName() const
{
    return ToLower(staticdesc);
}

bool Mobile::hasKey(const std::string & key) const
{
    bool found = false;
    for (auto iterator : keys)
    {
        if (BeginWith(iterator, key))
        {
            found = true;
        }
    }
    return found;
}

bool Mobile::hasAction(const std::string & _action) const
{
    bool found = false;
    for (auto iterator : actions)
    {
        if (BeginWith(iterator, _action))
        {
            found = true;
        }
    }
    return found;
}

void Mobile::kill()
{
    auto generateItem = [&](Item * item)
    {
        // Set the item vnum.
        item->vnum = Mud::instance().getMaxVnumItem() + 1;
        // Add the item to the mud.
        Mud::instance().addItem(item);
        // Evaluate the minimum and maximum condition.
        auto min = (item->maxCondition / 100) * 10;
        auto max = (item->maxCondition / 100) * 50;
        // Set a random condition for the new item.
        item->condition = TRandReal<double>(min, max);
    };
    // Before calling the character kill function, set the vnum for the new
    //  items, and set the item condition to a random value from 10% to 50%.
    for (auto item : this->inventory) generateItem(item);
    for (auto item : this->equipment) generateItem(item);
    // Call the method of the father class.
    Character::kill();
    // Set to 0 the cycle that this mobile has passed dead.
    nextRespawn = std::chrono::system_clock::now() +
                  std::chrono::seconds(10 * this->level);
    // Call the LUA function: Event_Death.
    this->triggerEventDeath();
}

int64_t Mobile::getRespawnTime() const
{
    // Return the check if the mobile can be respawned.
    return std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now() - nextRespawn).count();
}

bool Mobile::canRespawn()
{
    // Return the check if the mobile can be respawned.
    return (this->getRespawnTime() >= 0);
}

void Mobile::reloadLua()
{
    // Delete the models loaded as equipment.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    equipment.clear();
    // Delete the models loaded in the inventory.
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    inventory.clear();
    // Completely clear the stack.
    lua_settop(L, 0);
    // Reset the lua state.
    L = luaL_newstate();
    // Load the lua environment.
    LoadLuaEnvironmet(L, lua_script);
    // Call the LUA function: Event_Init in order to prepare the mobile.
    this->triggerEventInit();
}

void Mobile::sendMsg(const std::string & msg)
{
    if (controller != NULL)
    {
        controller->sendMsg(msg);
    }
    else
    {
        message_buffer += msg;
    }
}

void Mobile::performBehaviour()
{
    if (behaviourQueue.empty())
    {
        this->triggerEventMain();
    }
    if (this->checkBehaviourTimer())
    {
        auto status = behaviourQueue.front()->perform();
        if ((status == BehaviourStatus::Finished) ||
            (status == BehaviourStatus::Error))
        {
            behaviourQueue.pop_front();
        }
    }
}

bool Mobile::checkBehaviourTimer()
{
    // Check if the tic is passed.
    if (std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now() - behaviourTimer) >= behaviourDelay)
    {
        behaviourTimer = std::chrono::system_clock::now();
        return true;
    }
    return false;
}

void Mobile::triggerEventInit()
{
    this->mobileThread("EventInit", nullptr, "");
}

void Mobile::triggerEventFight(Character * character)
{
    this->mobileThread("EventFight", character, "");
}

void Mobile::triggerEventEnter(Character * character)
{
    Logger::log(LogLevel::Trace, "Activating EventEnter.");
    this->mobileThread("EventEnter", character, "");
    behaviourTimer = std::chrono::system_clock::now() -
                     std::chrono::seconds(1);
}

void Mobile::triggerEventExit(Character * character)
{
    this->mobileThread("EventExit", character, "");
}

void Mobile::triggerEventMessage(Character * character, std::string message)
{
    this->mobileThread("EventMessage", character, message);
}

void Mobile::triggerEventRandom()
{
    this->mobileThread("EventRandom", nullptr, "");
}

void Mobile::triggerEventMorning()
{
    this->mobileThread("EventMorning", nullptr, "");
}

void Mobile::triggerEventDay()
{
    this->mobileThread("EventDay", nullptr, "");
}

void Mobile::triggerEventDusk()
{
    this->mobileThread("EventDusk", nullptr, "");
}

void Mobile::triggerEventNight()
{
    this->mobileThread("EventNight", nullptr, "");
}

void Mobile::triggerEventDeath()
{
    this->mobileThread("EventDeath", nullptr, "");
}

void Mobile::triggerEventMain()
{
    this->mobileThread("EventMain", nullptr, "");
}

bool Mobile::mobileThread(std::string event,
                          Character * character,
                          std::string message)
{
    if (!event.empty())
    {
        try
        {
            luabridge::LuaRef func = luabridge::getGlobal(L, event.c_str());
            if (func.isFunction())
            {
                if (character != nullptr)
                {
                    if (!message.empty())
                    {
                        behaviourQueue.emplace_back(
                            std::make_shared<BehaviourP3<
                                Character *,
                                Character *,
                                std::string>>(event,
                                              func,
                                              this,
                                              character,
                                              message));
                    }
                    else
                    {
                        behaviourQueue.emplace_back(
                            std::make_shared<
                                BehaviourP2<
                                    Character *,
                                    Character *>>(event,
                                                  func,
                                                  this,
                                                  character));
                    }
                }
                else
                {
                    behaviourQueue.emplace_back(
                        std::make_shared<
                            BehaviourP1<Character *>>(event,
                                                      func,
                                                      this));
                }
            }
        }
        catch (luabridge::LuaException const & e)
        {
            Logger::log(LogLevel::Error, e.what());
        }
    }
    return true;
}

void Mobile::updateTicImpl()
{
    // Check if the mobile is alive.
    if (this->isAlive())
    {
        Character::updateTicImpl();
    }
    else
    {
        // Check if the mobile can be respawned.
        if (this->canRespawn())
        {
            // Respawn the mobile.
            this->respawn();
        }
    }
}

void Mobile::updateHourImpl()
{
    if (this->isAlive())
    {
        auto mudHour = MudUpdater::instance().getMudHour();
        if (mudHour == 6)
        {
            this->triggerEventMorning();
        }
        else if (mudHour == 12)
        {
            this->triggerEventDay();
        }
        else if (mudHour == 18)
        {
            this->triggerEventDusk();
        }
        else if (mudHour == 24)
        {
            this->triggerEventNight();
        }
        else
        {
            this->triggerEventRandom();
        }
    }
}
<commit_msg>Fix reset of Lua environment<commit_after>/// @file   mobile.cpp
/// @brief  Implements mobile methods.
/// @author Enrico Fraccaroli
/// @date   Aug 23 2014
/// @copyright
/// Copyright (c) 2016 Enrico Fraccaroli <enrico.fraccaroli@gmail.com>
/// Permission is hereby granted, free of charge, to any person obtaining a
/// copy of this software and associated documentation files (the "Software"),
/// to deal in the Software without restriction, including without limitation
/// the rights to use, copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit persons to whom the
/// Software is furnished to do so, subject to the following conditions:
///     The above copyright notice and this permission notice shall be included
///     in all copies or substantial portions of the Software.
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.

#include "mobile.hpp"

#include "generalBehaviour.hpp"
#include "lua_script.hpp"
#include "logger.hpp"
#include "mud.hpp"

Mobile::Mobile() :
    id(),
    respawnRoom(),
    keys(),
    shortdesc(),
    staticdesc(),
    actions(),
    message_buffer(),
    nextRespawn(),
    controller(),
    lua_script(),
    managedItem(),
    behaviourQueue(),
    behaviourTimer(std::chrono::system_clock::now()),
    behaviourDelay(500000)
{
    // Nothing to do.
}

Mobile::~Mobile()
{
    // Delete only the temporary items.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    if (this->isAlive())
    {
        room->removeCharacter(this);
    }
    Logger::log(LogLevel::Debug,
                "Deleted mobile\t\t\t\t(%s)",
                this->getNameCapital());
}

bool Mobile::setAbilities(const std::string & source)
{
    if (source.empty()) return false;
    std::vector<std::string> charList = SplitString(source, ";");
    if (charList.size() != 5) return false;
    if (!this->setAbility(Ability::Strength,
                          ToNumber<unsigned int>(charList[0])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Agility,
                          ToNumber<unsigned int>(charList[1])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Perception,
                          ToNumber<unsigned int>(charList[2])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Constitution,
                          ToNumber<unsigned int>(charList[3])))
    {
        return false;
    }
    if (!this->setAbility(Ability::Intelligence,
                          ToNumber<unsigned int>(charList[4])))
    {
        return false;
    }
    return true;
}

void Mobile::respawn()
{
    // Delete the models loaded as equipment.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    equipment.clear();
    // Delete the models loaded in the inventory.
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    inventory.clear();
    // Intialize the lua state.
    L = luaL_newstate();
    // Load the lua environment.
    LoadLuaEnvironmet(L, lua_script);
    // Set the mobile to Alive.
    this->setHealth(this->getMaxHealth(), true);
    this->setStamina(this->getMaxStamina(), true);
    // Trigger the init lua function.
    this->triggerEventInit();
    // Add the mobile to the respawn room.
    this->respawnRoom->addCharacter(this);
    // Set the list of exceptions.
    std::vector<Character *> exceptions;
    exceptions.push_back(this);
    // Send the message inside the room.
    this->room->sendToAll("%s apear from somewhere.\n",
                          exceptions,
                          this->getNameCapital());
    // Set the next action time.
    behaviourTimer = std::chrono::system_clock::now() +
                     std::chrono::seconds(level);
    // Log to the mud.
    //Logger::log(LogLevel::Debug, "Respawning " + this->id);
}

bool Mobile::isAlive() const
{
    return (this->room != nullptr);
}

bool Mobile::check() const
{
    bool safe = Character::check();
    safe &= CorrectAssert(!id.empty());
    safe &= CorrectAssert(respawnRoom != nullptr);
    safe &= CorrectAssert(!keys.empty());
    safe &= CorrectAssert(!shortdesc.empty());
    safe &= CorrectAssert(!staticdesc.empty());
    safe &= CorrectAssert(!actions.empty());
    safe &= CorrectAssert(!lua_script.empty());
    return safe;
}

bool Mobile::isMobile() const
{
    return true;
}

void Mobile::getSheet(Table & sheet) const
{
    // Call the function of the father class.
    Character::getSheet(sheet);
    // Add a divider.
    sheet.addDivider();
    // Set the values.
    sheet.addRow({"Id", this->id});
    sheet.addRow({"Respawn Room", ToString(this->respawnRoom->vnum)});
    std::string keyGroup;
    for (auto it : this->keys)
    {
        keyGroup += " " + it;
    }
    sheet.addRow({"Keys", keyGroup});
    sheet.addRow({"Short Desc.", this->shortdesc});
    sheet.addRow({"Static Desc.", this->staticdesc});
    std::string actionGroup;
    for (auto it : this->actions)
    {
        actionGroup += " " + it;
    }
    sheet.addRow({"Actions", actionGroup});
    sheet.addRow({"Is Alive", ToString(this->isAlive())});
    if (!this->isAlive())
    {
        sheet.addRow({"Respawn Time", ToString(this->getRespawnTime())});

    }
    if (this->controller != nullptr)
    {
        sheet.addRow({"Controller", this->controller->getName()});
    }
    sheet.addRow({"Lua Script", this->lua_script});
}

std::string Mobile::getName() const
{
    return ToLower(staticdesc);
}

bool Mobile::hasKey(const std::string & key) const
{
    bool found = false;
    for (auto iterator : keys)
    {
        if (BeginWith(iterator, key))
        {
            found = true;
        }
    }
    return found;
}

bool Mobile::hasAction(const std::string & _action) const
{
    bool found = false;
    for (auto iterator : actions)
    {
        if (BeginWith(iterator, _action))
        {
            found = true;
        }
    }
    return found;
}

void Mobile::kill()
{
    auto generateItem = [&](Item * item)
    {
        // Set the item vnum.
        item->vnum = Mud::instance().getMaxVnumItem() + 1;
        // Add the item to the mud.
        Mud::instance().addItem(item);
        // Evaluate the minimum and maximum condition.
        auto min = (item->maxCondition / 100) * 10;
        auto max = (item->maxCondition / 100) * 50;
        // Set a random condition for the new item.
        item->condition = TRandReal<double>(min, max);
    };
    // Before calling the character kill function, set the vnum for the new
    //  items, and set the item condition to a random value from 10% to 50%.
    for (auto item : this->inventory) generateItem(item);
    for (auto item : this->equipment) generateItem(item);
    // Call the method of the father class.
    Character::kill();
    // Set to 0 the cycle that this mobile has passed dead.
    nextRespawn = std::chrono::system_clock::now() +
                  std::chrono::seconds(10 * this->level);
    // Call the LUA function: Event_Death.
    this->triggerEventDeath();
}

int64_t Mobile::getRespawnTime() const
{
    // Return the check if the mobile can be respawned.
    return std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now() - nextRespawn).count();
}

bool Mobile::canRespawn()
{
    // Return the check if the mobile can be respawned.
    return (this->getRespawnTime() >= 0);
}

void Mobile::reloadLua()
{
    // Delete the models loaded as equipment.
    for (auto item : equipment)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    equipment.clear();
    // Delete the models loaded in the inventory.
    for (auto item : inventory)
    {
        if (HasFlag(item->flags, ItemFlag::Temporary))
        {
            delete (item);
        }
    }
    inventory.clear();
    // Completely clear the stack.
    lua_settop(L, 0);
    // Empty the behaviours queue.
    behaviourQueue.clear();
    // Reset the lua state.
    L = luaL_newstate();
    // Load the lua environment.
    LoadLuaEnvironmet(L, lua_script);
    // Call the LUA function: Event_Init in order to prepare the mobile.
    this->triggerEventInit();
}

void Mobile::sendMsg(const std::string & msg)
{
    if (controller != NULL)
    {
        controller->sendMsg(msg);
    }
    else
    {
        message_buffer += msg;
    }
}

void Mobile::performBehaviour()
{
    if (behaviourQueue.empty())
    {
        this->triggerEventMain();
    }
    if (this->checkBehaviourTimer())
    {
        auto status = behaviourQueue.front()->perform();
        if ((status == BehaviourStatus::Finished) ||
            (status == BehaviourStatus::Error))
        {
            behaviourQueue.pop_front();
        }
    }
}

bool Mobile::checkBehaviourTimer()
{
    // Check if the tic is passed.
    if (std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now() - behaviourTimer) >= behaviourDelay)
    {
        behaviourTimer = std::chrono::system_clock::now();
        return true;
    }
    return false;
}

void Mobile::triggerEventInit()
{
    this->mobileThread("EventInit", nullptr, "");
}

void Mobile::triggerEventFight(Character * character)
{
    this->mobileThread("EventFight", character, "");
}

void Mobile::triggerEventEnter(Character * character)
{
    Logger::log(LogLevel::Trace, "Activating EventEnter.");
    this->mobileThread("EventEnter", character, "");
    behaviourTimer = std::chrono::system_clock::now() -
                     std::chrono::seconds(1);
}

void Mobile::triggerEventExit(Character * character)
{
    this->mobileThread("EventExit", character, "");
}

void Mobile::triggerEventMessage(Character * character, std::string message)
{
    this->mobileThread("EventMessage", character, message);
}

void Mobile::triggerEventRandom()
{
    this->mobileThread("EventRandom", nullptr, "");
}

void Mobile::triggerEventMorning()
{
    this->mobileThread("EventMorning", nullptr, "");
}

void Mobile::triggerEventDay()
{
    this->mobileThread("EventDay", nullptr, "");
}

void Mobile::triggerEventDusk()
{
    this->mobileThread("EventDusk", nullptr, "");
}

void Mobile::triggerEventNight()
{
    this->mobileThread("EventNight", nullptr, "");
}

void Mobile::triggerEventDeath()
{
    this->mobileThread("EventDeath", nullptr, "");
}

void Mobile::triggerEventMain()
{
    this->mobileThread("EventMain", nullptr, "");
}

bool Mobile::mobileThread(std::string event,
                          Character * character,
                          std::string message)
{
    if (!event.empty())
    {
        try
        {
            luabridge::LuaRef func = luabridge::getGlobal(L, event.c_str());
            if (func.isFunction())
            {
                if (character != nullptr)
                {
                    if (!message.empty())
                    {
                        behaviourQueue.emplace_back(
                            std::make_shared<BehaviourP3<
                                Character *,
                                Character *,
                                std::string>>(event,
                                              func,
                                              this,
                                              character,
                                              message));
                    }
                    else
                    {
                        behaviourQueue.emplace_back(
                            std::make_shared<
                                BehaviourP2<
                                    Character *,
                                    Character *>>(event,
                                                  func,
                                                  this,
                                                  character));
                    }
                }
                else
                {
                    behaviourQueue.emplace_back(
                        std::make_shared<
                            BehaviourP1<Character *>>(event,
                                                      func,
                                                      this));
                }
            }
        }
        catch (luabridge::LuaException const & e)
        {
            Logger::log(LogLevel::Error, e.what());
        }
    }
    return true;
}

void Mobile::updateTicImpl()
{
    // Check if the mobile is alive.
    if (this->isAlive())
    {
        Character::updateTicImpl();
    }
    else
    {
        // Check if the mobile can be respawned.
        if (this->canRespawn())
        {
            // Respawn the mobile.
            this->respawn();
        }
    }
}

void Mobile::updateHourImpl()
{
    if (this->isAlive())
    {
        auto mudHour = MudUpdater::instance().getMudHour();
        if (mudHour == 6)
        {
            this->triggerEventMorning();
        }
        else if (mudHour == 12)
        {
            this->triggerEventDay();
        }
        else if (mudHour == 18)
        {
            this->triggerEventDusk();
        }
        else if (mudHour == 24)
        {
            this->triggerEventNight();
        }
        else
        {
            this->triggerEventRandom();
        }
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: helper.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2002-12-02 17:30:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <unistd.h>

#ifndef _PAD_HELPER_HXX_
#include <helper.hxx>
#endif
#ifndef _PAD_PADIALOG_HRC_
#include <padialog.hrc>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _INTN_HXX
#include <tools/intn.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#ifndef  _COM_SUN_STAR_UI_DIALOGS_EXECUTABLEDIALOGRESULTS_HPP_
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
#endif
#ifndef  _COM_SUN_STAR_UI_DIALOGS_XFOLDERPICKER_HPP_
#include <com/sun/star/ui/dialogs/XFolderPicker.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_XCONTROLACCESS_HPP_
#include <com/sun/star/ui/dialogs/XControlAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif

using namespace osl;
using namespace rtl;
using namespace padmin;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ui::dialogs;

#define MAX_PATH 1024

/*
 *  PaResId
 */

ResId padmin::PaResId( ULONG nId )
{
    static ResMgr* pPaResMgr = NULL;
    if( ! pPaResMgr )
    {
        LanguageType nLang = LANGUAGE_SYSTEM;
        pPaResMgr = ResMgr::SearchCreateResMgr( "spa" MAKE_NUMSTR(SUPD), nLang );
        AllSettings aSettings = Application::GetSettings();
        aSettings.SetUILanguage( nLang );
        Application::SetSettings( aSettings );
    }
    return ResId( nId, pPaResMgr );
}

/*
 *  FindFiles
 */

void padmin::FindFiles( const String& rDirectory, ::std::list< String >& rResult, const String& rSuffixes )
{
    rResult.clear();

    OUString aDirPath;
    ::osl::FileBase::getFileURLFromSystemPath( rDirectory, aDirPath );
    Directory aDir( aDirPath );
    aDir.open();
    DirectoryItem aItem;
    while( aDir.getNextItem( aItem ) == FileBase::E_None )
    {
        FileStatus aStatus( FileStatusMask_FileName         |
                            FileStatusMask_Type
                            );
        if( aItem.getFileStatus( aStatus ) == FileBase::E_None &&
            ( aStatus.getFileType() == FileStatus::Regular ||
              aStatus.getFileType() == FileStatus::Link ) )
        {
            String aFileName = aStatus.getFileName();
            int nToken = rSuffixes.GetTokenCount( ';' );
            while( nToken-- )
            {
                String aSuffix = rSuffixes.GetToken( nToken, ';' );
                if( aFileName.Len() > aSuffix.Len()+1 )
                {
                    String aExtension = aFileName.Copy( aFileName.Len()-aSuffix.Len() );
                    if( aFileName.GetChar( aFileName.Len()-aSuffix.Len()-1 ) == '.' &&
                        aExtension.EqualsIgnoreCaseAscii( aSuffix ) )
                    {
                        rResult.push_back( aFileName );
                        break;
                    }
                }
            }
        }
    }
    aDir.close();
}

/*
 *  DelMultiListBox
 */

long DelMultiListBox::Notify( NotifyEvent& rEvent )
{
    long nRet = 0;

    if( rEvent.GetType() == EVENT_KEYINPUT &&
        rEvent.GetKeyEvent()->GetKeyCode().GetCode() == KEY_DELETE )
    {
        m_aDelPressedLink.Call( this );
        nRet = 1;
    }
    else
        nRet = MultiListBox::Notify( rEvent );

    return nRet;
}

/*
 *  DelListBox
 */

long DelListBox::Notify( NotifyEvent& rEvent )
{
    long nRet = 0;

    if( rEvent.GetType() == EVENT_KEYINPUT &&
        rEvent.GetKeyEvent()->GetKeyCode().GetCode() == KEY_DELETE )
    {
        m_aDelPressedLink.Call( this );
        nRet = 1;
    }
    else
        nRet = ListBox::Notify( rEvent );

    return nRet;
}

/*
 *  QueryString
 */

QueryString::QueryString( Window* pParent, String& rQuery, String& rRet, const ::std::list< String >& rChoices ) :
        m_rReturnValue( rRet ),
        ModalDialog( pParent, PaResId( RID_STRINGQUERYDLG ) ),
        m_aOKButton( this, PaResId( RID_STRQRY_BTN_OK ) ),
        m_aEdit( this, PaResId( RID_STRQRY_EDT_NEWNAME ) ),
        m_aComboBox( this, PaResId( RID_STRQRY_BOX_NEWNAME ) ),
        m_aFixedText( this, PaResId( RID_STRQRY_TXT_RENAME ) ),
        m_aCancelButton( this, PaResId( RID_STRQRY_BTN_CANCEL ) )
{
    m_aOKButton.SetClickHdl( LINK( this, QueryString, ClickBtnHdl ) );
    m_aFixedText.SetText( rQuery );
    if( rChoices.begin() != rChoices.end() )
    {
        m_aComboBox.SetText( m_rReturnValue );
        m_aComboBox.InsertEntry( m_rReturnValue );
        for( ::std::list<String>::const_iterator it = rChoices.begin(); it != rChoices.end(); ++it )
            m_aComboBox.InsertEntry( *it );
        m_aEdit.Show( FALSE );
        m_bUseEdit = false;
    }
    else
    {
        m_aEdit.SetText( m_rReturnValue );
        m_aComboBox.Show( FALSE );
        m_bUseEdit = true;
    }
    SetText( Application::GetDisplayName() );
    FreeResource();
}

QueryString::~QueryString()
{
}

IMPL_LINK( QueryString, ClickBtnHdl, Button*, pButton )
{
    if( pButton == &m_aOKButton )
    {
        m_rReturnValue = m_bUseEdit ? m_aEdit.GetText() : m_aComboBox.GetText();
        EndDialog( 1 );
    }
    else
        EndDialog(0);
    return 0;
}

/*
 *  AreYouSure
 */

BOOL padmin::AreYouSure( Window* pParent, int nRid )
{
    if( nRid == -1 )
        nRid = RID_YOU_SURE;
    QueryBox aQueryBox( pParent, WB_YES_NO | WB_DEF_NO,
                        String( PaResId( nRid ) ) );
    return aQueryBox.Execute() == RET_NO ? FALSE : TRUE;
}

/*
 *  getPadminRC
 */

static Config* pRC = NULL;

Config& padmin::getPadminRC()
{
    if( ! pRC )
    {
        static const char* pEnv = getenv( "HOME" );
        String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() );
        aFileName.AppendAscii( "/.padminrc" );
        pRC = new Config( aFileName );
    }
    return *pRC;
}

void padmin::freePadminRC()
{
    if( pRC )
        delete pRC, pRC = NULL;
}

bool padmin::chooseDirectory( Window* pParent, String& rInOutPath )
{
    bool bRet = false;
    Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
    if( xFactory.is() )
    {
        Reference< XFolderPicker > xFolderPicker( xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FolderPicker" ) ) ), UNO_QUERY );
        if( xFolderPicker.is() )
        {
            Reference< XControlAccess > xCA( xFolderPicker, UNO_QUERY );
            if( xCA.is() )
            {
                try
                {
                    Any aState;
                    aState <<= sal_False;
                    xCA->setControlProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpButton" ) ),
                                             OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ),
                                             aState );

                }
                catch( ... )
                {
                }
            }
            INetURLObject aObj( rInOutPath, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
            xFolderPicker->setDisplayDirectory( aObj.GetMainURL(INetURLObject::DECODE_TO_IURI) );
            if( xFolderPicker->execute() == ExecutableDialogResults::OK )
            {
                aObj = INetURLObject( xFolderPicker->getDirectory() );
                rInOutPath = aObj.PathToFileName();
                bRet = true;
            }
        }
#ifdef DEBUG
        else
            fprintf( stderr, "could not get FolderPicker service\n" );
#endif
    }
    return bRet;
}
<commit_msg>INTEGRATION: CWS dbgmacros1 (1.10.26); FILE MERGED 2003/04/09 12:04:04 kso 1.10.26.1: #108413# - debug macro unification.<commit_after>/*************************************************************************
 *
 *  $RCSfile: helper.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: vg $ $Date: 2003-04-15 17:21:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <unistd.h>

#ifndef _PAD_HELPER_HXX_
#include <helper.hxx>
#endif
#ifndef _PAD_PADIALOG_HRC_
#include <padialog.hrc>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _INTN_HXX
#include <tools/intn.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#ifndef  _COM_SUN_STAR_UI_DIALOGS_EXECUTABLEDIALOGRESULTS_HPP_
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
#endif
#ifndef  _COM_SUN_STAR_UI_DIALOGS_XFOLDERPICKER_HPP_
#include <com/sun/star/ui/dialogs/XFolderPicker.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_XCONTROLACCESS_HPP_
#include <com/sun/star/ui/dialogs/XControlAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif

using namespace osl;
using namespace rtl;
using namespace padmin;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ui::dialogs;

#define MAX_PATH 1024

/*
 *  PaResId
 */

ResId padmin::PaResId( ULONG nId )
{
    static ResMgr* pPaResMgr = NULL;
    if( ! pPaResMgr )
    {
        LanguageType nLang = LANGUAGE_SYSTEM;
        pPaResMgr = ResMgr::SearchCreateResMgr( "spa" MAKE_NUMSTR(SUPD), nLang );
        AllSettings aSettings = Application::GetSettings();
        aSettings.SetUILanguage( nLang );
        Application::SetSettings( aSettings );
    }
    return ResId( nId, pPaResMgr );
}

/*
 *  FindFiles
 */

void padmin::FindFiles( const String& rDirectory, ::std::list< String >& rResult, const String& rSuffixes )
{
    rResult.clear();

    OUString aDirPath;
    ::osl::FileBase::getFileURLFromSystemPath( rDirectory, aDirPath );
    Directory aDir( aDirPath );
    aDir.open();
    DirectoryItem aItem;
    while( aDir.getNextItem( aItem ) == FileBase::E_None )
    {
        FileStatus aStatus( FileStatusMask_FileName         |
                            FileStatusMask_Type
                            );
        if( aItem.getFileStatus( aStatus ) == FileBase::E_None &&
            ( aStatus.getFileType() == FileStatus::Regular ||
              aStatus.getFileType() == FileStatus::Link ) )
        {
            String aFileName = aStatus.getFileName();
            int nToken = rSuffixes.GetTokenCount( ';' );
            while( nToken-- )
            {
                String aSuffix = rSuffixes.GetToken( nToken, ';' );
                if( aFileName.Len() > aSuffix.Len()+1 )
                {
                    String aExtension = aFileName.Copy( aFileName.Len()-aSuffix.Len() );
                    if( aFileName.GetChar( aFileName.Len()-aSuffix.Len()-1 ) == '.' &&
                        aExtension.EqualsIgnoreCaseAscii( aSuffix ) )
                    {
                        rResult.push_back( aFileName );
                        break;
                    }
                }
            }
        }
    }
    aDir.close();
}

/*
 *  DelMultiListBox
 */

long DelMultiListBox::Notify( NotifyEvent& rEvent )
{
    long nRet = 0;

    if( rEvent.GetType() == EVENT_KEYINPUT &&
        rEvent.GetKeyEvent()->GetKeyCode().GetCode() == KEY_DELETE )
    {
        m_aDelPressedLink.Call( this );
        nRet = 1;
    }
    else
        nRet = MultiListBox::Notify( rEvent );

    return nRet;
}

/*
 *  DelListBox
 */

long DelListBox::Notify( NotifyEvent& rEvent )
{
    long nRet = 0;

    if( rEvent.GetType() == EVENT_KEYINPUT &&
        rEvent.GetKeyEvent()->GetKeyCode().GetCode() == KEY_DELETE )
    {
        m_aDelPressedLink.Call( this );
        nRet = 1;
    }
    else
        nRet = ListBox::Notify( rEvent );

    return nRet;
}

/*
 *  QueryString
 */

QueryString::QueryString( Window* pParent, String& rQuery, String& rRet, const ::std::list< String >& rChoices ) :
        m_rReturnValue( rRet ),
        ModalDialog( pParent, PaResId( RID_STRINGQUERYDLG ) ),
        m_aOKButton( this, PaResId( RID_STRQRY_BTN_OK ) ),
        m_aEdit( this, PaResId( RID_STRQRY_EDT_NEWNAME ) ),
        m_aComboBox( this, PaResId( RID_STRQRY_BOX_NEWNAME ) ),
        m_aFixedText( this, PaResId( RID_STRQRY_TXT_RENAME ) ),
        m_aCancelButton( this, PaResId( RID_STRQRY_BTN_CANCEL ) )
{
    m_aOKButton.SetClickHdl( LINK( this, QueryString, ClickBtnHdl ) );
    m_aFixedText.SetText( rQuery );
    if( rChoices.begin() != rChoices.end() )
    {
        m_aComboBox.SetText( m_rReturnValue );
        m_aComboBox.InsertEntry( m_rReturnValue );
        for( ::std::list<String>::const_iterator it = rChoices.begin(); it != rChoices.end(); ++it )
            m_aComboBox.InsertEntry( *it );
        m_aEdit.Show( FALSE );
        m_bUseEdit = false;
    }
    else
    {
        m_aEdit.SetText( m_rReturnValue );
        m_aComboBox.Show( FALSE );
        m_bUseEdit = true;
    }
    SetText( Application::GetDisplayName() );
    FreeResource();
}

QueryString::~QueryString()
{
}

IMPL_LINK( QueryString, ClickBtnHdl, Button*, pButton )
{
    if( pButton == &m_aOKButton )
    {
        m_rReturnValue = m_bUseEdit ? m_aEdit.GetText() : m_aComboBox.GetText();
        EndDialog( 1 );
    }
    else
        EndDialog(0);
    return 0;
}

/*
 *  AreYouSure
 */

BOOL padmin::AreYouSure( Window* pParent, int nRid )
{
    if( nRid == -1 )
        nRid = RID_YOU_SURE;
    QueryBox aQueryBox( pParent, WB_YES_NO | WB_DEF_NO,
                        String( PaResId( nRid ) ) );
    return aQueryBox.Execute() == RET_NO ? FALSE : TRUE;
}

/*
 *  getPadminRC
 */

static Config* pRC = NULL;

Config& padmin::getPadminRC()
{
    if( ! pRC )
    {
        static const char* pEnv = getenv( "HOME" );
        String aFileName( pEnv ? pEnv : "", osl_getThreadTextEncoding() );
        aFileName.AppendAscii( "/.padminrc" );
        pRC = new Config( aFileName );
    }
    return *pRC;
}

void padmin::freePadminRC()
{
    if( pRC )
        delete pRC, pRC = NULL;
}

bool padmin::chooseDirectory( Window* pParent, String& rInOutPath )
{
    bool bRet = false;
    Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
    if( xFactory.is() )
    {
        Reference< XFolderPicker > xFolderPicker( xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FolderPicker" ) ) ), UNO_QUERY );
        if( xFolderPicker.is() )
        {
            Reference< XControlAccess > xCA( xFolderPicker, UNO_QUERY );
            if( xCA.is() )
            {
                try
                {
                    Any aState;
                    aState <<= sal_False;
                    xCA->setControlProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "HelpButton" ) ),
                                             OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ),
                                             aState );

                }
                catch( ... )
                {
                }
            }
            INetURLObject aObj( rInOutPath, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
            xFolderPicker->setDisplayDirectory( aObj.GetMainURL(INetURLObject::DECODE_TO_IURI) );
            if( xFolderPicker->execute() == ExecutableDialogResults::OK )
            {
                aObj = INetURLObject( xFolderPicker->getDirectory() );
                rInOutPath = aObj.PathToFileName();
                bRet = true;
            }
        }
#if OSL_DEBUG_LEVEL > 1
        else
            fprintf( stderr, "could not get FolderPicker service\n" );
#endif
    }
    return bRet;
}
<|endoftext|>