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