#
##
## SPDX-FileCopyrightText: © 2007-2024 Benedict Verhegghe <bverheg@gmail.com>
## SPDX-License-Identifier: GPL-3.0-or-later
##
## This file is part of pyFormex 3.5 (Thu Feb 8 19:11:13 CET 2024)
## pyFormex is a tool for generating, manipulating and transforming 3D
## geometrical models by sequences of mathematical operations.
## Home page: https://pyformex.org
## Project page: https://savannah.nongnu.org/projects/pyformex/
## Development: https://gitlab.com/bverheg/pyformex
## Distributed under the GNU General Public License version 3 or later.
##
## 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 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see http://www.gnu.org/licenses/.
##
"""Display help
"""
import sys
import pyformex as pf
from pyformex.gui import guiscript as pg
from pyformex.gui.menus.Settings import updateSettings
_I = pg._I
# TODO: this info may be not up to date
# The location of the local docs depends on the type of installation
#
# 'G': build/install under git tree
# build_dir = pyformexdir / 'doc'
#
# 'URD': as user post-install:
# build_dir = .local/share/pyformex/doc/html
#
# 'R': pyformex installation from .tar.gz, during install:
# build in pyformexdir / 'doc', install in /usr/local/share
#
# 'D': debian package during creation
# build in pyformexdir / 'doc'
# create pyformex-doc package /usr/share/doc/pyformex/html
#
[docs]def checkHtmlDir():
"""Check that we have the html docs available"""
for htmldir in (
# paths where the html docs might be
pf.cfg['htmldir'],
pf.cfg['docdir'] / 'html',
pf.Path.home() / '.local' / 'share' / 'pyformex' / 'doc' / 'html',
pf.Path.home() / '.local' / 'lib' / 'pyformex' / 'doc' / 'html',
):
if (htmldir / 'index.html').exists():
if pf.cfg['htmldir'] != htmldir:
pf.cfg['htmldir'] = htmldir # correct if needed
return True
return False
[docs]def checkHtmlReqs():
"""Check the requirements for building the html docs"""
required = {
'System': {
'pyFormex_installtype': 'G',
},
'Module': {
'docutils': '>= 0',
'sphinx': '>= 1.4',
},
'External': {
'sphinx-build': '>= 1.4',
},
}
# CHECK SOFT
result, s = pf.software.checkSoftware(required, report=True)
print(s)
return result
[docs]def buildHtmlDocs(builddir=None):
"""Build the html documentation.
Note: this is only for users building the docs.
Builds at installation time are done by the Makefile.
builddir is where the docs are built.
For 'G' this is pyformex/doc/.
For 'RD' this is .local/share/pyformex/doc/html.
"""
# Check requirements
if not checkHtmlReqs() != 'OK':
raise ValueError("I could not find some required software")
# the source should always be here
sourcedir = pf.cfg['pyformexdir'] / 'sphinx'
print(f"BUILDDIR {builddir} ({type(builddir)})")
if builddir is None:
# set default build dir
if pf._installtype in 'GU':
builddir = pf.cfg['docdir']
else:
builddir = pf.Path.home() / '.local' / 'share' / 'pyformex' / 'doc'
print(f"BUILDDIR {builddir} ({type(builddir)})")
builddir.mkdir(parents=True, exist_ok=True)
if not builddir.is_writable_dir():
pg.error("TODO: !!!!!!")
if pg.showInfo(f"""..
Building local documentation
----------------------------
I will now build the local documentation in ::
{builddir}
As this is a lengthy process (especially if you are building
for the first time), I will run it in the background
and notify you when it's ready.
""", actions=['Cancel', 'OK']) == 'OK':
cmd = f'make -C {sourcedir} html BUILDDIR={builddir}'
P = pg.runLongTask(cmd)
print(f"Return with value {P.returncode}")
updateSettings({'htmldir': builddir}, save=True)
menu_setup(pf.GUI.menu)
[docs]def searchIndex():
"""Search text in pyFormex refman index.
Asks a pattern from the user and searches for it the index of the
local pyFormex documentation. Displays the results in the browser.
"""
res = pg.askItems([
_I('text', '', text='String to search'),
])
if res:
showLocalURL(f"search.html?q={res['text']}&check_keywords=yes&area=default")
[docs]def searchText():
"""Search text in pyFormex source files.
Asks a pattern from the user and searches for it through all
the pyFormex source files.
"""
res = pg.askItems([
_I('pattern', '', text='String to grep'),
_I('options', '', text='Options',
tooltip="Some cool options: -a (extended search), -i (ignore case), "
"-f (literal string), -e (extended regexp)"),
])
if res:
out = pf.utils.grepSource(relative=False, **res)
pg.showText(out, mono=True) # , modal=False)
[docs]def catchAndDisplay(expression):
"""Catch stdout from a Python expression and display it in a window."""
save = sys.stdout
try:
with pf.TempFile() as f:
sys.stdout = f
eval(expression)
f.seek(0)
pg.showText(f.read())
finally:
sys.stdout = save
[docs]def opengl():
"""Display the OpenGL format description."""
from pyformex.gui import qtgl
from pyformex.opengl import gl
s = pf.formatDict(gl.gl_version()) + '\n'
s += qtgl.OpenGLFormat(pf.canvas.format())
pg.showText(s, mono=True)
[docs]def detected(probe):
"""Display the detected software components."""
header = "Detected Software"
if not probe:
header = "Already " + header
pg.showText(
pf.cmdtools.whereami() + '\n\n' +
pf.software.reportSoftware(probe=probe, header=header, color=False),
mono=True)
[docs]def about():
"""Display short information about pyFormex."""
version = pf.version()
pg.showInfo(f"""..
{version}
{'='*len(version)}
A tool for generating, manipulating and transforming 3D geometrical models by sequences of mathematical operations.
{pf._copyright}
Distributed under the GNU GPL version 3 or later
""") # noqa: E501
[docs]def developers():
"""Display the list of developers."""
import random
devs = [
'Matthieu De Beule',
'Nic Debusschere',
'Gianluca De Santis',
'Bart Desloovere',
'Wouter Devriendt',
'Francesco Iannaccone',
'Peter Mortier',
'Tim Neels',
'Tomas Praet',
'Tran Phuong Toan',
'Sofie Van Cauter',
'Benedict Verhegghe',
'Zhou Wenxuan',
]
random.shuffle(devs)
pg.showInfo("The following people have\n"
"contributed to pyFormex.\n"
"They are listed in random order.\n\n" +
'\n'.join(devs) +
"\n\nIf you feel that your name was left\n"
"out in error, please write to\n"
"bverheg@gmail.com\n")
_NO_COOKIES = 'No cookies found :('
_cookies = []
def roll(l):
l.append(l.pop(0))
def cookie():
import random
global _cookies
if not _cookies:
try:
cookie_file = pf.cfg['datadir'] / 'cookies.txt'
_cookies = cookie_file.read_text().split('\n')
print(f"Read {len(_cookies)} cookies")
random.shuffle(_cookies)
except Exception:
_cookies = [_NO_COOKIES]
pg.showInfo(_cookies[0], ["OK"])
roll(_cookies)
# Help showing functions
[docs]def showLocalURL(filename):
"""Show a html document in the local html dir.
Parameters
----------
filename: str
Path of the file relative to pf.cfg['htmldir']
"""
path = pf.cfg['htmldir'] / filename
pg.showURL(f"file:{path}")
[docs]def showConfig(which):
"""Show one of the configs: S(ession), U(ser), F(actory)"""
cfg = {'S': pf.cfg, 'U': pf.prefcfg, 'F': pf.refcfg}[which]
pg.showText(str(cfg))
[docs]def install_external(pkgdir, prgname):
"""Install external software from the pyformex/extra dir"""
extdir = pf.cfg['pyformexdir'] / 'extra' / pkgdir
cmd = f"cd {extdir} && make && make install"
P = pf.utils.command(cmd, shell=True)
if P.returncode:
pg.showText(P.stdout + P.stderr)
else:
if pf.External.has(prgname, check=True):
info = f"Succesfully installed {prgname}"
else:
info = "You should now restart pyFormex!"
pg.showInfo(info)
return P.returncode
# Short aliases for use in items
_L = showLocalURL
_C = showConfig
_F = pg.showFile
_U = pg.showURL
_E = install_external
# constant strings used in items
docdir = pf.cfg['docdir']
savannah = 'http://savannah.nongnu.org/'
[docs]def showHelp(action):
"""Function triggered by the help menu items.
If the action's data is a tuple with a callable as first item,
call it with the remainder of the tuple as arguments.
"""
if pf.debugon(pf.DEBUG.HELP):
print(f"SHOWHELP {action.text()}")
data = action.data()
if data and isinstance(data, tuple) and callable(data[0]):
data[0](*data[1:])
##### extra help items when running from source directory ########
if pf._installtype in 'UG':
# extra help items for developer version
devdir = pf.cfg['pyformexdir'] / '..'
dev_installs = [
# ('dxfparser', (_E, 'dxfparser', 'pyformex-dxfparser')), # fails
('postabq', (_E, 'postabq', 'pyformex-postabq')),
('gtsinside', (_E, 'gts', 'gtsinside')),
]
dev_docs = [
('Developer Guides', [
('Developer HOWTO', (
_F, devdir / "HOWTO-dev.rst")),
('pyFormex coding style guide', (
_F, devdir / "HOWTO-style.rst")),
('Installation of extra software', (
_F, devdir / "install-extra.rst")),
('Numpy documentation guidelines', (
_U, 'https://numpydoc.readthedocs.io/en/latest/'
'format.html#docstring-standard')),
('re-structured text (reST)', (
_U, 'http://docutils.sourceforge.io/rst.html')),
]),
('Build local documentation', buildHtmlDocs),
]
else:
dev_installs = dev_docs = []
########## The menu ##########
menu_items = [
('Online documentation', (_U, pf.cfg['help/webdoc'])),
('---', None),
('Local documentation', (_L, 'index.html')),
('Reference Manual', (_L, 'refman.html')),
('Tutorial', (_L, 'tutorial.html')),
('Running pyFormex', (_L, 'running.html')),
('Module Index', (_L, 'py-modindex.html')),
('Index', (_L, 'genindex.html')),
('Search in index', searchIndex),
('Search in source', searchText),
('About Current Application', pg.showDoc),
('---', None),
('Readme', (_F, docdir / 'README.rst')),
('ReleaseNotes', (_F, docdir / 'ReleaseNotes')),
('License', (_F, docdir / 'LICENSE')),
('Detected Software', [
('Detected so far', (detected, False)),
('Probe all', (detected, True)),
]),
('OpenGL Format', opengl),
('Settings', [
('Session settings', (_C, 'S')),
('User settings', (_C, 'U')),
('Factory settings', (_C, 'F')),
]),
('---', None),
('Important Links', [
('pyFormex', (_U, 'http://pyformex.org')),
('pyFormex development', (_U, 'https://gitlab.com/bverheg/pyformex')),
('pyFormex issues', (_U, 'https://gitlab.com/bverheg/pyformex/-/issues')),
('pyFormex @Savannah', [
('project page', (_U, savannah + 'projects/pyformex/')),
('support', (_U, savannah + 'support/?func=additem&group=pyformex')),
('bugs', (_U, savannah + 'bugs/?func=additem&group=pyformex')),
]),
('Python', (_U, 'https://python.org')),
('NumPy', (_U, 'https://numpy.org/doc/stable/')),
]),
('Fortune Cookie', cookie),
('People', developers),
('---', None),
('About', about),
('---', None),
('Install Externals', [
('Instant Meshes', (_E, 'instant', 'instant-meshes')),
] + dev_installs),
] + dev_docs
menu_func = showHelp
# End