diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/AlgorithmFactory.h b/Code/Mantid/Framework/API/inc/MantidAPI/AlgorithmFactory.h index 2a9d43cbe57e999a742bf56009562d35903fa9d0..9762c2995a48697e4a4e8d1cbf072635d0dfbf32 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/AlgorithmFactory.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/AlgorithmFactory.h @@ -125,6 +125,9 @@ public: /// Get the algorithm names and version - mangled use decodeName to separate const std::vector<std::string> getKeys() const; const std::vector<std::string> getKeys(bool includeHidden) const; + + /// Returns the highest version of the algorithm currently registered + int highestVersion(const std::string & algorithmName) const; ///Get the algorithm categories const std::set<std::string> getCategories(bool includeHidden=false) const; diff --git a/Code/Mantid/Framework/API/src/AlgorithmFactory.cpp b/Code/Mantid/Framework/API/src/AlgorithmFactory.cpp index 152a3215f4226d713921a999ee34eab1d876bbaa..79b39269797f1e9143f974e115d1245056a9ee18 100644 --- a/Code/Mantid/Framework/API/src/AlgorithmFactory.cpp +++ b/Code/Mantid/Framework/API/src/AlgorithmFactory.cpp @@ -227,6 +227,21 @@ namespace Mantid } } + /** + * @param algorithmName The name of an algorithm registered with the factory + * @return An integer corresponding to the highest version registered + * @throw std::invalid_argument if the algorithm cannot be found + */ + int AlgorithmFactoryImpl::highestVersion(const std::string &algorithmName) const + { + VersionMap::const_iterator viter = m_vmap.find(algorithmName); + if(viter != m_vmap.end()) return viter->second; + else + { + throw std::invalid_argument("AlgorithmFactory::highestVersion() - Unknown algorithm '" + algorithmName + "'"); + } + } + /** * Return the categories of the algorithms. This includes those within the Factory itself and * any cleanly constructed algorithms stored here. diff --git a/Code/Mantid/Framework/API/test/AlgorithmFactoryTest.h b/Code/Mantid/Framework/API/test/AlgorithmFactoryTest.h index 34806408aee43fbfe9316d1e031ef7a64174e217..1314ee8fc8fa2eedb5f9f9a769910e90499f4d62 100644 --- a/Code/Mantid/Framework/API/test/AlgorithmFactoryTest.h +++ b/Code/Mantid/Framework/API/test/AlgorithmFactoryTest.h @@ -106,6 +106,23 @@ public: TS_ASSERT_THROWS_NOTHING(keys = AlgorithmFactory::Instance().getKeys()); TS_ASSERT_EQUALS(noOfAlgs - 1, keys.size()); } + + void test_HighestVersion() + { + auto & factory = AlgorithmFactory::Instance(); + + TS_ASSERT_THROWS(factory.highestVersion("ToyAlgorithm"), std::invalid_argument); + + AlgorithmFactory::Instance().subscribe<ToyAlgorithm>(); + TS_ASSERT_EQUALS(1, factory.highestVersion("ToyAlgorithm")); + + Mantid::Kernel::Instantiator<ToyAlgorithmTwo, Algorithm>* newTwo = new Mantid::Kernel::Instantiator<ToyAlgorithmTwo, Algorithm>; + AlgorithmFactory::Instance().subscribe(newTwo); + TS_ASSERT_EQUALS(2, factory.highestVersion("ToyAlgorithm")); + + AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm",1); + AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm",2); + } void testCreate() { @@ -201,4 +218,4 @@ public: }; -#endif \ No newline at end of file +#endif diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp index 4b9b34ab283c7fd4f8551e208aa38485ff6eb6cf..12bfc84afbc68a1900b0a1214a4e3ef48a9e81fd 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AlgorithmFactory.cpp @@ -112,7 +112,8 @@ void export_AlgorithmFactory() "Returns true if the given algorithm exists with an option to specify the version")) .def("getRegisteredAlgorithms", &getRegisteredAlgorithms, "Returns a Python dictionary of currently registered algorithms") - + .def("highestVersion", &AlgorithmFactoryImpl::highestVersion, + "Returns the highest version of the named algorithm. Throws ValueError if no algorithm can be found") .def("subscribe", &subscribe, "Register a Python class derived from PythonAlgorithm into the factory") .def("Instance", &AlgorithmFactory::Instance, return_value_policy<reference_existing_object>(), diff --git a/Code/Mantid/MantidPlot/mantidplot.py b/Code/Mantid/MantidPlot/mantidplot.py index 3468089e37f7434f446cee3de258a03d1a6e23fb..663ac35bd24fbbda6e939a589ad5af69b91def65 100644 --- a/Code/Mantid/MantidPlot/mantidplot.py +++ b/Code/Mantid/MantidPlot/mantidplot.py @@ -915,13 +915,17 @@ def screenshot_to_dir(widget, filename, screenshot_dir): @param filename :: Destination filename for that image @param screenshot_dir :: Directory to put the screenshots into. """ - # Find the widget if handled with a proxy + # Find the widget if handled with a proxy if hasattr(widget, "_getHeldObject"): widget = widget._getHeldObject() if widget is not None: camera = Screenshot() - threadsafe_call(camera.take_picture, widget, os.path.join(screenshot_dir, filename+".png")) + imgpath = os.path.join(screenshot_dir, filename) + threadsafe_call(camera.take_picture, widget, imgpath) + return imgpath + else: + raise RuntimeError("Unable to retrieve widget. Has it been deleted?") #============================================================================= diff --git a/Code/Mantid/MantidPlot/test/MantidPlotAlgorithmDialogTest.py b/Code/Mantid/MantidPlot/test/MantidPlotAlgorithmDialogTest.py index 4d612a3407afb13d5260390838b545d50bee453e..3bb0da5fca89f43389649e2f42c6d28d952f92e7 100644 --- a/Code/Mantid/MantidPlot/test/MantidPlotAlgorithmDialogTest.py +++ b/Code/Mantid/MantidPlot/test/MantidPlotAlgorithmDialogTest.py @@ -23,10 +23,10 @@ class MantidPlotAlgorithmDialogTest(unittest.TestCase): interface_manager = mantidqtpython.MantidQt.API.InterfaceManager() dialog = threadsafe_call( interface_manager.createDialogFromName, self.__target_algorithm__, self.__clean_properties__) screenshotdir = tempfile.gettempdir(); - file = "CreateMDWorkspace_screenshot" - screenshot_to_dir(widget=dialog, filename=file, screenshot_dir=screenshotdir) + filename = "CreateMDWorkspace_screenshot.png" + screenshot_to_dir(widget=dialog, filename=filename, screenshot_dir=screenshotdir) threadsafe_call(dialog.close) - file_abs = os.path.join(screenshotdir, file + ".png") + file_abs = os.path.join(screenshotdir, filename) file_exists = os.path.isfile(file_abs) self.assertEquals(file_exists, True, "Screenshot was not written out as expected.") if file_exists: diff --git a/Code/Mantid/docs/CMakeLists.txt b/Code/Mantid/docs/CMakeLists.txt index 6bb594dc56c88bdf9c24571520361d41cff8a152..e9dac87df73b2354c41fe1169b2dc138ad19dd06 100644 --- a/Code/Mantid/docs/CMakeLists.txt +++ b/Code/Mantid/docs/CMakeLists.txt @@ -1,3 +1,41 @@ +############################################################################### +# Sphinx documentation +############################################################################### +find_package ( Sphinx ) + +if ( SPHINX_FOUND ) + # We generate a target per build type, i.e docs-html, docs-test + set ( SPHINX_BUILD_DIR ${CMAKE_BINARY_DIR}/docs ) + set ( SCREENSHOTS_DIR ${SPHINX_BUILD_DIR}/screenshots ) + + # targets + set ( TARGET_PREFIX docs) + # runner - default=current build + set ( DOCS_RUNNER_EXE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/MantidPlot CACHE FILEPATH + "MantidPlot executable to use to build the documentation" ) + + # HTML target + set ( BUILDER html ) + configure_file ( runsphinx.py.in runsphinx_html.py @ONLY ) + add_custom_target ( ${TARGET_PREFIX}-html + COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_html.py + COMMENT "Building html documentation" + ) + + # doctest target + set ( BUILDER doctest ) + configure_file ( runsphinx.py.in runsphinx_doctest.py @ONLY ) + add_custom_target ( ${TARGET_PREFIX}-test + COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_doctest.py + COMMENT "Running documentation tests" + ) + +endif () + + +############################################################################### +# QtAssistant +############################################################################### if ( APPLE ) set ( ENABLE_QTASSISTANT False CACHE BOOL "Build qt-assistant documentation" ) else () diff --git a/Code/Mantid/docs/DocumentationStyleGuide.rst b/Code/Mantid/docs/DocumentationStyleGuide.rst new file mode 100644 index 0000000000000000000000000000000000000000..7d171234020f20c5fe31fd59646120cc9f4db7cb --- /dev/null +++ b/Code/Mantid/docs/DocumentationStyleGuide.rst @@ -0,0 +1,11 @@ +========================= +Documentation Style Guide +========================= + +This guide describes the formatting that should be followed when documenting Mantid functionality. The documentation is built using `Sphinx <http://sphinx.pocoo.org/>` and when using Sphinx most of what you type is reStructuredText. For more information on reStructeredText see: + +* https://pythonhosted.org/an_example_pypi_project/sphinx.html +* http://docutils.sourceforge.net/rst.html +* http://docutils.sourceforge.net/docs/user/rst/quickref.html +* http://docutils.sourceforge.net/docs/user/rst/cheatsheet.txt + diff --git a/Code/Mantid/docs/README.md b/Code/Mantid/docs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..393d032b3b2a928f34481aecb7a42d042a300908 --- /dev/null +++ b/Code/Mantid/docs/README.md @@ -0,0 +1,16 @@ +The Mantid documentation is written in [reStructuredText](http://docutils.sourceforge.net/rst.html) and processed using [Sphinx](http://sphinx.pocoo.org/). It uses a custom +boostrap theme for Sphinx and both are required to build the documentation. + +To install Sphinx and the bootstrap theme use `easy_install`: + + easy_install -U Sphinx + easy_install -U sphinx-bootstrap-theme + +or `pip`: + + pip install Sphinx + pip install sphinx-bootstrap-theme + +This may require admin privileges on some environments. + +CMake produces a `docs-html` target that is used to build the documentation. The output files will appear in a `html` sub directory of the main `build/docs` directory. \ No newline at end of file diff --git a/Code/Mantid/docs/runsphinx.py.in b/Code/Mantid/docs/runsphinx.py.in new file mode 100644 index 0000000000000000000000000000000000000000..45724dc86fe3273e6a7c5c727fff91ff314fe28a --- /dev/null +++ b/Code/Mantid/docs/runsphinx.py.in @@ -0,0 +1,25 @@ +"""We need to run Sphinx inside MantidPlot to document the internal + module. This script calls the sphinx entry point with the necessary + arguments +""" + +__requires__ = 'Sphinx' +import sys +import os +from pkg_resources import load_entry_point + +mantidplot = "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/MantidPlot" +builder = "@BUILDER@" +src_dir = "@CMAKE_CURRENT_SOURCE_DIR@/source" +screenshots_dir = "@SCREENSHOTS_DIR@" +output_dir = os.path.join("@SPHINX_BUILD_DIR@", builder) + +# set environment +os.environ["SCREENSHOTS_DIR"] = screenshots_dir +# fake the sys args +argv = [mantidplot,'-b', builder, src_dir, output_dir] +if __name__ == '__main__': + sys.exit( + load_entry_point(__requires__, 'console_scripts', 'sphinx-build')(argv) + ) + diff --git a/Code/Mantid/docs/source/_static/custom.css b/Code/Mantid/docs/source/_static/custom.css new file mode 100644 index 0000000000000000000000000000000000000000..e7fe0571614f2caa26802b66dde8686f08f80c70 --- /dev/null +++ b/Code/Mantid/docs/source/_static/custom.css @@ -0,0 +1,76 @@ +/*-------------------- $GENERAL --------------------*/ + +#table-of-contents { border: none; } + +/*-------------------- $NAV --------------------*/ + +.navbar-version { display: none; } + +/*-------------------- $LINKS --------------------*/ + +a { + color: #009933; + text-decoration: none; +} + +a:hover { + color: #009933; + text-decoration: underline; +} + +/*-------------------- $SPACING --------------------*/ + +body { font-size: 1.6em; } /* 16px */ +dl dd { margin: .5em 0 .5em 1.6em; } +h1,h2 { margin-bottom: .5em; } + +/*-------------------- $IMAGES --------------------*/ + +.figure { + border: 1px solid #CCC; + padding: 10px 10px 0 10px; + background-color: whiteSmoke; + text-align: center; + width: 300px; + float: right; +} + +.screenshot { + height: 240px; + padding-bottom: 1em; +} + +.figure { margin: 0; } + +/*-------------------- $TABLES --------------------*/ + +table { + width: 100%; + border-collapse: collapse; + margin: 1.6em 0; +} + +/* Zebra striping */ +tr:nth-of-type(odd) { background: white; } + +tr:hover { background-color: whiteSmoke; } + +th { + background: #E0DFDE; + font-size: 1.3em; +} + +td, th { + padding: .75em; + border: 1px solid #CCC; + text-align: left; +} + +/*-------------------- $MEDIA-QUERIES --------------------*/ + +@media (min-width: 1200px) { + #table-of-contents { + width: auto; + max-width: 40%; + } +} diff --git a/Code/Mantid/docs/source/_templates/category.html b/Code/Mantid/docs/source/_templates/category.html new file mode 100644 index 0000000000000000000000000000000000000000..0d9249d9b59bcd348ed544ca2e253de6e60e9dde --- /dev/null +++ b/Code/Mantid/docs/source/_templates/category.html @@ -0,0 +1,43 @@ +{# Generates a better view for category pages #} + +{% extends "layout.html" %} + +{% macro split_to_three_columns(item_list) -%} +{# Split list into 3 columns #} +{# Uses bootstrap col-md-4 for each column along with slice(3) to divide input list #} +{# It currently assumes the items in the list are mantiddoc.directives.categories.PageRef classes #} + <div class="row"> + {%- for column in item_list|slice(3) %} + <div class="col-md-4"> + {%- set first = True %} + {%- for item in column %} + {%- if (item.name[0] != section or first) %} + {%- set section = item.name[0] %} + {%- if first != true %} + </ul> + {%- endif %} + <h3 style="font-weight:bold">{{ section }}</h3> + <ul> + {%- endif %} + <li><a href="{{ item.html_link() }}">{{ item.name }}</a></li> + {%- set first = False -%} + {%- endfor -%} + </ul> + </div> + {%- endfor -%} + </div> +{%- endmacro %} + +{%- block body -%} + <h1> Category: {{ title }} </h1> + {% if subcategories %} + <br> + <h2> Subcategories </h2> + {{ split_to_three_columns(subcategories) }} + <hr> + {% endif %} + + <h2> Pages </h2> + {{ split_to_three_columns(pages) }} + +{%- endblock -%} \ No newline at end of file diff --git a/Code/Mantid/docs/source/_templates/globaltoc.html b/Code/Mantid/docs/source/_templates/globaltoc.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Code/Mantid/docs/source/_templates/layout.html b/Code/Mantid/docs/source/_templates/layout.html new file mode 100644 index 0000000000000000000000000000000000000000..6f66bf7ba4d5ec6299064246b8142d627fd01cb1 --- /dev/null +++ b/Code/Mantid/docs/source/_templates/layout.html @@ -0,0 +1,4 @@ +{% extends "!layout.html" %} + +{# Custom CSS overrides #} +{% set bootswatch_css_custom = ['_static/custom.css'] %} diff --git a/Code/Mantid/docs/source/_templates/navbar.html b/Code/Mantid/docs/source/_templates/navbar.html new file mode 100644 index 0000000000000000000000000000000000000000..bf3b51f08e01afd38b7faf8c684c266979146384 --- /dev/null +++ b/Code/Mantid/docs/source/_templates/navbar.html @@ -0,0 +1,8 @@ +{% extends "!navbar.html" %} + +{%- block sidebarlogo %} +{%- if logo -%} + <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo" width=113 height=24/></a> +{%- endif %} +{%- endblock -%} + diff --git a/Code/Mantid/docs/source/_templates/redirect.html b/Code/Mantid/docs/source/_templates/redirect.html new file mode 100644 index 0000000000000000000000000000000000000000..e73ecf33d325c754c9507041d2c4702bd03c5689 --- /dev/null +++ b/Code/Mantid/docs/source/_templates/redirect.html @@ -0,0 +1,15 @@ +<!DOCTYPE HTML> +<html lang="en-US"> +<head> + <meta charset="UTF-8"> + <meta http-equiv="refresh" content="1;{{ target }}"> + <script type="text/javascript"> + window.location.href = "{{ target }}" + </script> + <title>Page Redirection</title> +</head> +<body> + <!-- Note: don't tell people to `click` the link, just tell them that it is a link. --> + If you are not redirected automatically, follow the <a href="{{ target }}">link to {{ name }}</a> +</body> +</html> \ No newline at end of file diff --git a/Code/Mantid/docs/source/conf.py b/Code/Mantid/docs/source/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..ea20dcc36f4a3410e03cde8f03f89dc9b0b5889f --- /dev/null +++ b/Code/Mantid/docs/source/conf.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import sphinx_bootstrap_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../sphinxext')) + +# -- General configuration ------------------------------------------------ + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.pngmath', + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.doctest', + 'mantiddoc.directives' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'MantidProject' +copyright = u'2014, Mantid' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.01' +# The full version, including alpha/beta/rc tags. +release = '0.01' + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'bootstrap' + +# Theme-specific options to customize the look and feel of a theme. +# We config the bootstrap settings here, and apply CSS changes in +# custom.css rather than here. +html_theme_options = { + # Navigation bar title. + 'navbar_title': " ", # deliberate single space so it's not visible + # Tab name for entire site. + 'navbar_site_name': "Mantid", + # Add links to the nav bar. Second param of tuple is true to create absolute url. + 'navbar_links': [ + ("Home", "/"), + ("Download", "http://download.mantidproject.org", True), + ("Documentation", "/documentation"), + ("Contact Us", "/contact-us"), + ], + # Do not show the "Show source" button. + 'source_link_position': "no", + # Remove the local TOC from the nav bar + 'navbar_pagenav': False, + # Hide the next/previous in the nav bar. + 'navbar_sidebarrel': False, + # Use the latest version. + 'bootstrap_version': "3", + # Ensure the nav bar always stays on top of page. + 'navbar_fixed_top': "true", +} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = os.path.relpath('../../Images/Mantid_Logo_Transparent_Cropped.png') + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Hide the Sphinx usage as we reference it on github instead. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = True diff --git a/Code/Mantid/docs/source/images/.gitignore b/Code/Mantid/docs/source/images/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b15bc0b3837deb97429074556e4d122be46497f1 --- /dev/null +++ b/Code/Mantid/docs/source/images/.gitignore @@ -0,0 +1 @@ +screenshots/* diff --git a/Code/Mantid/docs/source/images/README.md b/Code/Mantid/docs/source/images/README.md new file mode 100644 index 0000000000000000000000000000000000000000..74c28ac24b7918dcfc6a14366e656eebebf2b342 --- /dev/null +++ b/Code/Mantid/docs/source/images/README.md @@ -0,0 +1,3 @@ +Contains images for the documentation + +The algorithm screenshots are automatically generated into a `screenshots` subdirectory and this subdirectory has been added to the `.gitignore` in this directory diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..10dcf75288c50ec1edebb57d67a5508b42cb34f5 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py @@ -0,0 +1,23 @@ +""" + Defines custom directives for Mantid documentation + + Each directive should be defined in a different module and have its own + setup(app) function. The setup function defined here is used to tie them + all together in the case where all directives are required, allowing + 'mantiddoc.directives' to be added to the Sphinx extensions configuration. +""" + +import algorithm, aliases, categories, properties, summary + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + algorithm.setup(app) + aliases.setup(app) + categories.setup(app) + properties.setup(app) + summary.setup(app) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py new file mode 100644 index 0000000000000000000000000000000000000000..ec14e58566f4ab8ee2aadc13fb06fd52b785e08f --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/algorithm.py @@ -0,0 +1,226 @@ +from base import BaseDirective +from docutils import nodes +from sphinx.locale import _ +from sphinx.util.compat import make_admonition +import os +import re + +REDIRECT_TEMPLATE = "redirect.html" + +DEPRECATE_USE_ALG_RE = re.compile(r'Use\s([A-Z][a-zA-Z0-9]+)\sinstead') + +#-------------------------------------------------------------------------- +class AlgorithmDirective(BaseDirective): + + """ + Inserts details of an algorithm by querying Mantid + + Adds: + - A referenceable link for use with Sphinx ":ref:`` tags". If this is + the highest version of the algorithm being processed then a both + a versioned link is created and a non-versioned link + - A title + - A screenshot of the algorithm + - Table of contents + + If the algorithms is deprecated then a warning is inserted. + + It requires a SCREENSHOTS_DIR environment variable to be set to the + directory where a screenshot should be generated. If it is not set then + a RuntimeError occurs + """ + + required_arguments, optional_arguments = 0, 0 + + def run(self): + """ + Called by Sphinx when the ..algorithm:: directive is encountered + """ + self._track_algorithm() + + self._insert_reference_link() + self._insert_pagetitle() + imgpath = self._create_screenshot() + self._insert_screenshot_link(imgpath) + self._insert_toc() + self._insert_deprecation_warning() + + self.commit_rst() + return [] + + def _track_algorithm(self): + """ + Keep a track of the highest versions of algorithms encountered. + The algorithm name and version are retrieved from the document name. + See BaseDirective::set_algorithm_and_version() + """ + env = self.state.document.settings.env + if not hasattr(env, "algorithm"): + env.algorithms = {} + #endif + + name, version = self.algorithm_name(), self.algorithm_version() + algorithms = env.algorithms + if name in algorithms: + prev_version = algorithms[name][1] + if version > prev_version: + algorithms[name][1] = version + else: + algorithms[name] = (name, version) + + def _insert_reference_link(self): + """ + Outputs a reference to the top of the algorithm's rst + of the form ".. _algm-AlgorithmName-vVersion:", so that + the page can be referenced using + :ref:`algm-AlgorithmName-version`. If this is the highest + version then it also outputs a reference ".. _algm-AlgorithmName: + """ + from mantid.api import AlgorithmFactory + + alg_name = self.algorithm_name() + version = self.algorithm_version() + self.add_rst(".. _algm-%s-v%d:\n" % (alg_name, version)) + + if AlgorithmFactory.highestVersion(alg_name) == version: + self.add_rst(".. _algm-%s:\n" % alg_name) + + def _insert_pagetitle(self): + """ + Outputs a title for the page + """ + title = "%s v%d" % (self.algorithm_name(), self.algorithm_version()) + self.add_rst(self.make_header(title, True)) + + def _insert_toc(self): + """ + Outputs a title for the page + """ + self.add_rst(".. contents:: Table of Contents\n :local:\n") + + def _create_screenshot(self): + """ + Creates a screenshot for the named algorithm in the "images/screenshots" + subdirectory. + + The file will be named "algorithmname-vX_dlg.png", e.g. Rebin-v1_dlg.png + + Returns: + str: The full path to the created image + """ + from mantiddoc.tools.screenshot import algorithm_screenshot + + env = self.state.document.settings.env + screenshots_dir = self._screenshot_directory() + if not os.path.exists(screenshots_dir): + os.makedirs(screenshots_dir) + + try: + imgpath = algorithm_screenshot(self.algorithm_name(), screenshots_dir, version=self.algorithm_version()) + except Exception, exc: + env.warn(env.docname, "Unable to generate screenshot for '%s' - %s" % (algorithm_name, str(exc))) + imgpath = os.path.join(screenshots_dir, "failed_dialog.png") + + return imgpath + + def _insert_screenshot_link(self, img_path): + """ + Outputs an image link with a custom :class: style. The filename is + extracted from the path given and then a relative link to the + directory specified by the SCREENSHOTS_DIR environment variable from + the root source directory is formed. + + Args: + img_path (str): The full path as on the filesystem to the image + """ + env = self.state.document.settings.env + format_str = ".. figure:: %s\n"\ + " :class: screenshot\n\n"\ + " %s\n\n" + + # Sphinx assumes that an absolute path is actually relative to the directory containing the + # conf.py file and a relative path is relative to the directory where the current rst file + # is located. + + filename = os.path.split(img_path)[1] + cfgdir = env.srcdir + screenshots_dir = self._screenshot_directory() + rel_path = os.path.relpath(screenshots_dir, cfgdir) + # This is a href link so is expected to be in unix style + rel_path = rel_path.replace("\\","/") + + # stick a "/" as the first character so Sphinx computes relative location from source directory + path = "/" + rel_path + "/" + filename + caption = "A screenshot of the **" + self.algorithm_name() + "** dialog." + self.add_rst(format_str % (path, caption)) + + def _screenshot_directory(self): + """ + Returns a full path where the screenshots should be generated. They are + put in a screenshots subdirectory of the main images directory in the source + tree. Sphinx then handles copying them to the final location + + Arguments: + env (BuildEnvironment): Allows access to find the source directory + + Returns: + str: A string containing a path to where the screenshots should be created. This will + be a filesystem path + """ + try: + return os.environ["SCREENSHOTS_DIR"] + except: + raise RuntimeError("The '.. algorithm::' directive requires a SCREENSHOTS_DIR environment variable to be set.") + + def _insert_deprecation_warning(self): + """ + If the algorithm version is deprecated then construct a warning message + """ + from mantid.api import DeprecatedAlgorithmChecker + + checker = DeprecatedAlgorithmChecker(self.algorithm_name(), self.algorithm_version()) + msg = checker.isDeprecated() + if len(msg) == 0: + return + + # Check for message to use another algorithm an insert a link + match = DEPRECATE_USE_ALG_RE.search(msg) + if match is not None and len(match.groups()) == 1: + name = match.group(0) + msg = DEPRECATE_USE_ALG_RE.sub(r"Use :ref:`algorithm|\1` instead.", msg) + + self.add_rst(".. warning:: %s" % msg) + + +#------------------------------------------------------------------------------------------------------------ + +def html_collect_pages(app): + """ + Write out unversioned algorithm pages that redirect to the highest version of the algorithm + """ + env = app.builder.env + if not hasattr(env, "algorithms"): + return # nothing to do + + template = REDIRECT_TEMPLATE + + algorithms = env.algorithms + for name, highest_version in algorithms.itervalues(): + redirect_pagename = "algorithms/%s" % name + target = "%s-v%d.html" % (name, highest_version) + context = {"name" : name, "target" : target} + yield (redirect_pagename, context, template) + +#------------------------------------------------------------------------------------------------------------ + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + app.add_directive('algorithm', AlgorithmDirective) + + # connect event html collection to handler + app.connect("html-collect-pages", html_collect_pages) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py new file mode 100644 index 0000000000000000000000000000000000000000..2481e4ca734f3beb7687419d351deef2e8c20f8e --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/aliases.py @@ -0,0 +1,35 @@ +from base import BaseDirective + + +class AliasesDirective(BaseDirective): + + """ + Obtains the aliases for a given algorithm based on it's name. + """ + + required_arguments, optional_arguments = 0, 0 + + def run(self): + """ + Called by Sphinx when the ..aliases:: directive is encountered. + """ + alg = self.create_mantid_algorithm(self.algorithm_name(), self.algorithm_version()) + alias = alg.alias() + if len(alias) == 0: + return [] + + self.add_rst(self.make_header("Aliases")) + format_str = "This algorithm is also known as: **%s**" + self.add_rst(format_str % alias) + self.commit_rst() + + return [] + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + app.add_directive('aliases', AliasesDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py new file mode 100644 index 0000000000000000000000000000000000000000..f52f4c635420bc4c8dfa4666221c1125cbd4fdfc --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/base.py @@ -0,0 +1,119 @@ +from docutils import statemachine +from docutils.parsers.rst import Directive +import re + +ALG_DOCNAME_RE = re.compile(r'^([A-Z][a-zA-Z0-9]+)-v([0-9][0-9]*)$') + +#---------------------------------------------------------------------------------------- +def algorithm_name_and_version(docname): + """ + Returns the name and version of an algorithm based on the name of the + document supplied. The expected name of the document is "AlgorithmName-v?", which + is the name of the file with the extension removed + + Arguments: + docname (str): The name of the document as supplied by docutils. Can contain slashes to indicate a path + + Returns: + tuple: A tuple containing two elements (name, version) + """ + # docname includes path, using forward slashes, from root of documentation directory + docname = docname.split("/")[-1] + match = ALG_DOCNAME_RE.match(docname) + if not match or len(match.groups()) != 2: + raise RuntimeError("Document filename '%s.rst' does not match the expected format: AlgorithmName-vX.rst" % docname) + + grps = match.groups() + return (str(grps[0]), int(grps[1])) + +#---------------------------------------------------------------------------------------- +class BaseDirective(Directive): + + """ + Contains shared functionality for Mantid custom directives. + """ + has_content = False + final_argument_whitespace = True + + algm_name = None + algm_version = None + rst_lines = None + + def algorithm_name(self): + """ + Returns the algorithm name as parsed from the document name + """ + if self.algm_name is None: + self._set_algorithm_name_and_version() + return self.algm_name + + def algorithm_version(self): + """ + Returns the algorithm version as parsed from the document name + """ + if self.algm_version is None: + self._set_algorithm_name_and_version() + return self.algm_version + + def _set_algorithm_name_and_version(self): + """ + Returns the name and version of an algorithm based on the name of the + document. The expected name of the document is "AlgorithmName-v?", which + is the name of the file with the extension removed + """ + env = self.state.document.settings.env + self.algm_name, self.algm_version = algorithm_name_and_version(env.docname) + + def add_rst(self, text): + """ + Appends given reST into a managed list. It is NOT inserted into the + document until commit_rst() is called + + Args: + text (str): reST to track + """ + if self.rst_lines is None: + self.rst_lines = [] + + self.rst_lines.extend(statemachine.string2lines(text)) + + def commit_rst(self): + """ + Inserts the currently tracked rst lines into the state_machine + """ + self.state_machine.insert_input(self.rst_lines, "") + self.rst_lines = [] + + def make_header(self, name, pagetitle=False): + """ + Makes a ReStructuredText title from the algorithm's name. + + Args: + algorithm_name (str): The name of the algorithm to use for the title. + pagetitle (bool): If True, line is inserted above & below algorithm name. + + Returns: + str: ReST formatted header with algorithm_name as content. + """ + if pagetitle: + line = "\n" + "=" * len(name) + "\n" + return line + name + line + else: + line = "\n" + "-" * len(name) + "\n" + return name + line + + def create_mantid_algorithm(self, algorithm_name, version): + """ + Create and initializes a Mantid algorithm. + + Args: + algorithm_name (str): The name of the algorithm to use for the title. + version (int): Version of the algorithm to create + + Returns: + algorithm: An instance of a Mantid algorithm. + """ + from mantid.api import AlgorithmManager + alg = AlgorithmManager.createUnmanaged(algorithm_name, version) + alg.initialize() + return alg diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py new file mode 100644 index 0000000000000000000000000000000000000000..c5b7f51bcb7534b12299244f46feb3830398a118 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py @@ -0,0 +1,300 @@ +""" + Provides directives for dealing with category pages. + + While parsing the directives a list of the categories and associated pages/subcategories + is tracked. When the final set of html pages is collected, a processing function + creates "index" pages that lists the contents of each category. The display of each + "index" page is controlled by a jinja2 template. +""" +from base import BaseDirective, algorithm_name_and_version + +CATEGORY_INDEX_TEMPLATE = "category.html" +# relative to the "root" directory +CATEGORIES_HTML_DIR = "categories" + +class LinkItem(object): + """ + Defines a linkable item with a name and html reference + """ + # Name displayed on listing page + name = None + # html link + link = None + + def __init__(self, name, docname): + """ + Arguments: + name (str): Display name of document + docname (str): Name of document as referred to by docutils (can contain directory separators) + """ + self.name = str(name) + + rel_path = docname # no suffix + # Assumes the link is for the current document and that the + # page that will use this reference is in a single + # subdirectory from root + self.link = "../%s.html" % rel_path + + def __eq__(self, other): + """ + Define comparison for two objects as the comparison of their names + + Arguments: + other (PageRef): Another PageRef object to compare + """ + return self.name == other.name + + def __hash__(self): + return hash(self.name) + + def __repr__(self): + return self.name + + def html_link(self): + """ + Returns a link for use as a href to refer to this document from a + categories page. It assumes that the category pages are in a subdirectory + of the root and that the item to be referenced is in the algorithms directory + under the root. + + Returns: + str: A string containing the link + """ + return self.link +# endclass + +class PageRef(LinkItem): + """ + Store details of a single page reference + """ + + def __init__(self, name, docname): + super(PageRef, self).__init__(name, docname) + +#endclass + +class Category(LinkItem): + """ + Store information about a single category + """ + # Collection of PageRef objects that link to members of the category + pages = None + # Collection of PageRef objects that form subcategories of this category + subcategories = None + + def __init__(self, name, docname): + super(Category, self).__init__(name, docname) + + # override default link + self.link = "../categories/%s.html" % name + self.pages = set([]) + self.subcategories = set([]) + +#endclass + +class CategoriesDirective(BaseDirective): + """ + Records the page as part of given categories. Index pages for each + category are then automatically created after all pages are collected + together. + + Subcategories can be given using the "\\" separator, e.g. Algorithms\\Transforms + + If the argument list is empty then the the file is assumed to be an algorithm file + and the lists is pulled from the algoritm object + """ + + required_arguments = 0 + # it can be in many categories and we put an arbitrary upper limit here + optional_arguments = 25 + + def run(self): + """ + Called by Sphinx when the defined directive is encountered. + """ + categories = self._get_categories_list() + display_name = self._get_display_name() + links = self._create_links_and_track(display_name, categories) + + self.add_rst("\n" + links) + self.commit_rst() + return [] + + def _get_categories_list(self): + """ + Returns a list of the category strings + + Returns: + list: A list of strings containing the required categories + """ + # if the argument list is empty then assume this is in an algorithm file + args = self.arguments + if len(args) > 0: + return args + else: + return self._get_algorithm_categories_list() + + def _get_algorithm_categories_list(self): + """ + Returns a list of the category strings + + Returns: + list: A list of strings containing the required categories + """ + category_list = ["Algorithms"] + alg_cats = self.create_mantid_algorithm(self.algorithm_name(), self.algorithm_version()).categories() + for cat in alg_cats: + # double up the category separators so they are not treated as escape characters + category_list.append(cat.replace("\\", "\\\\")) + + return category_list + + def _get_display_name(self): + """ + Returns the name of the item as it should appear in the category + """ + # If there are no arguments then take the name directly from the document name, else + # assume it is an algorithm and use its name + if len(self.arguments) > 0: + env = self.state.document.settings.env + # env.docname returns relative path from doc root. Use name after last "/" separator + return env.docname.split("/")[-1] + else: + return self.algorithm_name() + + def _create_links_and_track(self, page_name, category_list): + """ + Return the reST text required to link to the given + categories. As the categories are parsed they are + stored within the current environment for use in the + "html_collect_pages" function. + + Args: + page_name (str): Name to use to refer to this page on the category index page + category_list (list): List of category strings + + Returns: + str: A string of reST that will define the links + """ + env = self.state.document.settings.env + if not hasattr(env, "categories"): + env.categories = {} + + link_rst = "" + ncategs = 0 + for item in category_list: + if r"\\" in item: + categs = item.split(r"\\") + else: + categs = [item] + # endif + + parent = None + for index, categ_name in enumerate(categs): + if categ_name not in env.categories: + category = Category(categ_name, env) + env.categories[categ_name] = category + else: + category = env.categories[categ_name] + #endif + + category.pages.add(PageRef(page_name, env.docname)) + if index > 0: # first is never a child + parent.subcategories.add(Category(categ_name, env.docname)) + #endif + + link_rst += "`%s <../%s/%s.html>`_ | " % (categ_name, CATEGORIES_HTML_DIR, categ_name) + ncategs += 1 + parent = category + # endfor + # endfor + + link_rst = "**%s**: " + link_rst.rstrip(" | ") # remove final separator + if ncategs == 1: + link_rst = link_rst % "Category" + else: + link_rst = link_rst % "Categories" + #endif + + return link_rst + #end def + +#--------------------------------------------------------------------------------- + +def html_collect_pages(app): + """ + Callback for the 'html-collect-pages' Sphinx event. Adds category + pages + a global Categories.html page that lists the pages included. + + Function returns an iterable (pagename, context, html_template), + where context is a dictionary defining the content that will fill the template + + Arguments: + app: A Sphinx application object + """ + if not hasattr(app.builder.env, "categories"): + return # nothing to do + + for name, context, template in create_category_pages(app): + yield (name, context, template) +# enddef + +def create_category_pages(app): + """ + Returns an iterable of (category_name, context, "category.html") + + Arguments: + app: A Sphinx application object + """ + env = app.builder.env + + # jinja2 html template + template = CATEGORY_INDEX_TEMPLATE + + categories = env.categories + for name, category in categories.iteritems(): + context = {} + context["title"] = category.name + # sort subcategories & pages by first letter + context["subcategories"] = sorted(category.subcategories, key = lambda x: x.name[0]) + context["pages"] = sorted(category.pages, key = lambda x: x.name[0]) + + yield (CATEGORIES_HTML_DIR + "/" + name, context, template) +# enddef + +#----------------------------------------------------------------------------------------------------------- + +def purge_categories(app, env, docname): + """ + Purge information about the given document name from the tracked algorithms + + Arguments: + app (Sphinx.application): Application object + env (Sphinx.BuildEnvironment): + docname (str): Name of the document + """ + if not hasattr(env, "categories"): + return # nothing to do + + categories = env.categories + try: + name, version = algorithm_name_and_version(docname) + except RuntimeError: # not an algorithm page + return + + deadref = PageRef(name, docname) + for category in categories.itervalues(): + pages = category.pages + if deadref in pages: + pages.remove(deadref) + +#------------------------------------------------------------------------------ +def setup(app): + # Add categories directive + app.add_directive('categories', CategoriesDirective) + + # connect event html collection to handler + app.connect("html-collect-pages", html_collect_pages) + + # connect document clean up to purge information about this page + app.connect('env-purge-doc', purge_categories) \ No newline at end of file diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py new file mode 100644 index 0000000000000000000000000000000000000000..0f6177b0ed266fba811cdd64488789e0c711e705 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/properties.py @@ -0,0 +1,163 @@ +from base import BaseDirective + + +class PropertiesDirective(BaseDirective): + + """ + Outputs the given algorithm's properties into a ReST formatted table. + """ + # Accept one required argument and no optional arguments. + required_arguments, optional_arguments = 0, 0 + + def run(self): + """ + Called by Sphinx when the ..properties:: directive is encountered. + """ + self.add_rst(self.make_header("Properties")) + self.add_rst(self._populate_properties_table()) + self.commit_rst() + + return [] + + def _populate_properties_table(self): + """ + Populates the ReST table with algorithm properties. + """ + alg = self.create_mantid_algorithm(self.algorithm_name(), self.algorithm_version()) + alg_properties = alg.getProperties() + + # Stores each property of the algorithm in a tuple. + properties = [] + + # Used to obtain the name for the direction property rather than an + # int. + direction_string = ["Input", "Output", "InOut", "None"] + + for prop in alg_properties: + # Append a tuple of properties to the list. + properties.append(( + str(prop.name), + str(direction_string[prop.direction]), + str(prop.type), + str(self._get_default_prop(prop)), + str(prop.documentation.replace("\n", " ")) + )) + + # Build and add the properties to the ReST table. + return self._build_table(properties) + + def _build_table(self, table_content): + """ + Build the ReST format + + Args: + table_content (list of tuples): Each tuple (row) container + property values for a unique property of that algorithm. + + Returns: + str: ReST formatted table containing algorithm properties. + """ + # Default values for the table headers. + header_content = ( + 'Name', 'Direction', 'Type', 'Default', 'Description') + # The width of the columns. Multiply row length by 10 to ensure small + # properties format correctly. + col_sizes = [max(len(row[i] * 10) for row in table_content) + for i in range(len(header_content))] + # Use the column widths as a means to formatting columns. + formatter = ' '.join('{:<%d}' % col for col in col_sizes) + # Add whitespace to each column. This depends on the values returned by + # col_sizes. + table_content_formatted = [ + formatter.format(*item) for item in table_content] + # Create a seperator for each column + seperator = formatter.format(*['=' * col for col in col_sizes]) + # Build the table. + header = '\n' + seperator + '\n' + formatter.format(*header_content) + '\n' + content = seperator + '\n' + \ + '\n'.join(table_content_formatted) + '\n' + seperator + # Join the header and footer. + return header + content + + def _get_default_prop(self, prop): + """ + Converts the default value of the property to a more use-friendly one. + + Args: + prop (str): The algorithm property to use. + + Returns: + str: The default value of the property. + """ + from mantid.api import IWorkspaceProperty + + # Used to obtain the name for the direction property rather than + # outputting an int. + direction_string = ["Input", "Output", "InOut", "None"] + + # Nothing to show under the default section for an output properties + # that are not workspace properties. + if (direction_string[prop.direction] == "Output") and \ + (not isinstance(prop, IWorkspaceProperty)): + default_prop = "" + elif (prop.isValid == ""): + default_prop = self._create_property_default_string(prop) + else: + default_prop = "Mandatory" + return default_prop + + def _create_property_default_string(self, prop): + """ + Converts the default value of the property to a more use-friendly one. + + Args: + prop. The property to find the default value of. + + Returns: + str: The string to add to the property table default section. + """ + + default = prop.getDefault + defaultstr = "" + + # Convert to int, then float, then any string + try: + val = int(default) + if (val >= 2147483647): + defaultstr = "Optional" + else: + defaultstr = str(val) + except: + try: + val = float(default) + if (val >= 1e+307): + defaultstr = "Optional" + else: + defaultstr = str(val) + except: + # Fall-back default for anything + defaultstr = str(default) + + # Replace the ugly default values with "Optional" + if (defaultstr == "8.9884656743115785e+307") or \ + (defaultstr == "1.7976931348623157e+308") or \ + (defaultstr == "2147483647"): + defaultstr = "Optional" + + if str(prop.type) == "boolean": + if defaultstr == "1": + defaultstr = "True" + else: + defaultstr = "False" + + return defaultstr + + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + app.add_directive('properties', PropertiesDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py new file mode 100644 index 0000000000000000000000000000000000000000..3d92a9071bd87368dd1fc984674d0c08745123cb --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/summary.py @@ -0,0 +1,30 @@ +from base import BaseDirective + + +class SummaryDirective(BaseDirective): + + """ + Obtains the summary for a given algorithm based on it's name. + """ + + required_arguments, optional_arguments = 0, 0 + + def run(self): + """ + Called by Sphinx when the ..summary:: directive is encountered. + """ + self.add_rst(self.make_header("Summary")) + alg = self.create_mantid_algorithm(self.algorithm_name(), self.algorithm_version()) + self.add_rst(alg.getWikiSummary()) + self.commit_rst() + + return [] + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + app.add_directive('summary', SummaryDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/tools/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f5c662ab970a487f685a55c2c41f221139809bed --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/tools/__init__.py @@ -0,0 +1,3 @@ +""" + Subpackage containing tools to help in constructing the documentation +""" diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py new file mode 100644 index 0000000000000000000000000000000000000000..8d57701f19aa45687ae81adb7933cfcbd4a7cf18 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py @@ -0,0 +1,45 @@ +""" + mantiddoc.tools.screenshot + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Provides functions to take a screenshot of a QWidgets. + + It currently assumes that the functions are called within the + MantidPlot Python environment + + :copyright: Copyright 2014 + ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory +""" + +def algorithm_screenshot(name, directory, version = -1, ext = ".png"): + """ + Takes a snapshot of an algorithm dialog and saves it as an image + named "name_dlg.png" + + Args: + name (str): The name of the algorithm + directory (str): An directory path where the image should be saved + version (str): A version of the algorithm to use (default=latest) + ext (str): An optional extension (including the period). Default=.png + + Returns: + str: A full path to the image file + """ + import mantid + if not mantid.__gui__: + return "NoGUI-ImageNotGenerated.png" + + import mantidqtpython as mantidqt + from mantidplot import screenshot_to_dir, threadsafe_call + + iface_mgr = mantidqt.MantidQt.API.InterfaceManager() + # threadsafe_call required for MantidPlot + dlg = threadsafe_call(iface_mgr.createDialogFromName, name, True, None) + + suffix = ("-v%d" % version) if version != -1 else "" + filename = "%s%s_dlg%s" % (name, suffix, ext) + + img_path = screenshot_to_dir(widget=dlg, filename=filename, screenshot_dir=directory) + threadsafe_call(dlg.close) + + return img_path diff --git a/Code/Mantid/scripts/WikiMaker/ScreenshotAlgDialogs.py b/Code/Mantid/scripts/WikiMaker/ScreenshotAlgDialogs.py index 2017cf85590436851bea5a112c4cf941a357770c..ff9be6948c72ded96bfb3c9350b127a55214e371 100644 --- a/Code/Mantid/scripts/WikiMaker/ScreenshotAlgDialogs.py +++ b/Code/Mantid/scripts/WikiMaker/ScreenshotAlgDialogs.py @@ -14,10 +14,10 @@ Take a screenshot of the algorithm dialog associated with the algorithmDeprecati def screenShotAlgorithm(alg_name): interface_manager = mantidqtpython.MantidQt.API.InterfaceManager() dlg = threadsafe_call( interface_manager.createDialogFromName, alg_name, True) - file = alg_name + "_dlg" - screenshot_to_dir(widget=dlg, filename=file, screenshot_dir=screenshotdir) + filename = alg_name + "_dlg.png" + screenshot_to_dir(widget=dlg, filename=filename, screenshot_dir=screenshotdir) threadsafe_call(dlg.close) - file_abs = os.path.join(screenshotdir, file + ".png") + file_abs = os.path.join(screenshotdir, filename) """ Screenshot all registered algorithms.