MainGui.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   (c) Jürgen Riegel (juergen.riegel@web.de) 2008                        *   
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU Library General Public License (LGPL)   *
00008  *   as published by the Free Software Foundation; either version 2 of     *
00009  *   the License, or (at your option) any later version.                   *
00010  *   for detail see the LICENCE text file.                                 *
00011  *                                                                         *
00012  *   FreeCAD is distributed in the hope that it will be useful,            *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * 
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU Library General Public License for more details.                  *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU Library General Public     *
00018  *   License along with FreeCAD; if not, write to the Free Software        * 
00019  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
00020  *   USA                                                                   *
00021  *                                                                         *
00022  *   Juergen Riegel 2002                                                   *
00023  ***************************************************************************/
00024 #include <FCConfig.h>
00025 
00026 #ifdef _PreComp_
00027 #   undef _PreComp_
00028 #endif
00029 
00030 #ifdef FC_OS_LINUX
00031 #   include <unistd.h>
00032 #endif
00033 
00034 #if HAVE_CONFIG_H
00035 #   include <config.h>
00036 #endif // HAVE_CONFIG_H
00037 
00038 #include <cstdio>
00039 #include <QApplication>
00040 #include <QFile>
00041 #include <QMessageBox>
00042 #include <QLocale>
00043 #include <QTextCodec>
00044 
00045 #include <QDomDocument>
00046 #include <QXmlSimpleReader>
00047 #include <QXmlInputSource>
00048 #include <QDir>
00049 #include <QFile>
00050 #include <QFileInfo>
00051 
00052 // FreeCAD header
00053 #include <Base/Console.h>
00054 #include <Base/Interpreter.h>
00055 #include <Base/Parameter.h>
00056 #include <Base/Exception.h>
00057 #include <Base/Factory.h>
00058 #include <App/Application.h>
00059 #include <Gui/BitmapFactory.h>
00060 #include <Gui/Icons/background.xpm>
00061 #include <Gui/Application.h>
00062 
00063 void PrintInitHelp(void);
00064 
00065 const char sBanner[] = "\xc2\xa9 Juergen Riegel, Werner Mayer, Yorik van Havre 2001-2011\n"\
00066 "  #####                 ####  ###   ####  \n" \
00067 "  #                    #      # #   #   # \n" \
00068 "  #     ##  #### ####  #     #   #  #   # \n" \
00069 "  ####  # # #  # #  #  #     #####  #   # \n" \
00070 "  #     #   #### ####  #    #     # #   # \n" \
00071 "  #     #   #    #     #    #     # #   #  ##  ##  ##\n" \
00072 "  #     #   #### ####   ### #     # ####   ##  ##  ##\n\n" ;
00073 
00074 class Branding
00075 {
00076 public:
00077     struct UserDefines
00078     {
00079         std::string windowTitle;
00080         std::string windowIcon;
00081         std::string programLogo;
00082         std::string splashScreen;
00083     };
00084 
00085     Branding()
00086     {
00087     }
00088 
00089     bool readFile(const QString& fn)
00090     {
00091         QFile file(fn);
00092         if (!file.open(QFile::ReadOnly))
00093             return false;
00094         if (!evaluateXML(&file, domDocument))
00095             return false;
00096         file.close();
00097         return true;
00098     }
00099     UserDefines getUserDefines() const
00100     {
00101         UserDefines ud;
00102         QDomElement root = domDocument.documentElement();
00103         QDomElement child;
00104         if (!root.isNull()) {
00105             child = root.firstChildElement(QLatin1String("WindowTitle"));
00106             if (!child.isNull())
00107                 ud.windowTitle = (const char*)child.text().toUtf8();
00108             child = root.firstChildElement(QLatin1String("WindowIcon"));
00109             if (!child.isNull())
00110                 ud.windowIcon = (const char*)child.text().toUtf8();
00111             child = root.firstChildElement(QLatin1String("ProgramLogo"));
00112             if (!child.isNull())
00113                 ud.programLogo = (const char*)child.text().toUtf8();
00114             child = root.firstChildElement(QLatin1String("SplashScreen"));
00115             if (!child.isNull())
00116                 ud.splashScreen = (const char*)child.text().toUtf8();
00117         }
00118         return ud;
00119     }
00120 
00121 private:
00122     bool evaluateXML(QIODevice *device, QDomDocument& xmlDocument)
00123     {
00124         QString errorStr;
00125         int errorLine;
00126         int errorColumn;
00127 
00128         if (!xmlDocument.setContent(device, true, &errorStr, &errorLine,
00129                                     &errorColumn)) {
00130             return false;
00131         }
00132 
00133         QDomElement root = xmlDocument.documentElement();
00134         if (root.tagName() != QLatin1String("Branding")) {
00135             return false;
00136         }
00137         else if (root.hasAttribute(QLatin1String("version"))) {
00138             QString attr = root.attribute(QLatin1String("version"));
00139             if (attr != QLatin1String("1.0"))
00140                 return false;
00141         }
00142 
00143         return true;
00144     }
00145     QDomDocument domDocument;
00146 };
00147 
00148 class ProgramOptions
00149 {
00150 public:
00151     ProgramOptions()
00152     {
00153         newcout = new ProgramOptionsStream(out);
00154         oldcout = std::cout.rdbuf(newcout);
00155         out.reserve(80);
00156         newcerr = new ProgramOptionsStream(err);
00157         oldcerr = std::cerr.rdbuf(newcerr);
00158         err.reserve(80);
00159 
00160         error = true;
00161         ::atexit(ProgramOptions::failure);
00162     }
00163     ~ProgramOptions()
00164     {
00165         std::cout.rdbuf(oldcout);
00166         delete newcout;
00167         std::cerr.rdbuf(oldcerr);
00168         delete newcerr;
00169         error = false;
00170     }
00171     static void failure()
00172     {
00173         if (error) {
00174             int argc=0;
00175             QApplication app(argc,0);
00176             QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
00177             if (!err.empty()) {
00178                 QString msg = QString::fromAscii(err.c_str());
00179                 QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
00180                 QMessageBox::critical(0, appName, s);
00181             }
00182             else if (!out.empty()) {
00183                 QString msg = QString::fromAscii(out.c_str());
00184                 QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
00185                 QMessageBox::information(0, appName, s);
00186             }
00187         }
00188     }
00189 
00190 private:
00191     class ProgramOptionsStream : public std::streambuf
00192     {
00193     public:
00194         ProgramOptionsStream(std::string& s) : buf(s)
00195         {
00196         }
00197         int overflow(int c = EOF)
00198         {
00199             if (c != EOF)
00200                 buf.push_back((char)c);
00201             return c;
00202         }
00203         int sync()
00204         {
00205             return 0;
00206         }
00207     private:
00208         std::string& buf;
00209     };
00210 
00211 private:
00212     friend class ProgramOptionsStream;
00213     std::streambuf* oldcout;
00214     std::streambuf* newcout;
00215     std::streambuf* oldcerr;
00216     std::streambuf* newcerr;
00217     static std::string out, err;
00218     static bool error;
00219 };
00220 
00221 bool ProgramOptions::error = false;
00222 std::string ProgramOptions::out;
00223 std::string ProgramOptions::err;
00224 
00225 #if defined (FC_OS_LINUX) || defined(FC_OS_BSD)
00226 QString myDecoderFunc(const QByteArray &localFileName)
00227 {
00228     QTextCodec* codec = QTextCodec::codecForName("UTF-8");
00229     return codec->toUnicode(localFileName);
00230 }
00231 
00232 QByteArray myEncoderFunc(const QString &fileName)
00233 {
00234     QTextCodec* codec = QTextCodec::codecForName("UTF-8");
00235     return codec->fromUnicode(fileName);
00236 }
00237 #endif
00238 
00239 int main( int argc, char ** argv )
00240 {
00241 #if defined (FC_OS_LINUX) || defined(FC_OS_BSD)
00242     // Make sure to setup the Qt locale system before setting LANG and LC_ALL to C.
00243     // which is needed to use the system locale settings.
00244     (void)QLocale::system();
00245     // https://sourceforge.net/apps/mantisbt/free-cad/view.php?id=399
00246     // Because of setting LANG=C the Qt automagic to use the correct encoding
00247     // for file names is broken. This is a workaround to force the use of UTF-8 encoding
00248     QFile::setEncodingFunction(myEncoderFunc);
00249     QFile::setDecodingFunction(myDecoderFunc);
00250     // Make sure that we use '.' as decimal point. See also
00251     // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=559846
00252     putenv("LANG=C");
00253     putenv("LC_ALL=C");
00254     putenv("PYTHONPATH=");
00255 #elif defined(FC_OS_MACOSX)
00256     (void)QLocale::system();
00257     putenv("LANG=C");
00258     putenv("LC_ALL=C");
00259     putenv("PYTHONPATH=");
00260 #else
00261     setlocale(LC_NUMERIC, "C");
00262     _putenv("PYTHONPATH=");
00263 #endif
00264 
00265     // Name and Version of the Application
00266     App::Application::Config()["ExeName"] = "FreeCAD";
00267     App::Application::Config()["ExeVendor"] = "FreeCAD";
00268     App::Application::Config()["AppDataSkipVendor"] = "true";
00269     App::Application::Config()["MaintainerUrl"] = "http://apps.sourceforge.net/mediawiki/free-cad/index.php?title=Main_Page";
00270 
00271     // set the banner (for logging and console)
00272     App::Application::Config()["ConsoleBanner"] = sBanner;
00273     App::Application::Config()["AppIcon"] = "freecad";
00274     App::Application::Config()["SplashPicture"] = "freecadsplash";
00275     App::Application::Config()["StartWorkbench"] = "StartWorkbench";
00276     //App::Application::Config()["HiddenDockWindow"] = "Property editor";
00277     App::Application::Config()["SplashAlignment" ] = "Bottom|Left";
00278     App::Application::Config()["SplashTextColor" ] = "#ffffff"; // white
00279 
00280     try {
00281         // Init phase ===========================================================
00282         // sets the default run mode for FC, starts with gui if not overridden in InitConfig...
00283         App::Application::Config()["RunMode"] = "Gui";
00284 
00285         // Inits the Application 
00286         ProgramOptions po;
00287         App::Application::init(argc,argv);
00288         Gui::Application::initApplication();
00289     }
00290     catch (const Base::Exception& e) {
00291         // Popup an own dialog box instead of that one of Windows
00292         QApplication app(argc,argv);
00293         QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
00294         QString msg;
00295         msg = QObject::tr("While initializing %1 the  following exception occurred: '%2'\n\n"
00296                           "Python is searching for its files in the following directories:\n%3\n\n"
00297                           "Python version information:\n%4\n")
00298                           .arg(appName).arg(QString::fromUtf8(e.what()))
00299                           .arg(QString::fromUtf8(Py_GetPath())).arg(QString::fromAscii(Py_GetVersion()));
00300         const char* pythonhome = getenv("PYTHONHOME");
00301         if (pythonhome) {
00302             msg += QObject::tr("\nThe environment variable PYTHONHOME is set to '%1'.")
00303                 .arg(QString::fromUtf8(pythonhome));
00304             msg += QObject::tr("\nSetting this environment variable might cause Python to fail. "
00305                 "Please contact your administrator to unset it on your system.\n\n");
00306         } else {
00307             msg += QObject::tr("\nPlease contact the application's support team for more information.\n\n");
00308         }
00309 
00310         QMessageBox::critical(0, QObject::tr("Initialization of %1 failed").arg(appName), msg);
00311         exit(100);
00312     }
00313     catch (...) {
00314         // Popup an own dialog box instead of that one of Windows
00315         QApplication app(argc,argv);
00316         QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
00317         QString msg = QObject::tr("Unknown runtime error occurred while initializing %1.\n\n"
00318                                   "Please contact the application's support team for more information.\n\n").arg(appName);
00319         QMessageBox::critical(0, QObject::tr("Initialization of %1 failed").arg(appName), msg);
00320         exit(101);
00321     }
00322 
00323     // Now it's time to read-in the file branding.xml if it exists
00324     Branding brand;
00325     QString path = QString::fromUtf8(App::GetApplication().GetHomePath());
00326     QFileInfo fi(path, QString::fromAscii("branding.xml"));
00327     if (brand.readFile(fi.absoluteFilePath())) {
00328         Branding::UserDefines ud = brand.getUserDefines();
00329         if (!ud.windowTitle.empty())
00330             App::Application::Config()["WindowTitle"] = ud.windowTitle;
00331         if (!ud.windowIcon.empty())
00332             App::Application::Config()["WindowIcon"] = ud.windowIcon;
00333         if (!ud.programLogo.empty())
00334             App::Application::Config()["ProgramLogo"] = ud.programLogo;
00335         if (!ud.splashScreen.empty())
00336             App::Application::Config()["SplashPicture"] = ud.splashScreen;
00337     }
00338 
00339     // Run phase ===========================================================
00340     Base::RedirectStdOutput stdcout;
00341     Base::RedirectStdLog    stdclog;
00342     Base::RedirectStdError  stdcerr;
00343     std::streambuf* oldcout = std::cout.rdbuf(&stdcout);
00344     std::streambuf* oldclog = std::clog.rdbuf(&stdclog);
00345     std::streambuf* oldcerr = std::cerr.rdbuf(&stdcerr);
00346 
00347     try {
00348         if (App::Application::Config()["RunMode"] == "Gui")
00349             Gui::Application::runApplication();
00350         else
00351             App::Application::runApplication();
00352     }
00353     catch (const Base::Exception& e) {
00354         Base::Console().Error("%s\n", e.what());
00355     }
00356     catch (...) {
00357         Base::Console().Error("Application unexpectedly terminated\n");
00358     }
00359 
00360     std::cout.rdbuf(oldcout);
00361     std::clog.rdbuf(oldclog);
00362     std::cerr.rdbuf(oldcerr);
00363 
00364     // Destruction phase ===========================================================
00365     Base::Console().Log("%s terminating...\n",App::Application::Config()["ExeName"].c_str());
00366 
00367     // cleans up 
00368     App::Application::destruct();
00369 
00370     Base::Console().Log("%s completely terminated\n",App::Application::Config()["ExeName"].c_str());
00371 
00372     return 0;
00373 }

Generated on Wed Nov 23 19:00:21 2011 for FreeCAD by  doxygen 1.6.1