diff --git a/src/Ext/freecad/CMakeLists.txt b/src/Ext/freecad/CMakeLists.txt index c39e5e07eb..d1d660f337 100644 --- a/src/Ext/freecad/CMakeLists.txt +++ b/src/Ext/freecad/CMakeLists.txt @@ -27,6 +27,7 @@ endif() configure_file(__init__.py.template ${NAMESPACE_INIT}) set(EXT_FILES + freecad_doc.py part.py partdesign.py project_utility.py diff --git a/src/Ext/freecad/freecad_doc.py b/src/Ext/freecad/freecad_doc.py new file mode 100644 index 0000000000..8ca2bb2b7c --- /dev/null +++ b/src/Ext/freecad/freecad_doc.py @@ -0,0 +1,63 @@ +# (c) 2024 Werner Mayer LGPL + +__title__="FreeCAD Python documentation" +__author__ = "Werner Mayer" +__url__ = "https://www.freecad.org" +__doc__ = "Helper module to use pydoc" + + +import os, sys, pydoc, pkgutil + +class FreeCADDoc(pydoc.HTMLDoc): + def index(self, dir, shadowed=None): + """ Generate an HTML index for a directory of modules.""" + modpkgs = [] + if shadowed is None: shadowed = {} + for importer, name, ispkg in pkgutil.iter_modules([dir]): + if name == 'Init': + continue + if name == 'InitGui': + continue + if name[-2:] == '_d': + continue + modpkgs.append((name, '', ispkg, name in shadowed)) + shadowed[name] = 1 + + if len(modpkgs) == 0: + return None + + modpkgs.sort() + contents = self.multicolumn(modpkgs, self.modpkglink) + return self.bigsection(dir, '#ffffff', '#ee77aa', contents) + +def bltinlink(name): + return '%s' % (name, name) + +def createDocumentation(): + pydoc.html = FreeCADDoc() + title = 'FreeCAD Python Modules Index' + + heading = pydoc.html.heading('Python: Index of Modules','#ffffff', '#7799ee') + + + names = list(filter(lambda x: x != '__main__', sys.builtin_module_names)) + contents = pydoc.html.multicolumn(names, bltinlink) + indices = ['
' + pydoc.html.bigsection('Built-in Modules', '#ffffff', '#ee77aa', contents)] + + names = ['FreeCAD', 'FreeCADGui'] + contents = pydoc.html.multicolumn(names, bltinlink) + indices.append('
' + pydoc.html.bigsection('Built-in FreeCAD Modules', '#ffffff', '#ee77aa', contents)) + + seen = {} + for dir in sys.path: + dir = os.path.realpath(dir) + ret = pydoc.html.index(dir, seen) + if ret != None: + indices.append(ret) + + contents = heading + ' '.join(indices) + '''
+ +pydoc by Ka-Ping Yee <ping@lfw.org>''' + + htmldocument = pydoc.html.page(title, contents) + return htmldocument diff --git a/src/Gui/OnlineDocumentation.cpp b/src/Gui/OnlineDocumentation.cpp index 7d786601be..e6c70cfb93 100644 --- a/src/Gui/OnlineDocumentation.cpp +++ b/src/Gui/OnlineDocumentation.cpp @@ -39,6 +39,7 @@ using namespace Gui; // the favicon +// NOLINTBEGIN static const unsigned int navicon_data_len = 318; static const unsigned char navicon_data[] = { 0x00,0x00,0x01,0x00,0x01,0x00,0x10,0x10,0x10,0x00,0x01,0x00,0x04,0x00, @@ -64,6 +65,7 @@ static const unsigned char navicon_data[] = { 0x00,0x00,0x93,0xfd,0x00,0x00,0x81,0xd8,0x00,0x00,0x99,0x9d,0x00,0x00, 0x9c,0x3d,0x00,0x00,0x9f,0xfd,0x00,0x00,0x80,0xfd,0x00,0x00,0xff,0x7d, 0x00,0x00,0xfe,0x01,0x00,0x00,0xff,0x7f,0x00,0x00}; +// NOLINTEND PythonOnlineHelp::PythonOnlineHelp() = default; @@ -71,146 +73,99 @@ PythonOnlineHelp::~PythonOnlineHelp() = default; QByteArray PythonOnlineHelp::loadResource(const QString& filename) const { - QString fn; - fn = filename.mid(1); - QByteArray res; - - if (fn == QLatin1String("favicon.ico")) { - // Return a resource icon in ico format - QBuffer buffer; - buffer.open(QBuffer::WriteOnly); - QImageWriter writer; - writer.setDevice(&buffer); - writer.setFormat("ICO"); - if (writer.canWrite()) { - QPixmap px = qApp->windowIcon().pixmap(24,24); - writer.write(px.toImage()); - buffer.close(); - res = buffer.data(); - } - else { - // fallback - res.reserve(navicon_data_len); - for (int i=0; i<(int)navicon_data_len;i++) { - res[i] = navicon_data[i]; - } - } + if (filename == QLatin1String("/favicon.ico")) { + return loadFavicon(); } - else if (filename == QLatin1String("/")) { - // get the global interpreter lock otherwise the app may crash with the error - // 'PyThreadState_Get: no current thread' (see pystate.c) - Base::PyGILStateLocker lock; - PyObject* main = PyImport_AddModule("__main__"); - PyObject* dict = PyModule_GetDict(main); - dict = PyDict_Copy(dict); - QByteArray cmd = - "import os, sys, pydoc, pkgutil\n" - "\n" - "class FreeCADDoc(pydoc.HTMLDoc):\n" - " def index(self, dir, shadowed=None):\n" - " \"\"\"Generate an HTML index for a directory of modules.\"\"\"\n" - " modpkgs = []\n" - " if shadowed is None: shadowed = {}\n" - " for importer, name, ispkg in pkgutil.iter_modules([dir]):\n" - " if name == 'Init': continue\n" - " if name == 'InitGui': continue\n" - " if name[-2:] == '_d': continue\n" - " modpkgs.append((name, '', ispkg, name in shadowed))\n" - " shadowed[name] = 1\n" - "\n" - " if len(modpkgs) == 0: return None\n" - " modpkgs.sort()\n" - " contents = self.multicolumn(modpkgs, self.modpkglink)\n" - " return self.bigsection(dir, '#ffffff', '#ee77aa', contents)\n" - "\n" - "pydoc.html=FreeCADDoc()\n" - "title='FreeCAD Python Modules Index'\n" - "\n" - "heading = pydoc.html.heading(" - "'Python: Index of Modules'," - "'#ffffff', '#7799ee')\n" - "def bltinlink(name):\n" - " return '%s' % (name, name)\n" - "names = list(filter(lambda x: x != '__main__',\n" - " sys.builtin_module_names))\n" - "contents = pydoc.html.multicolumn(names, bltinlink)\n" - "indices = ['
' + pydoc.html.bigsection(\n" - " 'Built-in Modules', '#ffffff', '#ee77aa', contents)]\n" - "\n" - "names = ['FreeCAD', 'FreeCADGui']\n" - "contents = pydoc.html.multicolumn(names, bltinlink)\n" - "indices.append('
' + pydoc.html.bigsection(\n" - " 'Built-in FreeCAD Modules', '#ffffff', '#ee77aa', contents))\n" - "\n" - "seen = {}\n" - "for dir in sys.path:\n" - " dir = os.path.realpath(dir)\n" - " ret = pydoc.html.index(dir, seen)\n" - " if ret != None:\n" - " indices.append(ret)\n" - "contents = heading + ' '.join(indices) + '''
\n"
- "\n"
- "pydoc by Ka-Ping Yee <ping@lfw.org>'''\n"
- "htmldocument=pydoc.html.page(title,contents)\n";
+ if (filename == QLatin1String("/")) {
+ return loadIndexPage();
+ }
- PyObject* result = PyRun_String(cmd.constData(), Py_file_input, dict, dict);
- if (result) {
- Py_DECREF(result);
- result = PyDict_GetItemString(dict, "htmldocument");
- const char* contents = PyUnicode_AsUTF8(result);
- res.append("HTTP/1.0 200 OK\n");
- res.append("Content-type: text/html\n");
- res.append(contents);
- return res;
- }
- else {
- // load the error page
- Base::PyException e;
- res = loadFailed(QString::fromUtf8(e.what()));
- }
+ return loadHelpPage(filename);
+}
- Py_DECREF(dict);
+QByteArray PythonOnlineHelp::loadFavicon() const
+{
+ // Return a resource icon in ico format
+ QByteArray res;
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ QImageWriter writer;
+ writer.setDevice(&buffer);
+ writer.setFormat("ICO");
+ if (writer.canWrite()) {
+ const int size = 24;
+ QPixmap px = qApp->windowIcon().pixmap(size, size); // NOLINT
+ writer.write(px.toImage());
+ buffer.close();
+ res = buffer.data();
}
else {
- // get the global interpreter lock otherwise the app may crash with the error
- // 'PyThreadState_Get: no current thread' (see pystate.c)
- Base::PyGILStateLocker lock;
- QString name = fn.left(fn.length()-5);
- PyObject* main = PyImport_AddModule("__main__");
- PyObject* dict = PyModule_GetDict(main);
- dict = PyDict_Copy(dict);
- QByteArray cmd =
- "import pydoc\n"
- "object, name = pydoc.resolve(\"";
- cmd += name.toUtf8();
- cmd += "\")\npage = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))\n";
- PyObject* result = PyRun_String(cmd.constData(), Py_file_input, dict, dict);
- if (result) {
- Py_DECREF(result);
- result = PyDict_GetItemString(dict, "page");
- const char* page = PyUnicode_AsUTF8(result);
- res.append("HTTP/1.0 200 OK\n");
- res.append("Content-type: text/html\n");
- res.append(page);
+ // fallback
+ res.reserve(navicon_data_len);
+ for (int i=0; i<(int)navicon_data_len;i++) {
+ res[i] = navicon_data[i];
}
- else {
- // get information about the error
- Base::PyException e;
- //Base::Console().Error("loadResource: %s\n", e.what());
- // load the error page
- //res = fileNotFound();
- res = loadFailed(QString::fromUtf8(e.what()));
- }
-
- Py_DECREF(dict);
}
return res;
}
+QByteArray PythonOnlineHelp::invoke(const std::function