Files
SingularityViewer/indra/newview/statemachine/aifilepicker.h
Aleric Inglewood 779f697ffb Fix yield_ms().
This fixes
https://code.google.com/p/singularity-viewer/issues/detail?id=714

The problem was a typo in AIStateMachine::sleep, >= should have been <=
which caused a state machine that uses yield_ms() to never run anymore
when next run it already should have run again. AIFilePicker is the only
state machine that currently uses yield_ms and I hadn't spotted this
because I don't have plugin messages on by default which made my viewer
just that much faster that it the yield never expired the first run
already (causing it to expire immediately).

The rest of the changes in this commit are just minor improvements /
conformation to the EXAMPLE_CODE in aistatemachine.cpp.
2013-03-26 23:30:04 +01:00

259 lines
10 KiB
C++

/**
* @file aifilepicker.h
* @brief File picker State machine
*
* Copyright (c) 2010, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 02/12/2010
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIFILEPICKER_H
#define AIFILEPICKER_H
#include "aistatemachine.h"
#include "llpluginclassmedia.h"
#include "llviewerpluginmanager.h"
#include <vector>
enum ELoadFilter
{
DF_DIRECTORY,
FFLOAD_ALL,
FFLOAD_WAV,
FFLOAD_IMAGE,
FFLOAD_ANIM,
FFLOAD_XML,
FFLOAD_SLOBJECT,
FFLOAD_RAW,
FFLOAD_MODEL,
FFLOAD_COLLADA,
FFLOAD_SCRIPT,
FFLOAD_DICTIONARY,
FFLOAD_INVGZ,
FFLOAD_AO,
FFLOAD_BLACKLIST
};
enum ESaveFilter
{
FFSAVE_ALL,
FFSAVE_WAV,
FFSAVE_TGA,
FFSAVE_BMP,
FFSAVE_AVI,
FFSAVE_ANIM,
FFSAVE_XML,
FFSAVE_COLLADA,
FFSAVE_RAW,
FFSAVE_J2C,
FFSAVE_PNG,
FFSAVE_JPEG,
FFSAVE_SCRIPT,
FFSAVE_ANIMATN,
FFSAVE_OGG,
FFSAVE_NOTECARD,
FFSAVE_GESTURE,
FFSAVE_SHAPE,
FFSAVE_SKIN,
FFSAVE_HAIR,
FFSAVE_EYES,
FFSAVE_SHIRT,
FFSAVE_PANTS,
FFSAVE_SHOES,
FFSAVE_SOCKS,
FFSAVE_JACKET,
FFSAVE_GLOVES,
FFSAVE_UNDERSHIRT,
FFSAVE_UNDERPANTS,
FFSAVE_SKIRT,
FFSAVE_INVGZ,
FFSAVE_LANDMARK,
FFSAVE_AO,
FFSAVE_BLACKLIST,
FFSAVE_PHYSICS
};
/*
AIFilePicker is an AIStateMachine, that has a LLViewerPluginManager (mPluginManager)
to manage a plugin that runs the actual filepicker in a separate process.
The relationship with the plugin is as follows:
new AIFilePicker
AIFilePicker::mPluginManager = new LLViewerPluginManager
LLPluginProcessParentOwner LLPluginMessagePipeOwner
| | LLPluginMessagePipeOwner::mOwner = LLPluginProcessParentOwner
| | LLPluginMessagePipeOwner::mMessagePipe = LLPluginMessagePipe
| | LLPluginMessagePipeOwner::receiveMessageRaw calls
v | LLPluginProcessParent::receiveMessageRaw
LLPluginClassBasic v
| LLPluginClassBasic::mPlugin = new LLPluginProcessParent ---> new LLPluginMessagePipe
| LLPluginProcessParent::mOwner = (LLPluginProcessParentOwner*)LLPluginClassBasic
| LLPluginProcessParent::sendMessage calls
| LLPluginMessagePipeOwner::writeMessageRaw calls
| mMessagePipe->LLPluginMessagePipe::addMessage
| LLPluginProcessParent::receiveMessageRaw calls
| LLPluginProcessParent::receiveMessage calls
| LLPluginProcessParentOwner::receivePluginMessage == AIPluginFilePicker::receivePluginMessage
|
| LLPluginClassBasic::sendMessage calls mPlugin->LLPluginProcessParent::sendMessage
|
v
LLViewerPluginManager::mPluginBase = new AIPluginFilePicker
AIPluginFilePicker::receivePluginMessage calls
AIFilePicker::receivePluginMessage
AIPluginFilePicker::mStateMachine = AIFilePicker
Where the entry point to send messages to the plugin is LLPluginClassBasic::sendMessage,
and the end point for messages received from the plugin is AIFilePicker::receivePluginMessage.
Termination happens by receiving the "canceled" or "done" message,
which sets the state to AIFilePicker_canceled or AIFilePicker_done
respectively, causing a call to AIStateMachine::finish(), which calls
AIFilePicker::finish_impl which destroys the plugin (mPluginBase),
the plugin manager (mPluginManager) after which the state machine
calls unref() causing the AIFilePicker to be deleted.
*/
// A file picker state machine.
//
// Before calling run(), call open() to pass needed parameters.
//
// When the state machine finishes, call isCanceled to check
// whether or not getFilename and getFolder will be valid.
//
// Objects of this type can be reused multiple times, see
// also the documentation of AIStateMachine.
class AIFilePicker : public AIStateMachine {
protected:
// The base class of this state machine.
typedef AIStateMachine direct_base_type;
enum filepicker_state_type {
AIFilePicker_initialize_plugin = direct_base_type::max_state,
AIFilePicker_plugin_running,
AIFilePicker_canceled,
AIFilePicker_done
};
public:
static state_type const max_state = AIFilePicker_done + 1; // One beyond the largest state.
public:
// The derived class must have a default constructor.
AIFilePicker(void);
// Create a dynamically created AIFilePicker object.
static AIFilePicker* create(void) { AIFilePicker* filepicker = new AIFilePicker; return filepicker; }
// The starting directory that the user will be in when the file picker opens
// will be the same as the directory used the last time the file picker was
// opened with the same context. If the file picker was never opened before
// with the given context, the starting directory will be set to default_path
// unless that is the empty string, in which case it will be equal to the
// directory used the last time the filepicker was opened with context "savefile".
void open(std::string const& filename, ESaveFilter filter = FFSAVE_ALL, std::string const& default_path = "", std::string const& context = "savefile");
void open(ELoadFilter filter = FFLOAD_ALL, std::string const& default_path = "", std::string const& context = "openfile", bool multiple = false);
bool isCanceled(void) const { return mCanceled; }
bool hasFilename(void) const { return *this && !mCanceled; }
std::string const& getFilename(void) const;
std::string getFolder(void) const;
std::vector<std::string> const& getFilenames(void) const { return mFilenames; }
// Load the sContextMap from disk.
static bool loadFile(std::string const& filename);
// Save the sContextMap to disk.
static bool saveFile(std::string const& filename);
private:
friend class AIPluginFilePicker;
// This is called from AIPluginFilePicker::receivePluginMessage, see below.
void receivePluginMessage(LLPluginMessage const& message);
public:
enum open_type { save, load, load_multiple };
private:
LLPointer<LLViewerPluginManager> mPluginManager; //!< Pointer to the plugin manager.
typedef std::map<std::string, std::string> context_map_type; //!< Type of mContextMap.
static AIThreadSafeSimpleDC<context_map_type> sContextMap; //!< Map context (ie, "snapshot" or "image") to last used folder.
std::string mContext; //!< Some key to indicate the context (remembers the folder per key).
// Input variables (cache variable between call to open and run).
open_type mOpenType; //!< Set to whether opening a filepicker to select for saving one file, for loading one file, or loading multiple files.
std::string mFilter; //!< A keyword indicating which file types (extensions) we want to see.
std::string mFilename; //!< When saving: proposed filename.
std::string mFolder; //!< Initial folder to start in.
// Output variables:
bool mCanceled; //!< True if the file picker was canceled or closed.
std::vector<std::string> mFilenames; //!< Filesnames.
// Store a folder for the given context.
static void store_folder(std::string const& context, std::string const& folder);
// Return the last folder stored for 'context', or default_path if none, or context "savefile" if empty, or $HOME if none.
static std::string get_folder(std::string const& default_path, std::string const& context);
protected:
// Call finish() (or abort()), not delete.
/*virtual*/ ~AIFilePicker() { LL_DEBUGS("Plugin") << "Calling AIFilePicker::~AIFilePicker()" << LL_ENDL; }
// Handle initializing the object.
/*virtual*/ void initialize_impl(void);
// Handle mRunState.
/*virtual*/ void multiplex_impl(state_type run_state);
// Handle cleaning up from initialization (or post abort) state.
/*virtual*/ void finish_impl(void);
// Implemenation of state_str for run states.
/*virtual*/ char const* state_str_impl(state_type run_state) const;
};
// Viewer-side helper class for objects with a lifetime equal to the
// plugin child process (SLPlugin). Don't use directly.
class AIPluginFilePicker : public LLPluginClassBasic {
LOG_CLASS(AIPluginFilePicker);
public:
AIPluginFilePicker(AIFilePicker* state_machine) : mStateMachine(state_machine) { }
/*virtual*/ ~AIPluginFilePicker() { LL_DEBUGS("Plugin") << "Calling AIPluginFilePicker::~AIPluginFilePicker()" << LL_ENDL; }
static std::string launcher_name(void) { return gDirUtilp->getLLPluginLauncher(); }
static char const* plugin_basename(void) { return "basic_plugin_filepicker"; }
/*virtual*/ void receivePluginMessage(LLPluginMessage const& message) { mStateMachine->receivePluginMessage(message); }
/*virtual*/ void receivedShutdown(void) { /* Nothing -- we terminate on deletion (from AIStateMachine::mainloop) */ }
private:
AIFilePicker* mStateMachine;
};
#endif