xref: /glogg/src/main.cpp (revision c9a9366412fcda118aaadfe3742db8727a163a0f)
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2013, 2014 Nicolas Bonnefon and other contributors
3  *
4  * This file is part of glogg.
5  *
6  * glogg is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * glogg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <QApplication>
21 #include <QFileInfo>
22 
23 #include <memory>
24 
25 #include <boost/program_options.hpp>
26 namespace po = boost::program_options;
27 
28 #include <iostream>
29 #include <iomanip>
30 using namespace std;
31 
32 #ifdef _WIN32
33 #include "unistd.h"
34 #endif
35 
36 #include "persistentinfo.h"
37 #include "sessioninfo.h"
38 #include "configuration.h"
39 #include "filterset.h"
40 #include "recentfiles.h"
41 #include "session.h"
42 #include "mainwindow.h"
43 #include "savedsearches.h"
44 #include "loadingstatus.h"
45 
46 #include "externalcom.h"
47 #ifdef GLOGG_SUPPORTS_DBUS
48 #include "dbusexternalcom.h"
49 #elif GLOGG_SUPPORTS_WINIPC
50 #include "winexternalcom.h"
51 #endif
52 
53 
54 #include "log.h"
55 
56 static void print_version();
57 
58 int main(int argc, char *argv[])
59 {
60     QApplication app(argc, argv);
61 
62     string filename = "";
63 
64     // Configuration
65     bool new_session = false;
66     bool load_session = false;
67     bool multi_instance = false;
68 #ifdef _WIN32
69     bool log_to_file = false;
70 #endif
71 
72     TLogLevel logLevel = logWARNING;
73 
74     try {
75         po::options_description desc("Usage: glogg [options] [file]");
76         desc.add_options()
77             ("help,h", "print out program usage (this message)")
78             ("version,v", "print glogg's version information")
79             ("multi,m", "allow multiple instance of glogg to run simultaneously (use together with -s)")
80             ("load-session,s", "load the previous session (default when no file is passed)")
81             ("new-session,n", "do not load the previous session (default when a file is passed)")
82 #ifdef _WIN32
83             ("log,l", "save the log to a file (Windows only)")
84 #endif
85             ("debug,d", "output more debug (include multiple times for more verbosity e.g. -dddd)")
86             ;
87         po::options_description desc_hidden("Hidden options");
88         // For -dd, -ddd...
89         for ( string s = "dd"; s.length() <= 10; s.append("d") )
90             desc_hidden.add_options()(s.c_str(), "debug");
91 
92         desc_hidden.add_options()
93             ("input-file", po::value<string>(), "input file")
94             ;
95 
96         po::options_description all_options("all options");
97         all_options.add(desc).add(desc_hidden);
98 
99         po::positional_options_description positional;
100         positional.add("input-file", 1);
101 
102         int command_line_style = (((po::command_line_style::unix_style ^
103                 po::command_line_style::allow_guessing) |
104                 po::command_line_style::allow_long_disguise) ^
105                 po::command_line_style::allow_sticky);
106 
107         po::variables_map vm;
108         po::store(po::command_line_parser(argc, argv).
109                 options(all_options).
110                 positional(positional).
111                 style(command_line_style).run(),
112                 vm);
113         po::notify(vm);
114 
115         if ( vm.count("help") ) {
116             desc.print(cout);
117             return 0;
118         }
119 
120         if ( vm.count("version") ) {
121             print_version();
122             return 0;
123         }
124 
125         if ( vm.count( "debug" ) )
126             logLevel = logINFO;
127 
128         if ( vm.count( "multi" ) )
129             multi_instance = true;
130 
131         if ( vm.count( "new-session" ) )
132             new_session = true;
133 
134         if ( vm.count( "load-session" ) )
135             load_session = true;
136 
137 #ifdef _WIN32
138         if ( vm.count( "log" ) )
139             log_to_file = true;
140 #endif
141 
142         for ( string s = "dd"; s.length() <= 10; s.append("d") )
143             if ( vm.count( s ) )
144                 logLevel = (TLogLevel) (logWARNING + s.length());
145 
146         if ( vm.count("input-file") )
147             filename = vm["input-file"].as<string>();
148     }
149     catch(exception& e) {
150         cerr << "Option processing error: " << e.what() << endl;
151         return 1;
152     }
153     catch(...) {
154         cerr << "Exception of unknown type!\n";
155     }
156 
157 #ifdef _WIN32
158     if ( log_to_file )
159     {
160         char file_name[255];
161         snprintf( file_name, sizeof file_name, "glogg_%d.log", getpid() );
162         FILE* file = fopen(file_name, "w");
163         Output2FILE::Stream() = file;
164     }
165 #endif
166 
167     FILELog::setReportingLevel( logLevel );
168 
169     if ( ! filename.empty() ) {
170         // Convert to absolute path
171         QFileInfo file( QString::fromStdString( filename ) );
172         filename = file.absoluteFilePath().toStdString();
173     }
174 
175     // External communicator
176     shared_ptr<ExternalCommunicator> externalCommunicator = nullptr;
177     shared_ptr<ExternalInstance> externalInstance = nullptr;
178 
179     try {
180 #ifdef GLOGG_SUPPORTS_DBUS
181         externalCommunicator = make_shared<DBusExternalCommunicator>();
182         externalInstance = shared_ptr<ExternalInstance>(
183                 externalCommunicator->otherInstance() );
184 #elif GLOGG_SUPPORTS_WINIPC
185         externalCommunicator = make_shared<WinExternalCommunicator>();
186         externalInstance = shared_ptr<ExternalInstance>(
187                 externalCommunicator->otherInstance() );
188 #endif
189     }
190     catch(CantCreateExternalErr& e) {
191         LOG(logWARNING) << "Cannot initialise external communication.";
192     }
193 
194     LOG(logDEBUG) << "externalInstance = " << externalInstance;
195     if ( ( ! multi_instance ) && externalInstance ) {
196         uint32_t version = externalInstance->getVersion();
197         LOG(logINFO) << "Found another glogg (version = "
198             << std::setbase(16) << version << ")";
199 
200         externalInstance->loadFile( QString::fromStdString( filename ) );
201 
202         return 0;
203     }
204     else {
205         // FIXME: there is a race condition here. One glogg could start
206         // between the declaration of externalInstance and here,
207         // is it a problem?
208         if ( externalCommunicator )
209             externalCommunicator->startListening();
210     }
211 
212     // Register types for Qt
213     qRegisterMetaType<LoadingStatus>("LoadingStatus");
214 
215     // Register the configuration items
216     GetPersistentInfo().migrateAndInit();
217     GetPersistentInfo().registerPersistable(
218             std::make_shared<SessionInfo>(), QString( "session" ) );
219     GetPersistentInfo().registerPersistable(
220             std::make_shared<Configuration>(), QString( "settings" ) );
221     GetPersistentInfo().registerPersistable(
222             std::make_shared<FilterSet>(), QString( "filterSet" ) );
223     GetPersistentInfo().registerPersistable(
224             std::make_shared<SavedSearches>(), QString( "savedSearches" ) );
225     GetPersistentInfo().registerPersistable(
226             std::make_shared<RecentFiles>(), QString( "recentFiles" ) );
227 #ifdef GLOGG_SUPPORTS_VERSION_CHECKING
228     GetPersistentInfo().registerPersistable(
229             std::make_shared<VersionCheckerConfig>(), QString( "versionChecker" ) );
230 #endif
231 
232 #ifdef _WIN32
233     // Allow the app to raise it's own windows (in case an external
234     // glogg send us a file to open)
235     AllowSetForegroundWindow(ASFW_ANY);
236 #endif
237 
238     // We support high-dpi (aka Retina) displays
239     app.setAttribute( Qt::AA_UseHighDpiPixmaps );
240 
241     // No icon in menus
242     app.setAttribute( Qt::AA_DontShowIconsInMenus );
243 
244     // FIXME: should be replaced by a two staged init of MainWindow
245     GetPersistentInfo().retrieve( QString( "settings" ) );
246 
247     std::unique_ptr<Session> session( new Session() );
248     MainWindow mw( std::move( session ), externalCommunicator );
249 
250     LOG(logDEBUG) << "MainWindow created.";
251     mw.show();
252     // Load the existing session if needed
253     if ( load_session || ( filename.empty() && !new_session ) )
254         mw.reloadSession();
255     mw.loadInitialFile( QString::fromStdString( filename ) );
256     mw.startBackgroundTasks();
257 
258     return app.exec();
259 }
260 
261 static void print_version()
262 {
263     cout << "glogg " GLOGG_VERSION "\n";
264 #ifdef GLOGG_COMMIT
265     cout << "Built " GLOGG_DATE " from " GLOGG_COMMIT "\n";
266 #endif
267     cout << "Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicolas Bonnefon and other contributors\n";
268     cout << "This is free software.  You may redistribute copies of it under the terms of\n";
269     cout << "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n";
270     cout << "There is NO WARRANTY, to the extent permitted by law.\n";
271 }
272