1 /*
2     This file is a part of the RepSnapper project.
3     Copyright (C) 2010 Michael Meeks
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include "config.h"
20 #include "stdafx.h"
21 
22 #include <string>
23 #include <vector>
24 
25 #include <giomm/file.h>
26 #include <gtkglmm.h>
27 
28 #include "ui/view.h"
29 #include "ui/progress.h"
30 #include "gcode/gcode.h"
31 #include "model.h"
32 
33 using namespace std;
34 
35 GUI *gui;
36 
37 struct CommandLineOptions
38 {
39 public:
40 	bool use_gui;
41 	string stl_input_path;
42 	string binary_output_path;
43 	string gcode_output_path;
44 	string settings_path;
45 	string printerdevice_path;
46   string svg_output_path;
47   bool svg_single_output;
48 	std::vector<std::string> files;
49 private:
initCommandLineOptions50 	void init ()
51 	{
52 		// specify defaults here or in the block below
53 		use_gui = true;
54 	}
versionCommandLineOptions55 	void version ()
56 	{
57 		printf(_("Version: %s\n"), VERSION);
58 		exit (1);
59 	}
usageCommandLineOptions60 	void usage ()
61 	{
62 	  fprintf (stderr, _("Version: %s\n"), VERSION);
63 	  fprintf (stderr, _("Usage: repsnapper [OPTION]... [FILE]...\n"
64 			     "Start reprap control software and load [FILES]\n"
65 			     "Options:\n"
66 			     "  -t, --no-gui           act as a head-less renderer\n"
67 			     "  -i, --input [file]     read input Model [file]\n"
68 			     "  -b, --binary [file]    batch convert input file to binary STL\n"
69 			     "  -o, --output [file]    if not head-less (-t),\n"
70 			     "                         enter non-printing GUI mode\n"
71 			     "                         only able to output gcode to [file]\n"
72 			     "  --svg [file]           slice to SVG file\n"
73 			     "  --ssvg [file]          slice to single layer SVG files [file]NNNN.svg\n"
74 			     "  -s, --settings [file]  read render settings [file]\n"
75 			     "  -h, --help             show this help\n"
76 			     "\n"
77 			     "Report bugs to #repsnapper, irc.freenode.net\n\n"));
78 		exit (1);
79 	}
80 public:
81 
CommandLineOptionsCommandLineOptions82 	CommandLineOptions(int argc, char **argv)
83 	{
84 		init ();
85 		for (int i = 1; i < argc; i++) {
86 			const char *arg = argv[i];
87 			bool param = i < argc - 1;
88 
89 		        /**/ if (param && (!strcmp (arg, "-i") ||
90 					   !strcmp (arg, "--input")))
91 				stl_input_path = argv[++i];
92 			else if (param && (!strcmp (arg, "-b") ||
93 					   !strcmp (arg, "--binary"))) {
94 				binary_output_path = argv[++i];
95 				use_gui = false;
96 			}
97 			else if (param && (!strcmp (arg, "-p") ||
98 					   !strcmp (arg, "--printnow")))
99 			        printerdevice_path = argv[++i];
100 
101 			else if (param && (!strcmp (arg, "-o") ||
102 					   !strcmp (arg, "--output")))
103 				gcode_output_path = argv[++i];
104 			else if (param && (!strcmp (arg, "-s") ||
105 					   !strcmp (arg, "--settings")))
106 				settings_path = argv[++i];
107 			else if (!strcmp (arg, "-t") || !strcmp (arg, "--no-gui"))
108 				use_gui = false;
109 			else if (!strcmp (arg, "--help") || !strcmp (arg, "-h") ||
110 				 !strcmp (arg, "/?"))
111 				usage();
112 			else if (!strcmp (arg, "--svg")) {
113 				svg_output_path = argv[++i];
114 				svg_single_output = false;
115 			}
116 			else if (!strcmp (arg, "--ssvg")) {
117 				svg_output_path = argv[++i];
118 				svg_single_output = true;
119 			}
120 			else if (!strcmp (arg, "--version") || !strcmp (arg, "-v"))
121 				version();
122 			else
123 				files.push_back (std::string (argv[i]));
124 		}
125 	}
126 	// add more options above
127 };
128 
find_global_config(const std::string filename)129 Glib::RefPtr<Gio::File> find_global_config(const std::string filename) {
130   std::vector<std::string> dirs = Platform::getConfigPaths();
131   Glib::RefPtr<Gio::File> f;
132   for (std::vector<std::string>::const_iterator i = dirs.begin();
133        i != dirs.end(); ++i) {
134     std::string f_name = Glib::build_filename (*i, filename);
135     f = Gio::File::create_for_path(f_name);
136     if(f->query_exists()) {
137       return f;
138     }
139   }
140   return Glib::RefPtr<Gio::File>();
141 }
142 
main(int argc,char ** argv)143 int main(int argc, char **argv)
144 {
145   Glib::thread_init();
146 
147   // gdk_threads_init();
148 
149   // gdk_threads_enter();
150   Gtk::Main tk(argc, argv);
151   // gdk_threads_leave();
152 
153   gchar *locale_dir;
154 
155 #ifdef G_OS_WIN32
156   char *inst_dir;
157   inst_dir = g_win32_get_package_installation_directory_of_module (NULL);
158   locale_dir = g_build_filename (inst_dir, "share", "locale", NULL);
159   g_free (inst_dir);
160 #else
161   locale_dir = g_strdup (LOCALEDIR);
162 #endif
163   bindtextdomain (GETTEXT_PACKAGE, locale_dir);
164   textdomain (GETTEXT_PACKAGE);
165 
166   //cerr << locale_dir<< endl;
167   g_free(locale_dir);
168   locale_dir = NULL;
169 
170   save_locales();
171 
172   CommandLineOptions opts (argc, argv);
173 
174   Platform::setBinaryPath (argv[0]);
175 
176   try {
177     std::string user_config_dir = Glib::build_filename (Glib::get_user_config_dir(), "repsnapper");
178     Gio::File::create_for_path(user_config_dir)->make_directory_with_parents();
179   } catch(Gio::Error e) {
180     switch(e.code()) {
181     case Gio::Error::EXISTS:
182       // Directory has already been created.  Normal.
183       break;
184 
185     default:
186       Gtk::MessageDialog dialog (_("Couldn't create user config directory!"),
187 				 false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE);
188       dialog.set_secondary_text(e.what());
189       dialog.run();
190       return 1;
191     }
192   }
193 
194   std::vector<std::string> user_config_bits(3);
195   user_config_bits[0] = Glib::get_user_config_dir();
196   user_config_bits[1] = "repsnapper";
197   user_config_bits[2] = "repsnapper.conf";
198 
199   std::string user_config_file = Glib::build_filename (user_config_bits);
200   Glib::RefPtr<Gio::File> conf = Gio::File::create_for_path(user_config_file);
201   Glib::RefPtr<Gio::File> global_conf = find_global_config("repsnapper.conf");
202   if(!global_conf) {
203     Gtk::MessageDialog dialog (_("Couldn't find global configuration!"),
204 			       false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE);
205     dialog.set_secondary_text (_("It is likely that repsnapper is not correctly installed."));
206     dialog.run();
207     return 1;
208   }
209 
210   try {
211     // try to copy to user config, if it doesn't exist ...
212     if (!conf->query_exists())
213         global_conf->copy(conf);
214   } catch(Gio::Error e) {
215     switch(e.code()) {
216     case Gio::Error::EXISTS:
217       // Forget about it, the user already has a config.  This is the normal case.
218       break;
219 
220     case Gio::Error::PERMISSION_DENIED:
221     {
222       // Fall back to global config
223       Gtk::MessageDialog dialog (_("Unable to create user config"), false,
224                                 Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE);
225       dialog.set_secondary_text(e.what() + _("\nFalling back to global config. Settings will not be saved."));
226       dialog.run();
227       break;
228     }
229 
230     default:
231     {
232       Gtk::MessageDialog dialog (_("Failed to locate config"), false,
233 				 Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE);
234       dialog.set_secondary_text(e.what());
235       dialog.run();
236       return 1;
237     }
238     }
239   }
240 
241   Model *model = new Model();
242 
243   if (opts.settings_path.size() > 0)
244     conf = Gio::File::create_for_path(opts.settings_path);
245 
246   // first load global config to make sure all settings exist
247   if (global_conf->query_exists())
248     model->LoadConfig(global_conf);
249   if (conf->query_exists())
250     model->LoadConfig(conf);
251 
252   bool nonprintingmode = false;
253 
254   if (opts.gcode_output_path.size() > 0) {
255     nonprintingmode = true;
256   }
257 
258   if (opts.printerdevice_path.size() > 0) {
259     model->settings.set_string("Hardware","PortName",opts.printerdevice_path);
260   }
261 
262   if (!opts.use_gui) {
263       if (opts.settings_path.size() > 0)
264         model->LoadConfig(Gio::File::create_for_path(opts.settings_path));
265 
266       ViewProgress vprog(new Gtk::HBox(),new Gtk::ProgressBar(),new Gtk::Label());
267       vprog.set_terminal_output(true);
268       model->SetViewProgress(&vprog);
269       model->statusbar=NULL;
270 
271       if (opts.stl_input_path.size() > 0) {
272 	model->Read(Gio::File::create_for_path(opts.stl_input_path));
273       }
274 
275       if (opts.printerdevice_path.size() > 0) {
276 	Printer printer(NULL);
277 	printer.setModel(model);
278 	printer.Connect();
279 	printer.StartPrinting();
280 	printer.Disconnect();
281 	return 0;
282       }
283 
284       if (opts.gcode_output_path.size() > 0) {
285 	model->ConvertToGCode();
286         model->WriteGCode(Gio::File::create_for_path(opts.gcode_output_path));
287       }
288       else if (opts.svg_output_path.size() > 0) {
289 	model->SliceToSVG(Gio::File::create_for_path(opts.svg_output_path),
290 			  opts.svg_single_output);
291       }
292       else if (opts.binary_output_path.size() > 0) {
293 	model->SaveStl(Gio::File::create_for_path(opts.binary_output_path));
294       }
295       else cerr << _("No output file given") << endl;
296     delete model;
297     return 0;
298   }
299 
300   Gdk::GL::init(argc, argv);
301 
302   View* mainwin = View::create(model);
303 
304   mainwin->setNonPrintingMode(nonprintingmode, opts.gcode_output_path);
305 
306   Glib::RefPtr<Gio::File> iconfile = find_global_config("repsnapper.svg");
307   mainwin->set_icon_file(iconfile);
308   mainwin->set_title("Repsnapper");
309 
310   if (opts.stl_input_path.size() > 0) {
311     model->Read(Gio::File::create_for_path(opts.stl_input_path));
312   }
313 
314   for (uint i = 0; i < opts.files.size(); i++)
315     model->Read(Gio::File::create_for_path(opts.files[i]));
316 
317   model->ModelChanged();
318 
319   tk.run();
320 
321   delete mainwin;
322   delete model;
323 
324   return 0;
325 }
326