#include "gromacs/options/basicoptions.h"
#include "gromacs/options/filenameoption.h"
#include "gromacs/options/options.h"
+#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
-#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionoptionmanager.h"
#include "gromacs/utility/file.h"
#include "testutils/datapath.h"
options.addOption(SelectionOption("sel").required().valueCount(2)
.description("Selection option"));
gmx::SelectionCollection selections;
- setSelectionCollectionForOptions(&options, &selections);
+ gmx::SelectionOptionManager manager(&selections);
+ setManagerForSelectionOptions(&options, &manager);
options.finish();
- selections.parseRequestedFromString(
+ manager.parseRequestedFromString(
"resname SOL;"
"surface = within 0.5 of resname SOL;"
"group \"Protein\" and surface;"
* module_options for general explanation of the options mechanism). These
* classes provide the main interface to obtain gmx::Selection objects in
* trajectory analysis using gmx::TrajectoryAnalysisModule.
- *
+ * To use these classes outside the trajectory analysis framework,
+ * a gmx::SelectionOptionManager needs to be created to serve as a bridge
+ * between the selection option classes and the gmx::SelectionCollection
+ * object.
* \if libapi
+ * gmx::SelectionFileOption can be used to implement generic file input for
+ * selection options (done internally in the trajectory analysis framework).
+ *
* The selection module contains some lower-level functionality that is
* currently internal to it (centerofmass.h, indexutil.h, poscalc.h,
* position.h), but could possibly be useful also outside the module.
#include "selection/selectioncollection.h"
#include "selection/selectionoption.h"
#include "selection/selectionoptioninfo.h"
+#include "selection/selectionoptionmanager.h"
#endif
selectioncollection.h
selectionenums.h
selectionoption.h
- selectionoptioninfo.h)
+ selectionoptioninfo.h
+ selectionoptionmanager.h)
install(FILES ${SELECTION_PUBLIC_HEADERS}
DESTINATION ${INCL_INSTALL_DIR}/gromacs/selection
COMPONENT development)
{
class MessageStringCollector;
-class SelectionOptionStorage;
/*! \internal \brief
* Private implemention class for SelectionCollection.
class SelectionCollection::Impl
{
public:
- /*! \brief
- * Request for postponed parsing of selections.
- *
- * Used to communicate what needs to be parsed with
- * parseRequestedFromStdin() or parseRequstedFromString().
- */
- struct SelectionRequest
- {
- //! Initializes a request for the given option.
- SelectionRequest(const std::string &name, const std::string &descr,
- SelectionOptionStorage *storage)
- : name(name), descr(descr), storage(storage)
- {
- }
-
- /*! \brief
- * Returns the number of selections requested in this request.
- *
- * -1 indicates no upper limit.
- */
- int count() const;
-
- //! Name of the option to which this request relates to.
- std::string name;
- //! Description of the option to which this request relates to.
- std::string descr;
- //! Storage object to which the selections will be added.
- SelectionOptionStorage *storage;
- };
-
- //! Collection for a list of selection requests.
- typedef std::vector<SelectionRequest> RequestList;
-
- /*! \brief
- * Helper class that clears a request list on scope exit.
- *
- * Methods in this class do not throw.
- */
- class RequestsClearer
- {
- public:
- //! Constructs an object that clears given list on scope exit.
- explicit RequestsClearer(RequestList *requests)
- : requests_(requests)
- {
- }
- //! Clears the request list given to the constructor.
- ~RequestsClearer()
- {
- requests_->clear();
- }
-
- private:
- RequestList *requests_;
- };
-
/*! \brief
* Creates a new selection collection.
*
*/
void runParser(void *scanner, int maxnr,
SelectionList *output);
- /*! \brief
- * Adds a selection request for delayed user input.
- *
- * \param[in] name Name for the requested selections.
- * \param[in] descr Description of the requested selections.
- * \param storage Storage object to receive the selections.
- * \throws std::bad_alloc if out of memory.
- *
- * Strong exception safety.
- *
- * \see parseRequestedFromStdin()
- */
- void requestSelections(const std::string &name,
- const std::string &descr,
- SelectionOptionStorage *storage);
- /*! \brief
- * Assign selections from a list to pending requests.
- *
- * \param[in] selections List of selections to assign.
- * \throws std::bad_alloc if out of memory.
- * \throws InvalidInputError if the assignment cannot be done
- * (see parseRequestedFromFile() for documented conditions).
- *
- * Loops through \p selections and the pending requests lists in order,
- * and for each requests, assigns the first yet unassigned selections
- * from the list.
- *
- * Used to implement parseRequestedFromFile() and
- * parseRequestedFromStdin().
- */
- void placeSelectionsInRequests(const SelectionList &selections);
/*! \brief
* Replace group references by group contents.
*
bool _bExternalGroupsSet;
//! External index groups (can be NULL).
gmx_ana_indexgrps_t *_grps;
- //! List of selections requested for later parsing.
- RequestList _requests;
};
/*! \internal \brief
#include <cstdio>
-#include "futil.h"
-#include "oenv.h"
-#include "smalloc.h"
-#include "xvgr.h"
+#include "gromacs/legacyheaders/oenv.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/xvgr.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
-#include "gromacs/utility/format.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/messagestringcollector.h"
#include "poscalc.h"
#include "scanner.h"
#include "selectioncollection-impl.h"
-#include "selectionoptionstorage.h"
#include "selelem.h"
#include "selmethod.h"
#include "symrec.h"
* SelectionCollection::Impl
*/
-int SelectionCollection::Impl::SelectionRequest::count() const
-{
- return storage->maxValueCount();
-}
-
SelectionCollection::Impl::Impl()
: _options("selection", "Common selection control"),
_debugLevel(0), _bExternalGroupsSet(false), _grps(NULL)
}
-void SelectionCollection::Impl::requestSelections(
- const std::string &name, const std::string &descr,
- SelectionOptionStorage *storage)
-{
- _requests.push_back(SelectionRequest(name, descr, storage));
-}
-
-
-void SelectionCollection::Impl::placeSelectionsInRequests(
- const SelectionList &selections)
-{
- RequestsClearer clearRequestsOnExit(&_requests);
-
- SelectionList::const_iterator first = selections.begin();
- SelectionList::const_iterator last = first;
- RequestList::const_iterator i;
- // TODO: Improve error messages.
- for (i = _requests.begin(); i != _requests.end(); ++i)
- {
- const SelectionRequest &request = *i;
- if (request.count() > 0)
- {
- if (selections.end() - first < request.count())
- {
- GMX_THROW(InvalidInputError("Too few selections provided"));
- }
- last = first + request.count();
- }
- else
- {
- if (i != _requests.end() - 1)
- {
- GMX_THROW(InvalidInputError(
- formatString("Request for selection '%s' must "
- "not be followed by others",
- request.name.c_str())));
- }
- last = selections.end();
- }
- SelectionList curr(first, last);
- request.storage->addSelections(curr, true);
- first = last;
- }
- if (last != selections.end())
- {
- GMX_THROW(InvalidInputError("Too many selections provided"));
- }
-}
-
-
void SelectionCollection::Impl::resolveExternalGroups(
t_selelem *root, MessageStringCollector *errors)
{
}
-void
-SelectionCollection::parseRequestedFromStdin(bool bInteractive)
-{
- Impl::RequestsClearer clearRequestsOnExit(&_impl->_requests);
-
- Impl::RequestList::const_iterator i;
- for (i = _impl->_requests.begin(); i != _impl->_requests.end(); ++i)
- {
- const Impl::SelectionRequest &request = *i;
- if (bInteractive)
- {
- std::fprintf(stderr, "\nSpecify ");
- if (request.count() < 0)
- {
- std::fprintf(stderr, "any number of selections");
- }
- else if (request.count() == 1)
- {
- std::fprintf(stderr, "a selection");
- }
- else
- {
- std::fprintf(stderr, "%d selections", request.count());
- }
- std::fprintf(stderr, " for option '%s' (%s):\n",
- request.name.c_str(), request.descr.c_str());
- std::fprintf(stderr, "(one selection per line, 'help' for help%s)\n",
- request.count() < 0 ? ", Ctrl-D to end" : "");
- }
- SelectionList selections;
- parseFromStdin(request.count(), bInteractive, &selections);
- request.storage->addSelections(selections, true);
- }
-}
-
-
-void
-SelectionCollection::parseRequestedFromFile(const std::string &filename)
-{
- SelectionList selections;
- parseFromFile(filename, &selections);
- _impl->placeSelectionsInRequests(selections);
-}
-
-
-void
-SelectionCollection::parseRequestedFromString(const std::string &str)
-{
- SelectionList selections;
- parseFromString(str, &selections);
- _impl->placeSelectionsInRequests(selections);
-}
-
-
void
SelectionCollection::parseFromStdin(int nr, bool bInteractive,
SelectionList *output)
class Options;
class SelectionCompiler;
class SelectionEvaluator;
-class SelectionOptionStorage;
/*! \brief
* Collection of selections.
*
* After setting the default values, one or more selections can be parsed with
* one or more calls to parseFromStdin(), parseFromFile(), and/or
- * parseFromString(). parseRequestedFromStdin() and parseRequestedFromString()
- * are provided for integration with SelectionOption. After all selections are
- * parsed, the topology must be set with setTopology() unless
- * requiresTopology() returns false (the topology can also be set earlier).
+ * parseFromString(). After all selections are parsed, the topology must be
+ * set with setTopology() unless requiresTopology() returns false (the topology
+ * can also be set earlier).
* setIndexGroups() must also be called if external index group references are
* used in the selections; it can be called at any point before compile().
* Once all selections are parsed, they must be compiled all at once using
* called as setIndexGroups(NULL).
*/
void setIndexGroups(gmx_ana_indexgrps_t *grps);
- /*! \brief
- * Parses selection(s) from standard input for options not yet
- * provided.
- *
- * \param[in] bInteractive Whether the parser should behave
- * interactively.
- * \throws unspecified Can throw any exception thrown by
- * parseFromStdin().
- * \throws std::bad_alloc if out of memory.
- *
- * This method cooperates with SelectionOption to allow interactive
- * input of missing selections after all options have been processed.
- * It should be called after the Options::finish() method has been
- * called on all options that add selections to this collection.
- * For each required selection option that has not been given, as well
- * as for optional selection options that have been specified without
- * values, it will prompt the user to input the necessary selections.
- */
- void parseRequestedFromStdin(bool bInteractive);
- /*! \brief
- * Parses selection(s) from a file for options not yet provided.
- *
- * \param[in] filename Name of the file to parse selections from.
- * \throws unspecified Can throw any exception thrown by
- * parseFromFile().
- * \throws std::bad_alloc if out of memory.
- * \throws InvalidInputError if
- * - the number of selections in \p filename doesn't match the
- * number requested.
- * - any selection uses a feature that is not allowed for the
- * corresponding option.
- * - if there is a request for any number of selections that is
- * not the last (in which case it is not possible to determine
- * which selections belong to which request).
- *
- * This method behaves as parseRequestedFromStdin(), but reads the
- * selections from a file instead of standard input.
- * This is used to implement SelectionFileOption.
- *
- * \see parseRequestedFromStdin()
- */
- void parseRequestedFromFile(const std::string &filename);
- /*! \brief
- * Parses selection(s) from a string for options not yet provided.
- *
- * \param[in] str String to parse.
- * \throws unspecified Can throw any exception thrown by
- * parseFromString().
- * \throws std::bad_alloc if out of memory.
- * \throws InvalidInputError in same conditions as
- * parseRequestedFromFile().
- *
- * This method behaves as parseRequestedFromFile(), but reads the
- * selections from a string instead of a file.
- * This method is mainly used for testing.
- *
- * \see parseRequestedFromFile()
- */
- void parseRequestedFromString(const std::string &str);
/*! \brief
* Parses selection(s) from standard input.
*
* Needed for the evaluator to freely modify the collection.
*/
friend class SelectionEvaluator;
- /*! \brief
- * Needed for handling delayed selection parsing requests.
- */
- friend class SelectionOptionStorage;
};
} // namespace gmx
*
* This option is used internally by the command-line framework to implement
* file input for selections. The option takes a file name, and reads it in
- * using SelectionCollection::parseRequestedFromFile(). This means that
+ * using SelectionOptionManager::parseRequestedFromFile(). This means that
* selections from the file are assigned to selection options that have been
* explicitly provided without values earlier on the command line.
*
namespace gmx
{
-class SelectionCollection;
class SelectionFileOptionStorage;
+class SelectionOptionManager;
/*! \libinternal \brief
* Wrapper class for accessing and modifying selection file option information.
*/
explicit SelectionFileOptionInfo(SelectionFileOptionStorage *option);
- /*! \brief
- * Set selection collection into which this option adds selections.
- *
- * \param selections Selection collection to set.
- *
- * This must be called before values are added.
- *
- * Typically it is called through setSelectionCollectionForOptions(),
- * which recursively sets the collection for all selection options in
- * an Options object.
- *
- * Does not throw.
- */
- void setSelectionCollection(SelectionCollection *selections);
+ //! \copydoc SelectionOptionInfo::setManager()
+ void setManager(SelectionOptionManager *manager);
private:
SelectionFileOptionStorage &option();
namespace gmx
{
-class SelectionCollection;
class SelectionFileOption;
+class SelectionOptionManager;
/*! \internal \brief
* Implementation for a special option for reading selections from files.
virtual int valueCount() const { return 0; }
virtual std::string formatValue(int /*i*/) const { return ""; }
- //! \copydoc SelectionFileOptionInfo::setSelectionCollection()
- void setSelectionCollection(SelectionCollection *selections)
+ //! \copydoc SelectionFileOptionInfo::setManager()
+ void setManager(SelectionOptionManager *manager)
{
- sc_ = selections;
+ manager_ = manager;
}
private:
virtual void processAll() {}
SelectionFileOptionInfo info_;
- SelectionCollection *sc_;
+ SelectionOptionManager *manager_;
bool bValueParsed_;
};
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
+#include "gromacs/selection/selectionoptionmanager.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/messagestringcollector.h"
-#include "selectioncollection-impl.h"
#include "selectionfileoptionstorage.h"
#include "selectionoptionstorage.h"
SelectionOptionStorage::SelectionOptionStorage(const SelectionOption &settings)
: MyBase(settings, OptionFlags() | efNoDefaultValue | efDontCheckMinimumCount),
- _info(this), _sc(NULL), _selectionFlags(settings._selectionFlags)
+ info_(this), manager_(NULL), selectionFlags_(settings._selectionFlags)
{
GMX_RELEASE_ASSERT(!hasFlag(efMulti),
"allowMultiple() is not supported for selection options");
if (settings._infoPtr != NULL)
{
- *settings._infoPtr = &_info;
+ *settings._infoPtr = &info_;
}
}
{
// TODO: Having this check in the parser would make interactive input
// behave better.
- if (_selectionFlags.test(efOnlyStatic) && i->isDynamic())
+ if (selectionFlags_.test(efOnlyStatic) && i->isDynamic())
{
GMX_THROW(InvalidInputError("Dynamic selections not supported"));
}
void SelectionOptionStorage::convertValue(const std::string &value)
{
- GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
+ GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
SelectionList selections;
- _sc->parseFromString(value, &selections);
+ manager_->selectionCollection().parseFromString(value, &selections);
addSelections(selections, false);
}
void SelectionOptionStorage::processSetValues(ValueList *values)
{
- GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
+ GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
if (values->size() == 0)
{
- _sc->_impl->requestSelections(name(), description(), this);
+ manager_->requestDelayedParsing(this);
}
else if (values->size() < static_cast<size_t>(minValueCount()))
{
ValueList::iterator i;
for (i = values->begin(); i != values->end(); ++i)
{
- i->data().setFlags(_selectionFlags);
+ i->data().setFlags(selectionFlags_);
}
}
{
if (isRequired() && !isSet())
{
- GMX_RELEASE_ASSERT(_sc != NULL, "Selection collection is not set");
+ GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
- _sc->_impl->requestSelections(name(), description(), this);
+ manager_->requestDelayedParsing(this);
setFlag(efSet);
}
}
GMX_THROW(InvalidInputError(errors.toString()));
}
}
- _selectionFlags.set(flag, bSet);
+ selectionFlags_.set(flag, bSet);
for (i = values().begin(); i != values().end(); ++i)
{
- i->data().setFlags(_selectionFlags);
+ i->data().setFlags(selectionFlags_);
}
}
return static_cast<const SelectionOptionStorage &>(OptionInfo::option());
}
-void SelectionOptionInfo::setSelectionCollection(SelectionCollection *selections)
+void SelectionOptionInfo::setManager(SelectionOptionManager *manager)
{
- option().setSelectionCollection(selections);
+ option().setManager(manager);
}
void SelectionOptionInfo::setValueCount(int count)
SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
: AbstractOptionStorage(settings, OptionFlags() | efMulti | efDontCheckMinimumCount),
- info_(this), sc_(NULL), bValueParsed_(false)
+ info_(this), manager_(NULL), bValueParsed_(false)
{
}
void SelectionFileOptionStorage::convertValue(const std::string &value)
{
- GMX_RELEASE_ASSERT(sc_ != NULL, "Selection collection is not set");
+ GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
if (bValueParsed_)
{
}
bValueParsed_ = true;
// TODO: Should we throw an InvalidInputError if the file does not exist?
- sc_->parseRequestedFromFile(value);
+ manager_->parseRequestedFromFile(value);
}
void SelectionFileOptionStorage::processSet()
return static_cast<const SelectionFileOptionStorage &>(OptionInfo::option());
}
-void SelectionFileOptionInfo::setSelectionCollection(SelectionCollection *selections)
+void SelectionFileOptionInfo::setManager(SelectionOptionManager *manager)
{
- option().setSelectionCollection(selections);
+ option().setManager(manager);
}
{
/*! \internal \brief
- * Visitor that sets the selection collection for each selection option.
+ * Visitor that sets the manager for each selection option.
*
* \ingroup module_selection
*/
-class SelectionCollectionSetter : public OptionsModifyingVisitor
+class SelectionOptionManagerSetter : public OptionsModifyingVisitor
{
public:
- //! Construct a visitor that sets given selection collection.
- explicit SelectionCollectionSetter(SelectionCollection *selections)
- : selections_(selections)
+ //! Construct a visitor that sets given manager.
+ explicit SelectionOptionManagerSetter(SelectionOptionManager *manager)
+ : manager_(manager)
{
}
= option->toType<SelectionOptionInfo>();
if (selOption != NULL)
{
- selOption->setSelectionCollection(selections_);
+ selOption->setManager(manager_);
}
SelectionFileOptionInfo *selFileOption
= option->toType<SelectionFileOptionInfo>();
if (selFileOption != NULL)
{
- selFileOption->setSelectionCollection(selections_);
+ selFileOption->setManager(manager_);
}
}
private:
- SelectionCollection *selections_;
+ SelectionOptionManager *manager_;
};
} // namespace
-void setSelectionCollectionForOptions(Options *options,
- SelectionCollection *selections)
+void setManagerForSelectionOptions(Options *options,
+ SelectionOptionManager *manager)
{
- SelectionCollectionSetter(selections).visitSubSection(options);
+ SelectionOptionManagerSetter(manager).visitSubSection(options);
}
} // namespace gmx
{
class Options;
-class SelectionCollection;
+class SelectionOptionManager;
class SelectionOptionStorage;
/*! \brief
explicit SelectionOptionInfo(SelectionOptionStorage *option);
/*! \brief
- * Set selection collection into which this option adds selections.
+ * Set manager for handling interaction with other options and the
+ * selection collection.
*
- * \param selections Selection collection to set.
+ * \param manager Selection manager to set.
*
* This must be called before the values are added.
*
- * Typically it is called through setSelectionCollectionForOptions(),
- * which recursively sets the collection for all selection options in
+ * Typically it is called through setManagerForSelectionOptions(),
+ * which recursively sets the manager for all selection options in
* an Options object.
*
* Does not throw.
*/
- void setSelectionCollection(SelectionCollection *selections);
+ void setManager(SelectionOptionManager *manager);
/*! \brief
* Sets the number of selections allowed for the option.
};
/*! \brief
- * Set selection collection for all selection options.
+ * Set manager for all selection options.
*
- * Recursively sets the selection collection to \p selections for all selection
- * options in \p options.
+ * Recursively sets the manager to \p manager for all selection options in
+ * \p options.
* Must be called before value assignment starts for \p options.
*
* Does not throw.
*
* \inpublicapi
*/
-void setSelectionCollectionForOptions(Options *options,
- SelectionCollection *selections);
+void setManagerForSelectionOptions(Options *options,
+ SelectionOptionManager *manager);
} // namespace gmx
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * 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.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::SelectionOptionManager.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#include "selectionoptionmanager.h"
+
+#include <cstdio>
+
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/format.h"
+
+#include "selectionoptionstorage.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * SelectionOptionManager::Impl
+ */
+
+/*! \internal \brief
+ * Private implemention class for SelectionOptionManager.
+ *
+ * \ingroup module_selection
+ */
+class SelectionOptionManager::Impl
+{
+ public:
+ /*! \brief
+ * Request for postponed parsing of selections.
+ */
+ struct SelectionRequest
+ {
+ //! Initializes a request for the given option.
+ explicit SelectionRequest(SelectionOptionStorage *storage)
+ : storage_(storage)
+ {
+ }
+
+ //! Returns name of the requested selection optin.
+ const std::string &name() const
+ {
+ return storage_->name();
+ }
+ //! Returns description for the requested selection option.
+ const std::string &description() const
+ {
+ return storage_->description();
+ }
+ /*! \brief
+ * Returns the number of selections requested in this request.
+ *
+ * -1 indicates no upper limit.
+ */
+ int count() const
+ {
+ return storage_->maxValueCount();
+ }
+
+ //! Storage object to which the selections will be added.
+ SelectionOptionStorage *storage_;
+ };
+
+ //! Collection for a list of selection requests.
+ typedef std::vector<SelectionRequest> RequestList;
+
+ /*! \brief
+ * Helper class that clears a request list on scope exit.
+ *
+ * Methods in this class do not throw.
+ */
+ class RequestsClearer
+ {
+ public:
+ //! Constructs an object that clears given list on scope exit.
+ explicit RequestsClearer(RequestList *requests)
+ : requests_(requests)
+ {
+ }
+ //! Clears the request list given to the constructor.
+ ~RequestsClearer()
+ {
+ requests_->clear();
+ }
+
+ private:
+ RequestList *requests_;
+ };
+
+ /*! \brief
+ * Creates a new selection collection.
+ *
+ * \throws std::bad_alloc if out of memory.
+ */
+ explicit Impl(SelectionCollection *collection);
+
+ /*! \brief
+ * Assign selections from a list to pending requests.
+ *
+ * \param[in] selections List of selections to assign.
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if the assignment cannot be done
+ * (see parseRequestedFromFile() for documented conditions).
+ *
+ * Loops through \p selections and the pending requests lists in order,
+ * and for each requests, assigns the first yet unassigned selections
+ * from the list.
+ */
+ void placeSelectionsInRequests(const SelectionList &selections);
+
+ //! Selection collection to which selections are stored.
+ SelectionCollection &collection_;
+ //! List of selections requested for later parsing.
+ RequestList requests_;
+};
+
+SelectionOptionManager::Impl::Impl(SelectionCollection *collection)
+ : collection_(*collection)
+{
+}
+
+void SelectionOptionManager::Impl::placeSelectionsInRequests(
+ const SelectionList &selections)
+{
+ RequestsClearer clearRequestsOnExit(&requests_);
+
+ SelectionList::const_iterator first = selections.begin();
+ SelectionList::const_iterator last = first;
+ RequestList::const_iterator i;
+ // TODO: Improve error messages.
+ for (i = requests_.begin(); i != requests_.end(); ++i)
+ {
+ const SelectionRequest &request = *i;
+ if (request.count() > 0)
+ {
+ if (selections.end() - first < request.count())
+ {
+ GMX_THROW(InvalidInputError("Too few selections provided"));
+ }
+ last = first + request.count();
+ }
+ else
+ {
+ if (i != requests_.end() - 1)
+ {
+ GMX_THROW(InvalidInputError(
+ formatString("Request for selection '%s' must "
+ "not be followed by others",
+ request.name().c_str())));
+ }
+ last = selections.end();
+ }
+ SelectionList curr(first, last);
+ request.storage_->addSelections(curr, true);
+ first = last;
+ }
+ if (last != selections.end())
+ {
+ GMX_THROW(InvalidInputError("Too many selections provided"));
+ }
+}
+
+
+/********************************************************************
+ * SelectionOptionManager
+ */
+
+SelectionOptionManager::SelectionOptionManager(SelectionCollection *collection)
+ : impl_(new Impl(collection))
+{
+}
+
+SelectionOptionManager::~SelectionOptionManager()
+{
+}
+
+SelectionCollection &
+SelectionOptionManager::selectionCollection()
+{
+ return impl_->collection_;
+}
+
+void
+SelectionOptionManager::requestDelayedParsing(SelectionOptionStorage *storage)
+{
+ impl_->requests_.push_back(Impl::SelectionRequest(storage));
+}
+
+void
+SelectionOptionManager::parseRequestedFromStdin(bool bInteractive)
+{
+ Impl::RequestsClearer clearRequestsOnExit(&impl_->requests_);
+
+ Impl::RequestList::const_iterator i;
+ for (i = impl_->requests_.begin(); i != impl_->requests_.end(); ++i)
+ {
+ const Impl::SelectionRequest &request = *i;
+ if (bInteractive)
+ {
+ std::fprintf(stderr, "\nSpecify ");
+ if (request.count() < 0)
+ {
+ std::fprintf(stderr, "any number of selections");
+ }
+ else if (request.count() == 1)
+ {
+ std::fprintf(stderr, "a selection");
+ }
+ else
+ {
+ std::fprintf(stderr, "%d selections", request.count());
+ }
+ std::fprintf(stderr, " for option '%s' (%s):\n",
+ request.name().c_str(), request.description().c_str());
+ std::fprintf(stderr, "(one selection per line, 'help' for help%s)\n",
+ request.count() < 0 ? ", Ctrl-D to end" : "");
+ }
+ SelectionList selections;
+ impl_->collection_.parseFromStdin(request.count(), bInteractive, &selections);
+ request.storage_->addSelections(selections, true);
+ }
+}
+
+void
+SelectionOptionManager::parseRequestedFromFile(const std::string &filename)
+{
+ SelectionList selections;
+ impl_->collection_.parseFromFile(filename, &selections);
+ impl_->placeSelectionsInRequests(selections);
+}
+
+void
+SelectionOptionManager::parseRequestedFromString(const std::string &str)
+{
+ SelectionList selections;
+ impl_->collection_.parseFromString(str, &selections);
+ impl_->placeSelectionsInRequests(selections);
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * 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.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::SelectionOptionManager.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONOPTIONMANAGER_H
+#define GMX_SELECTION_SELECTIONOPTIONMANAGER_H
+
+#include <string>
+
+#include "../utility/common.h"
+
+namespace gmx
+{
+
+class SelectionCollection;
+class SelectionOptionStorage;
+
+/*! \brief
+ * Handles interaction of selection options with other options and user input.
+ *
+ * This class implements features of SelectionOption that require actions
+ * outside options parsing. It is also used to pass the selection collection
+ * to the selection options, and to implement the coupling between
+ * SelectionOption and SelectionFileOption.
+ *
+ * The main feature of this class (in addition to passing the
+ * selectionCollection() method) is that the internal implementation of
+ * selection options calls requestDelayedParsing() when an option is provided
+ * on the command line without a value. Such calls are remembered, and
+ * the value for all requested options can be later provided by calling one of
+ * parseRequestedFromStdin(), parseRequestedFromFile() or
+ * parseRequstedFromString().
+ *
+ * \see setManagerForSelectionOptions()
+ *
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+class SelectionOptionManager
+{
+ public:
+ /*! \brief
+ * Creates a manager for selection options.
+ *
+ * \throws std::bad_alloc if out of memory.
+ */
+ explicit SelectionOptionManager(SelectionCollection *selections);
+ ~SelectionOptionManager();
+
+ /*! \brief
+ * Returns the selection collection for this manager.
+ *
+ * Does not throw.
+ */
+ SelectionCollection &selectionCollection();
+ /*! \brief
+ * Adds a selection option for delayed user input.
+ *
+ * \param storage Storage object for the option to request.
+ * \throws std::bad_alloc if out of memory.
+ *
+ * This is only for internal use by the selection module.
+ * It is not possible to obtain a SelectionOptionStorage pointer
+ * through any public or library API.
+ *
+ * Strong exception safety.
+ */
+ void requestDelayedParsing(SelectionOptionStorage *storage);
+
+ /*! \brief
+ * Parses selection(s) from standard input for options not yet
+ * provided.
+ *
+ * \param[in] bInteractive Whether the parser should behave
+ * interactively.
+ * \throws unspecified Can throw any exception thrown by
+ * SelectionCollection::parseFromStdin().
+ * \throws std::bad_alloc if out of memory.
+ *
+ * This method cooperates with SelectionOption to allow interactive
+ * input of requested selections after all options have been processed.
+ * It should be called after the Options::finish() method has been
+ * called on all options that add selections to this collection.
+ * For each required selection option that has not been given, as well
+ * as for optional selection options that have been specified without
+ * values, it will prompt the user to input the necessary selections.
+ */
+ void parseRequestedFromStdin(bool bInteractive);
+ /*! \brief
+ * Parses selection(s) from a file for options not yet provided.
+ *
+ * \param[in] filename Name of the file to parse selections from.
+ * \throws unspecified Can throw any exception thrown by
+ * SelectionCollection::parseFromFile().
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError if
+ * - the number of selections in \p filename doesn't match the
+ * number requested.
+ * - any selection uses a feature that is not allowed for the
+ * corresponding option.
+ * - if there is a request for any number of selections that is
+ * not the last (in which case it is not possible to determine
+ * which selections belong to which request).
+ *
+ * This method behaves as parseRequestedFromStdin(), but reads the
+ * selections from a file instead of standard input.
+ * This is used to implement SelectionFileOption.
+ *
+ * \see parseRequestedFromStdin()
+ */
+ void parseRequestedFromFile(const std::string &filename);
+ /*! \brief
+ * Parses selection(s) from a string for options not yet provided.
+ *
+ * \param[in] str String to parse.
+ * \throws unspecified Can throw any exception thrown by
+ * SelectionCollection::parseFromString().
+ * \throws std::bad_alloc if out of memory.
+ * \throws InvalidInputError in same conditions as
+ * parseRequestedFromFile().
+ *
+ * This method behaves as parseRequestedFromFile(), but reads the
+ * selections from a string instead of a file.
+ * This method is mainly used for testing.
+ *
+ * \see parseRequestedFromFile()
+ */
+ void parseRequestedFromString(const std::string &str);
+
+ private:
+ class Impl;
+
+ PrivateImplPointer<Impl> impl_;
+
+ /*! \brief
+ * Needed for handling delayed selection parsing requests.
+ */
+ friend class SelectionOptionStorage;
+};
+
+} // namespace gmx
+
+#endif
namespace gmx
{
-class SelectionCollection;
class SelectionOption;
+class SelectionOptionManager;
/*! \internal \brief
* Converts, validates, and stores selection values.
*/
SelectionOptionStorage(const SelectionOption &settings);
- virtual OptionInfo &optionInfo() { return _info; }
+ virtual OptionInfo &optionInfo() { return info_; }
virtual const char *typeString() const { return "sel"; }
virtual std::string formatSingleValue(const Selection &value) const;
- //! \copydoc SelectionOptionInfo::setSelectionCollection()
- void setSelectionCollection(SelectionCollection *selections)
+ //! \copydoc SelectionOptionInfo::setManager()
+ void setManager(SelectionOptionManager *manager)
{
- _sc = selections;
+ manager_ = manager;
}
/*! \brief
* - Any selection in \p selections is not allowed for this
* option.
*
- * This function is used to implement the methods
- * SelectionCollection::parseRequestedFromStdin() and
- * SelectionCollection::parseRequestedFromString() (called with
- * \p bFullValue set to true), as well as internally by the storage
- * class (called with \p bFullValue set to false).
+ * This function is used to add selections from SelectionOptionManager
+ * (called with \p bFullValue set to true), as well as internally by
+ * the storage class (called with \p bFullValue set to false).
*/
void addSelections(const SelectionList &selections,
bool bFullValue);
virtual void processSetValues(ValueList *values);
virtual void processAll();
- SelectionOptionInfo _info;
- SelectionCollection *_sc;
- SelectionFlags _selectionFlags;
+ SelectionOptionInfo info_;
+ SelectionOptionManager *manager_;
+ SelectionFlags selectionFlags_;
};
} // namespace gmx
#include "gromacs/options/optionsassigner.h"
#include "gromacs/selection/selection.h"
#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoption.h"
#include "gromacs/selection/selectionoptioninfo.h"
-#include "gromacs/selection/selectionfileoption.h"
+#include "gromacs/selection/selectionoptionmanager.h"
#include "gromacs/utility/exceptions.h"
#include "testutils/datapath.h"
public:
SelectionOptionTestBase();
- void setCollection();
+ void setManager();
- gmx::SelectionCollection _sc;
- gmx::Options _options;
+ gmx::SelectionCollection _sc;
+ gmx::SelectionOptionManager _manager;
+ gmx::Options _options;
};
SelectionOptionTestBase::SelectionOptionTestBase()
- : _options(NULL, NULL)
+ : _manager(&_sc), _options(NULL, NULL)
{
_sc.setReferencePosType("atom");
_sc.setOutputPosType("atom");
}
-void SelectionOptionTestBase::setCollection()
+void SelectionOptionTestBase::setManager()
{
- setSelectionCollectionForOptions(&_options, &_sc);
+ setManagerForSelectionOptions(&_options, &_manager);
}
gmx::Selection sel;
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(SelectionOption("sel").store(&sel)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").store(&sel).onlyStatic()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
gmx::Selection sel;
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(SelectionOption("sel").store(&sel)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").store(sel).valueCount(2)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()
.getAdjuster(&info)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").store(&sel)
.getAdjuster(&info)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()
.getAdjuster(&info)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()
.getAdjuster(&info)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").store(&sel).required()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
EXPECT_NO_THROW(assigner.finish());
EXPECT_NO_THROW(_options.finish());
- EXPECT_NO_THROW(_sc.parseRequestedFromString("resname RA RB"));
+ EXPECT_NO_THROW(_manager.parseRequestedFromString("resname RA RB"));
ASSERT_STREQ("resname RA RB", sel.selectionText());
}
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").store(sel).required()
.valueCount(2)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
EXPECT_NO_THROW(assigner.finish());
EXPECT_NO_THROW(_options.finish());
- EXPECT_THROW(_sc.parseRequestedFromString("resname RA RB"), gmx::InvalidInputError);
+ EXPECT_THROW(_manager.parseRequestedFromString("resname RA RB"), gmx::InvalidInputError);
}
gmx::Selection sel;
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(SelectionOption("sel").store(&sel)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
EXPECT_NO_THROW(assigner.finishOption());
EXPECT_NO_THROW(assigner.finish());
EXPECT_NO_THROW(_options.finish());
- EXPECT_NO_THROW(_sc.parseRequestedFromString("resname RA RB"));
+ EXPECT_NO_THROW(_manager.parseRequestedFromString("resname RA RB"));
ASSERT_STREQ("resname RA RB", sel.selectionText());
}
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).valueCount(3)
.getAdjuster(&info)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
EXPECT_NO_THROW(assigner.finish());
EXPECT_NO_THROW(_options.finish());
EXPECT_NO_THROW(info->setValueCount(2));
- EXPECT_NO_THROW(_sc.parseRequestedFromString("resname RA RB; resname RB RC"));
+ EXPECT_NO_THROW(_manager.parseRequestedFromString("resname RA RB; resname RB RC"));
}
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
SelectionOption("sel1").storeVector(&sel1).multiValue()));
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel2").storeVector(&sel2).multiValue()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
std::string value(gmx::test::getTestFilePath("selfile.dat"));
SelectionOption("sel1").storeVector(&sel1)));
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel2").storeVector(&sel2)));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
std::string value(gmx::test::getTestFilePath("selfile.dat"));
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
using gmx::SelectionOption;
ASSERT_NO_THROW(_options.addOption(
SelectionOption("sel").storeVector(&sel).multiValue()));
- setCollection();
+ setManager();
gmx::OptionsAssigner assigner(&_options);
EXPECT_NO_THROW(assigner.start());
#include "gromacs/options/options.h"
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionoptioninfo.h"
+#include "gromacs/selection/selectionoptionmanager.h"
#include "gromacs/trajectoryanalysis/analysismodule.h"
#include "gromacs/trajectoryanalysis/analysissettings.h"
#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
bool parseOptions(TrajectoryAnalysisSettings *settings,
TrajectoryAnalysisRunnerCommon *common,
SelectionCollection *selections,
+ SelectionOptionManager *seloptManager,
Options *options,
int *argc, char *argv[]);
TrajectoryAnalysisSettings *settings,
TrajectoryAnalysisRunnerCommon *common,
SelectionCollection *selections,
+ SelectionOptionManager *seloptManager,
Options *options,
int *argc, char *argv[])
{
options->addSubSection(&selectionOptions);
options->addSubSection(&moduleOptions);
- setSelectionCollectionForOptions(options, selections);
+ setManagerForSelectionOptions(options, seloptManager);
{
CommandLineParser parser(options);
// TODO: Check whether the input is a pipe.
bool bInteractive = true;
- selections->parseRequestedFromStdin(bInteractive);
+ seloptManager->parseRequestedFromStdin(bInteractive);
common->doneIndexGroups(selections);
return true;
SelectionCollection selections;
selections.setDebugLevel(_impl->_debugLevel);
+ SelectionOptionManager seloptManager(&selections);
TrajectoryAnalysisSettings settings;
TrajectoryAnalysisRunnerCommon common(&settings);
Options options(NULL, NULL);
- if (!_impl->parseOptions(&settings, &common, &selections, &options,
- &argc, argv))
+ if (!_impl->parseOptions(&settings, &common, &selections, &seloptManager,
+ &options, &argc, argv))
{
return 0;
}