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