00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QBuffer>
00027 # include <QHttpResponseHeader>
00028 # include <QMessageBox>
00029 # include <QTcpSocket>
00030 #endif
00031
00032 #include <sstream>
00033 #include <CXX/Objects.hxx>
00034 #include <zipios++/zipfile.h>
00035 #include <Base/Interpreter.h>
00036 #include <Base/Stream.h>
00037 #include <App/Application.h>
00038
00039 #include "MainWindow.h"
00040 #include "BitmapFactory.h"
00041 #include "OnlineDocumentation.h"
00042
00043 using namespace Gui;
00044
00045
00046 static const unsigned int navicon_data_len = 318;
00047 static const unsigned char navicon_data[] = {
00048 0x00,0x00,0x01,0x00,0x01,0x00,0x10,0x10,0x10,0x00,0x01,0x00,0x04,0x00,
00049 0x28,0x01,0x00,0x00,0x16,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x10,0x00,
00050 0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
00051 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00052 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
00053 0x84,0x82,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00054 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00055 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00056 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00057 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x00,
00058 0x00,0x00,0x00,0x00,0x01,0x10,0x01,0x10,0x00,0x00,0x00,0x00,0x11,0x00,
00059 0x00,0x10,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
00060 0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,
00061 0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x10,
00062 0x00,0x00,0x00,0x00,0x01,0x10,0x01,0x10,0x00,0x20,0x00,0x00,0x00,0x11,
00063 0x11,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,
00064 0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
00065 0x00,0x00,0x00,0x00,0x02,0x22,0x22,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
00066 0x00,0x00,0xff,0xff,0x00,0x00,0xfc,0x3f,0x00,0x00,0xf9,0x9f,0x00,0x00,
00067 0x93,0xdf,0x00,0x00,0x93,0xff,0x00,0x00,0x93,0xff,0x00,0x00,0x93,0xff,
00068 0x00,0x00,0x93,0xfd,0x00,0x00,0x81,0xd8,0x00,0x00,0x99,0x9d,0x00,0x00,
00069 0x9c,0x3d,0x00,0x00,0x9f,0xfd,0x00,0x00,0x80,0xfd,0x00,0x00,0xff,0x7d,
00070 0x00,0x00,0xfe,0x01,0x00,0x00,0xff,0x7f,0x00,0x00};
00071
00072 OnlineDocumentation::OnlineDocumentation()
00073 {
00074
00075 std::string path = App::GetApplication().GetHomePath();
00076 path += "/doc/docs.zip";
00077 zipios::ZipFile zip(path);
00078 if (zip.isValid()) {
00079 zipios::ConstEntries entries = zip.entries();
00080 for (zipios::ConstEntries::iterator it = entries.begin(); it != entries.end(); ++it) {
00081 this->files.push_back(QString::fromAscii((*it)->getFileName().c_str()));
00082 }
00083 }
00084 }
00085
00086 OnlineDocumentation::~OnlineDocumentation()
00087 {
00088 }
00089
00090 QByteArray OnlineDocumentation::loadResource(const QString& filename) const
00091 {
00092 QString fn = filename;
00093 fn = filename.mid(1);
00094 QByteArray res;
00095
00096 if (fn == QLatin1String("favicon.ico")) {
00097
00098 res.reserve(navicon_data_len);
00099 for (int i=0; i<(int)navicon_data_len;i++) {
00100 res[i] = navicon_data[i];
00101 }
00102 }
00103 else if (filename == QLatin1String("/")) {
00104
00105 QString header = QString::fromAscii(
00106 "<!doctype html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
00107 "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">"
00108 "<html><head><title>Python: Index of Modules</title>"
00109 "</head><body bgcolor=\"#f0f0f8\">"
00110 ""
00111 "<table width=\"100%\" cellspacing=0 cellpadding=2 border=0 summary=\"heading\">"
00112 "<tr bgcolor=\"#7799ee\">"
00113 "<td valign=bottom> <br>"
00114 "<font color=\"#ffffff\" face=\"helvetica, arial\"> <br><big><big><strong>Python: Index of Modules</strong></big></big></font></td>"
00115 "<td align=right valign=bottom>"
00116 "<font color=\"#ffffff\" face=\"helvetica, arial\"> </font></td></tr></table>"
00117 "<p><p>"
00118 "<table width=\"100%\" cellspacing=0 cellpadding=2 border=0 summary=\"section\">"
00119 "<tr bgcolor=\"#ee77aa\">"
00120 "<td colspan=3 valign=bottom> <br>"
00121 "<font color=\"#ffffff\" face=\"helvetica, arial\"><big><strong>FreeCAD Modules</strong></big></font></td></tr>"
00122 ""
00123 "<tr><td bgcolor=\"#ee77aa\"><tt> </tt></td><td> </td>"
00124 "<td width=\"100%\"><table width=\"100%\" summary=\"list\"><tr><td width=\"25%\" valign=top>");
00125 int ct=0;
00126 for (QStringList::ConstIterator it = this->files.begin(); it != this->files.end(); ++it) {
00127 QString file = *it;
00128 if (file.endsWith(QLatin1String(".html"))) {
00129 file.chop(5);
00130 if ((++ct)%15 == 0)
00131 header += QString::fromAscii("</td><td width=\"25%\" valign=top>");
00132 header += QString::fromAscii("<a href=\"%1.html\">%2</a><br>").arg(file).arg(file);
00133 }
00134 }
00135
00136 header += QString::fromAscii(
00137 "</td></tr></table></td></tr></table> <p>"
00138
00139
00140
00141 "</body></html>");
00142 res.append(header);
00143 }
00144 else if (this->files.contains(fn)) {
00145
00146 std::string path = App::GetApplication().GetHomePath();
00147 path += "/doc/docs.zip";
00148 zipios::ZipFile zip(path);
00149 zipios::ConstEntryPointer entry = zip.getEntry((const char*)fn.toAscii());
00150 std::istream* str = zip.getInputStream(entry);
00151
00152
00153 res.reserve(entry->getSize());
00154 QBuffer buffer(&res);
00155 buffer.open(QIODevice::WriteOnly);
00156 Base::IODeviceOStreambuf buf(&buffer);
00157 (*str) >> &buf;
00158 }
00159 else {
00160
00161 QHttpResponseHeader header(404, QString::fromAscii("File not found"));
00162 header.setContentType(QString::fromAscii("text/html\r\n"
00163 "\r\n"
00164 "<html><head><title>Error</title></head>"
00165 "<body bgcolor=\"#f0f0f8\">"
00166 "<table width=\"100%\" cellspacing=0 cellpadding=2 border=0 summary=\"heading\">"
00167 "<tr bgcolor=\"#7799ee\">"
00168 "<td valign=bottom> <br>"
00169 "<font color=\"#ffffff\" face=\"helvetica, arial\"> <br><big><big><strong>FreeCAD Documentation</strong></big></big></font></td>"
00170 "<td align=right valign=bottom>"
00171 "<font color=\"#ffffff\" face=\"helvetica, arial\"> </font></td></tr></table>"
00172 "<p><p>"
00173 "<h1>404 - File not found</h1>"
00174 "<div><p><strong>The requested URL was not found on this server."
00175 "</strong></p>"
00176 "</div></body>"
00177 "</html>"
00178 "\r\n"));
00179 res.append(header.toString());
00180 }
00181
00182 return res;
00183 }
00184
00185 PythonOnlineHelp::PythonOnlineHelp()
00186 {
00187 }
00188
00189 PythonOnlineHelp::~PythonOnlineHelp()
00190 {
00191 }
00192
00193 QByteArray PythonOnlineHelp::loadResource(const QString& filename) const
00194 {
00195 QString fn = filename;
00196 fn = filename.mid(1);
00197 QByteArray res;
00198
00199 if (fn == QLatin1String("favicon.ico")) {
00200
00201 res.reserve(navicon_data_len);
00202 for (int i=0; i<(int)navicon_data_len;i++) {
00203 res[i] = navicon_data[i];
00204 }
00205 }
00206 else if (filename == QLatin1String("/")) {
00207
00208
00209 Base::PyGILStateLocker lock;
00210 PyObject* main = PyImport_AddModule("__main__");
00211 PyObject* dict = PyModule_GetDict(main);
00212 dict = PyDict_Copy(dict);
00213
00214 QByteArray cmd =
00215 "import string, os, sys, pydoc, pkgutil\n"
00216 "\n"
00217 "class FreeCADDoc(pydoc.HTMLDoc):\n"
00218 " def index(self, dir, shadowed=None):\n"
00219 " \"\"\"Generate an HTML index for a directory of modules.\"\"\"\n"
00220 " modpkgs = []\n"
00221 " if shadowed is None: shadowed = {}\n"
00222 " for importer, name, ispkg in pkgutil.iter_modules([dir]):\n"
00223 " if name == 'Init': continue\n"
00224 " if name == 'InitGui': continue\n"
00225 " if name[-2:] == '_d': continue\n"
00226 " modpkgs.append((name, '', ispkg, name in shadowed))\n"
00227 " shadowed[name] = 1\n"
00228 "\n"
00229 " if len(modpkgs) == 0: return None\n"
00230 " modpkgs.sort()\n"
00231 " contents = self.multicolumn(modpkgs, self.modpkglink)\n"
00232 " return self.bigsection(dir, '#ffffff', '#ee77aa', contents)\n"
00233 "\n"
00234 "pydoc.html=FreeCADDoc()\n"
00235 "\n"
00236 "heading = pydoc.html.heading(\n"
00237 "'<big><big><strong>Python: Index of Modules</strong></big></big>',\n"
00238 "'#ffffff', '#7799ee')\n"
00239 "def bltinlink(name):\n"
00240 " return '<a href=\"%s.html\">%s</a>' % (name, name)\n"
00241 "names = filter(lambda x: x != '__main__',\n"
00242 " sys.builtin_module_names)\n"
00243 "contents = pydoc.html.multicolumn(names, bltinlink)\n"
00244 "indices = ['<p>' + pydoc.html.bigsection(\n"
00245 " 'Built-in Modules', '#ffffff', '#ee77aa', contents)]\n"
00246 "\n"
00247 "names = ['FreeCAD', 'FreeCADGui']\n"
00248 "contents = pydoc.html.multicolumn(names, bltinlink)\n"
00249 "indices.append('<p>' + pydoc.html.bigsection(\n"
00250 " 'Built-in FreeCAD Modules', '#ffffff', '#ee77aa', contents))\n"
00251 "\n"
00252 "seen = {}\n"
00253 "for dir in sys.path:\n"
00254 " dir = os.path.realpath(dir)\n"
00255 " ret = pydoc.html.index(dir, seen)\n"
00256 " if ret != None:\n"
00257 " indices.append(ret)\n"
00258 "contents = heading + string.join(indices) + '''<p align=right>\n"
00259 "<font color=\"#909090\" face=\"helvetica, arial\"><strong>\n"
00260 "pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''\n";
00261
00262 PyObject* result = PyRun_String(cmd.constData(), Py_file_input, dict, dict);
00263 if (result) {
00264 Py_DECREF(result);
00265 result = PyDict_GetItemString(dict, "contents");
00266 const char* contents = PyString_AsString(result);
00267 res.append(contents);
00268 return res;
00269 }
00270 else {
00271
00272 PyErr_Clear();
00273 res = fileNotFound();
00274 }
00275
00276 Py_DECREF(dict);
00277 }
00278 else {
00279
00280
00281 Base::PyGILStateLocker lock;
00282 QString name = fn.left(fn.length()-5);
00283 PyObject* main = PyImport_AddModule("__main__");
00284 PyObject* dict = PyModule_GetDict(main);
00285 dict = PyDict_Copy(dict);
00286 QByteArray cmd =
00287 "import pydoc\n"
00288 "object, name = pydoc.resolve(\"";
00289 cmd += name.toUtf8();
00290 cmd += "\")\npage = pydoc.html.page(pydoc.describe(object), pydoc.html.document(object, name))\n";
00291 PyObject* result = PyRun_String(cmd.constData(), Py_file_input, dict, dict);
00292 if (result) {
00293 Py_DECREF(result);
00294 result = PyDict_GetItemString(dict, "page");
00295 const char* page = PyString_AsString(result);
00296 res.append(page);
00297 }
00298 else {
00299
00300 Base::PyException e;
00301 Base::Console().Warning("PythonOnlineHelp::loadResource: %s\n", e.what());
00302
00303 res = fileNotFound();
00304 }
00305
00306 Py_DECREF(dict);
00307 }
00308
00309 return res;
00310 }
00311
00312 QByteArray PythonOnlineHelp::fileNotFound() const
00313 {
00314 QByteArray res;
00315 QHttpResponseHeader header(404, QString::fromAscii("File not found"));
00316 header.setContentType(QString::fromAscii("text/html\r\n"
00317 "\r\n"
00318 "<html><head><title>Error</title></head>"
00319 "<body bgcolor=\"#f0f0f8\">"
00320 "<table width=\"100%\" cellspacing=0 cellpadding=2 border=0 summary=\"heading\">"
00321 "<tr bgcolor=\"#7799ee\">"
00322 "<td valign=bottom> <br>"
00323 "<font color=\"#ffffff\" face=\"helvetica, arial\"> <br><big><big><strong>FreeCAD Documentation</strong></big></big></font></td>"
00324 "<td align=right valign=bottom>"
00325 "<font color=\"#ffffff\" face=\"helvetica, arial\"> </font></td></tr></table>"
00326 "<p><p>"
00327 "<h1>404 - File not found</h1>"
00328 "<div><p><strong>The requested URL was not found on this server."
00329 "</strong></p>"
00330 "</div></body>"
00331 "</html>"
00332 "\r\n"));
00333 res.append(header.toString());
00334 return res;
00335 }
00336
00337 HttpServer::HttpServer(QObject* parent)
00338 : QTcpServer(parent), disabled(false)
00339 {
00340 }
00341
00342 void HttpServer::incomingConnection(int socket)
00343 {
00344 if (disabled)
00345 return;
00346
00347
00348
00349
00350
00351 QTcpSocket* s = new QTcpSocket(this);
00352 connect(s, SIGNAL(readyRead()), this, SLOT(readClient()));
00353 connect(s, SIGNAL(disconnected()), this, SLOT(discardClient()));
00354 s->setSocketDescriptor(socket);
00355 }
00356
00357 void HttpServer::pause()
00358 {
00359 disabled = true;
00360 }
00361
00362 void HttpServer::resume()
00363 {
00364 disabled = false;
00365 }
00366
00367 void HttpServer::readClient()
00368 {
00369 if (disabled)
00370 return;
00371
00372
00373
00374
00375 QTcpSocket* socket = (QTcpSocket*)sender();
00376 if (socket->canReadLine()) {
00377 QString request = QString::fromAscii(socket->readLine());
00378 QHttpRequestHeader header(request);
00379 if (header.method() == QLatin1String("GET")) {
00380 socket->write(help.loadResource(header.path()));
00381 socket->close();
00382 if (socket->state() == QTcpSocket::UnconnectedState) {
00383
00384 socket->deleteLater();
00385 }
00386 }
00387 }
00388 }
00389
00390 void HttpServer::discardClient()
00391 {
00392 QTcpSocket* socket = (QTcpSocket*)sender();
00393 socket->deleteLater();
00394 }
00395
00396
00397
00398
00399
00400 StdCmdPythonHelp::StdCmdPythonHelp()
00401 : Command("Std_PythonHelp"), server(0)
00402 {
00403 sGroup = QT_TR_NOOP("Tools");
00404 sMenuText = QT_TR_NOOP("Python Modules");
00405 sToolTipText = QT_TR_NOOP("Opens a browser to show the Python modules");
00406 sWhatsThis = QT_TR_NOOP("Opens a browser to show the Python modules");
00407 sStatusTip = QT_TR_NOOP("Opens a browser to show the Python modules");
00408 }
00409
00410 StdCmdPythonHelp::~StdCmdPythonHelp()
00411 {
00412 if (server) {
00413 server->close();
00414 delete server;
00415 }
00416 }
00417
00418 void StdCmdPythonHelp::activated(int iMsg)
00419 {
00420
00421 qint16 port = 7465;
00422 if (!this->server)
00423 this->server = new HttpServer();
00424
00425
00426 if (this->server->isListening() ||
00427 this->server->listen(QHostAddress(QHostAddress::LocalHost), port)) {
00428
00429 bool failed = true;
00430
00431
00432
00433 Base::PyGILStateLocker lock;
00434 PyObject* module = PyImport_ImportModule("webbrowser");
00435 if (module) {
00436
00437 PyObject* dict = PyModule_GetDict(module);
00438 PyObject* func = PyDict_GetItemString(dict, "open");
00439 if (func) {
00440 char szBuf[201];
00441 snprintf(szBuf, 200, "http://localhost:%d", port);
00442 PyObject* args = Py_BuildValue("(s)", szBuf);
00443 PyObject* result = PyEval_CallObject(func,args);
00444 if (result)
00445 failed = false;
00446
00447
00448 Py_XDECREF(result);
00449 Py_DECREF(args);
00450 Py_DECREF(module);
00451 }
00452 }
00453
00454
00455 if (failed) {
00456 QMessageBox::critical(Gui::getMainWindow(), QObject::tr("No Browser"),
00457 QObject::tr("Unable to open your browser.\n\n"
00458 "Please open a browser window and type in: http://localhost:%1.").arg(port));
00459 }
00460 }
00461 else {
00462 QMessageBox::critical(Gui::getMainWindow(), QObject::tr("No Server"),
00463 QObject::tr("Unable to start the server to port %1: %2.").arg(port).arg(server->errorString()));
00464 }
00465 }
00466
00467 bool Gui::OpenURLInBrowser(const char * URL)
00468 {
00469
00470 bool failed = true;
00471 Base::PyGILStateLocker lock;
00472 PyObject* module = PyImport_ImportModule("webbrowser");
00473 if (module) {
00474
00475 PyObject* dict = PyModule_GetDict(module);
00476 PyObject* func = PyDict_GetItemString(dict, "open");
00477 if (func) {
00478 PyObject* args = Py_BuildValue("(s)", URL);
00479 PyObject* result = PyEval_CallObject(func,args);
00480 if (result)
00481 failed = false;
00482
00483
00484 Py_XDECREF(result);
00485 Py_DECREF(args);
00486 Py_DECREF(module);
00487 }
00488 }
00489
00490
00491 if (failed) {
00492 QMessageBox::critical(Gui::getMainWindow(), QObject::tr("No Browser"),
00493 QObject::tr("Unable to open your system browser."));
00494 return false;
00495 }
00496
00497 return true;
00498 }
00499
00500
00501 #include "moc_OnlineDocumentation.cpp"
00502