]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/dialog.cxx
RedBoot Release TX53-v3 2012-02-08
[karo-tx-redboot.git] / tools / src / libcdl / dialog.cxx
1 //{{{  Banner                           
2
3 //============================================================================
4 //
5 //     dialog.cxx
6 //
7 //     Implementation of the CdlDialog class
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //                                                                          
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2002 Bart Veer
14 // Copyright (C) 1999, 2000 Red Hat, Inc.
15 //
16 // This file is part of the eCos host tools.
17 //
18 // This program is free software; you can redistribute it and/or modify it 
19 // under the terms of the GNU General Public License as published by the Free 
20 // Software Foundation; either version 2 of the License, or (at your option) 
21 // any later version.
22 // 
23 // This program is distributed in the hope that it will be useful, but WITHOUT 
24 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
25 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
26 // more details.
27 // 
28 // You should have received a copy of the GNU General Public License along with
29 // this program; if not, write to the Free Software Foundation, Inc., 
30 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31 //
32 // ----------------------------------------------------------------------------
33 //                                                                          
34 //####COPYRIGHTEND####
35 //============================================================================
36 //#####DESCRIPTIONBEGIN####
37 //
38 // Author(s):   bartv
39 // Contact(s):  bartv
40 // Date:        1999/03/01
41 // Version:     0.01
42 //
43 //####DESCRIPTIONEND####
44 //============================================================================
45
46 //}}}
47 //{{{  #include's                       
48
49 // ----------------------------------------------------------------------------
50 #include "cdlconfig.h"
51
52 // Get the infrastructure types, assertions, tracing and similar
53 // facilities.
54 #include <cyg/infra/cyg_ass.h>
55 #include <cyg/infra/cyg_trac.h>
56
57 // <cdlcore.hxx> defines everything implemented in this module.
58 // It implicitly supplies <string>, <vector> and <map> because
59 // the class definitions rely on these headers.
60 #include <cdlcore.hxx>
61
62 //}}}
63
64 //{{{  Class statics                    
65
66 // ----------------------------------------------------------------------------
67 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlDialogBody);
68
69 // The application code can specify whether or not it supports custom
70 // dialogs. This affects the internals of e.g.
71 // CdlValuable::get_widget_hint(). For now err on the side of caution.
72
73 bool CdlDialogBody::dialogs_enabled     = false;
74
75 void
76 CdlDialogBody::disable_dialogs()
77 {
78     CYG_REPORT_FUNCNAME("CdlDialog::disable_dialogs");
79     dialogs_enabled = false;
80     CYG_REPORT_RETURN();
81 }
82
83 void
84 CdlDialogBody::enable_dialogs()
85 {
86     CYG_REPORT_FUNCNAME("CdlDialog::enable_dialogs");
87     dialogs_enabled = true;
88     CYG_REPORT_RETURN();
89 }
90
91 bool
92 CdlDialogBody::dialogs_are_enabled()
93 {
94     CYG_REPORT_FUNCNAMETYPE("CdlDialog::dialogs_are_enabled", "result %d");
95     bool result = dialogs_enabled;
96     CYG_REPORT_RETVAL(result);
97     return result;
98 }
99
100 //}}}
101 //{{{  Constructor                      
102
103 // ----------------------------------------------------------------------------
104 // Constructor. The real work is actually done in the parse routine.
105 //
106 // There is no data associated with a custom dialog object.
107 CdlDialogBody::CdlDialogBody(std::string name_arg)
108     : CdlNodeBody(name_arg),
109       CdlUserVisibleBody(),
110       CdlParentableBody()
111 {
112     CYG_REPORT_FUNCNAME("CdlDialogBody:: constructor");
113     CYG_REPORT_FUNCARG1XV(this);
114
115     cdldialogbody_cookie = CdlDialogBody_Magic;
116     CYGDBG_MEMLEAK_CONSTRUCTOR();
117     
118     CYG_POSTCONDITION_THISC();
119     CYG_REPORT_RETURN();
120 }
121
122 //}}}
123 //{{{  Destructor                       
124
125 // ----------------------------------------------------------------------------
126 // The real work is done in the base classes.
127
128 CdlDialogBody::~CdlDialogBody()
129 {
130     CYG_REPORT_FUNCNAME("CdlDialogBody:: destructor");
131     CYG_REPORT_FUNCARG1XV(this);
132     CYG_PRECONDITION_THISC();
133
134     cdldialogbody_cookie = CdlDialogBody_Invalid;
135     CYGDBG_MEMLEAK_DESTRUCTOR();
136     
137     CYG_REPORT_RETURN();
138 }
139
140 //}}}
141 //{{{  parse_dialog()                   
142
143 // ----------------------------------------------------------------------------
144 // Parsing a dialog definition.
145 int
146 CdlDialogBody::parse_dialog(CdlInterpreter interp, int argc, const char* argv[])
147 {
148     CYG_REPORT_FUNCNAMETYPE("CdlDialog::parse_dialog", "result %d");
149     CYG_REPORT_FUNCARG1("argc %d", argc);
150     CYG_PRECONDITION_CLASSC(interp);
151     
152     std::string diag_argv0      = CdlParse::get_tcl_cmd_name(argv[0]);
153
154     CdlLoadable  loadable       = interp->get_loadable();
155     CdlContainer parent         = interp->get_container();       
156     CdlToplevel  toplevel       = interp->get_toplevel();
157     CYG_ASSERT_CLASSC(loadable);        // There should always be a loadable during parsing
158     CYG_ASSERT_CLASSC(parent);
159     CYG_ASSERT_CLASSC(toplevel);
160
161     // The new dialog should be created and added to the loadable
162     // early on. If there is a parsing error it will get cleaned up
163     // automatically as a consequence of the loadable destructor.
164     // However it is necessary to validate the name first. Errors
165     // should be reported via CdlParse::report_error(), which
166     // may result in an exception.
167     CdlDialog    new_dialog     = 0;
168     CdlNode      old_node       = 0;
169     std::vector<CdlInterpreterCommandEntry>* old_commands = 0;
170     int          result         = TCL_OK;
171     
172     // Currently there are no command-line options. This may change in future.
173     if (3 != argc) {
174         CdlParse::report_error(interp, "", std::string("Incorrect number of arguments to `") + diag_argv0 +
175                                "'\nExpecting name and properties list.");
176     } else if (!Tcl_CommandComplete(CDL_TCL_CONST_CAST(char*, argv[2]))) {
177         CdlParse::report_error(interp, "", std::string("Invalid property list for cdl_dialog `") + argv[1] + "'.");
178     } else if (0 != toplevel->lookup(argv[1])) {
179         CdlParse::report_error(interp, "", std::string("Dialog `") + argv[1] + "' cannot be loaded.\n" +
180                                "The name is already in use.");
181     } else {
182
183         try {
184             new_dialog = new CdlDialogBody(argv[1]);
185             toplevel->add_node(loadable, parent, new_dialog);
186
187             // Push the dialog as the current base object early on.
188             // This aids diagnostics.
189             old_node = interp->push_node(new_dialog);
190
191             std::string tcl_result;
192             std::vector<CdlInterpreterCommandEntry>  new_commands;
193             static CdlInterpreterCommandEntry commands[] =
194             {
195                 CdlInterpreterCommandEntry("init_proc",          &CdlWizardBody::parse_init_proc    ),
196                 CdlInterpreterCommandEntry("update_proc",        &CdlDialogBody::parse_update_proc  ),
197                 CdlInterpreterCommandEntry("display_proc",       &CdlDialogBody::parse_display_proc ),
198                 CdlInterpreterCommandEntry("confirm_proc",       &CdlWizardBody::parse_confirm_proc ),
199                 CdlInterpreterCommandEntry("cancel_proc",        &CdlWizardBody::parse_cancel_proc  ),
200                 CdlInterpreterCommandEntry("",                   0                                  ),
201             };
202             int i;
203             for (i = 0; 0 != commands[i].command; i++) {
204                 new_commands.push_back(commands[i]);
205             }
206             CdlParentableBody::add_property_parsers(new_commands);
207             CdlUserVisibleBody::add_property_parsers(new_commands);
208             CdlNodeBody::add_property_parsers(new_commands);
209     
210             // Now evaluate the body. If an error occurs then typically
211             // this will be reported via CdlParse::report_error(),
212             // but any exceptions will have been intercepted and
213             // turned into a Tcl error.
214             old_commands = interp->push_commands(new_commands);
215             result = interp->eval(argv[2], tcl_result);
216             interp->pop_commands(old_commands);
217             old_commands = 0;
218             interp->pop_node(old_node);
219             old_node = 0;
220         
221             if (TCL_OK == result) {
222                 // Even if there were errors, they were not fatal. There may
223                 // now be a number of properties for this option, and some
224                 // validation should take place. Start with the base classes.
225                 new_dialog->CdlNodeBody::check_properties(interp);
226                 new_dialog->CdlUserVisibleBody::check_properties(interp);
227                 new_dialog->CdlParentableBody::check_properties(interp);
228
229                 // The init_proc and update_proc properties are optional.
230                 // The display_proc, confirm_proc and cancel_proc properties
231                 // are compulsory.
232                 if (new_dialog->count_properties(CdlPropertyId_InitProc) > 1) {
233                     CdlParse::report_error(interp, "", "A dialog should have only one `init_proc' property.");
234                 }
235                 if (new_dialog->count_properties(CdlPropertyId_UpdateProc) > 1) {
236                     CdlParse::report_error(interp, "", "A dialog should have only one `update_proc' property.");
237                 }
238                 if (new_dialog->count_properties(CdlPropertyId_DisplayProc) != 1) {
239                     CdlParse::report_error(interp, "", "A dialog should have one `display_proc' property.");
240                 }
241                 if (new_dialog->count_properties(CdlPropertyId_ConfirmProc) != 1) {
242                     CdlParse::report_error(interp, "", "A dialog should have one `confirm_proc' property.");
243                 }
244                 if (new_dialog->count_properties(CdlPropertyId_CancelProc) != 1) {
245                     CdlParse::report_error(interp, "", "A dialog should have one `cancel_proc' property.");
246                 }
247             }
248             
249         } catch(...) {
250             if (0 != new_dialog) {
251                 delete new_dialog;
252             }
253             if (0 != old_node) {
254                 interp->pop_node(old_node);
255             }
256             if (0 != old_commands) {
257                 interp->pop_commands(old_commands);
258             }
259             throw;
260         }
261     }
262     
263     CYG_REPORT_RETVAL(result);
264     return result;
265 }
266
267
268 // ----------------------------------------------------------------------------
269 // Syntax: display_proc <tclcode>
270 int
271 CdlDialogBody::parse_display_proc(CdlInterpreter interp, int argc, const char* argv[])
272 {
273     CYG_REPORT_FUNCNAMETYPE("parse_display_proc", "result %d");
274
275     int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_DisplayProc, 0, 0);
276     
277     CYG_REPORT_RETVAL(result);
278     return result;
279 }
280
281 // ----------------------------------------------------------------------------
282 // Syntax: update_proc <tclcode>
283 int
284 CdlDialogBody::parse_update_proc(CdlInterpreter interp, int argc, const char* argv[])
285 {
286     CYG_REPORT_FUNCNAMETYPE("parse_update_proc", "result %d");
287
288     int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_UpdateProc, 0, 0);
289     
290     CYG_REPORT_RETVAL(result);
291     return result;
292 }
293
294 //}}}
295 //{{{  Persistence                      
296
297 // ----------------------------------------------------------------------------
298 // For now there is no information in a custom dialog that should end
299 // up in a save file, but it is still desirable to override the base
300 // class member function.
301
302 void
303 CdlDialogBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool minimal)
304 {
305     CYG_REPORT_FUNCNAME("CdlDialog::save");
306     CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
307     CYG_PRECONDITION_THISC();
308
309     CYG_UNUSED_PARAM(CdlInterpreter, interp);
310     CYG_UNUSED_PARAM(Tcl_Channel, chan);
311     CYG_UNUSED_PARAM(int, indentation);
312     CYG_UNUSED_PARAM(bool, minimal);
313     
314     CYG_REPORT_RETURN();
315 }
316
317 //}}}
318 //{{{  Data access                      
319
320 // ----------------------------------------------------------------------------
321 bool
322 CdlDialogBody::has_init_proc() const
323 {
324     CYG_REPORT_FUNCNAMETYPE("CdlDialog::has_init_proc", "result %d");
325     CYG_REPORT_FUNCARG1XV(this);
326     CYG_PRECONDITION_THISC();
327
328     bool result = has_property(CdlPropertyId_InitProc);
329     CYG_REPORT_RETVAL(result);
330     return result;
331 }
332
333 bool
334 CdlDialogBody::has_update_proc() const
335 {
336     CYG_REPORT_FUNCNAMETYPE("CdlDialog::has_update_proc", "result %d");
337     CYG_REPORT_FUNCARG1XV(this);
338     CYG_PRECONDITION_THISC();
339
340     bool result = has_property(CdlPropertyId_UpdateProc);
341     CYG_REPORT_RETVAL(result);
342     return result;
343 }
344
345 const cdl_tcl_code&
346 CdlDialogBody::get_init_proc() const
347 {
348     CYG_REPORT_FUNCNAME("CdlDialog::get_init_proc");
349     CYG_REPORT_FUNCARG1XV(this);
350     CYG_PRECONDITION_THISC();
351
352     static cdl_tcl_code null_result = "";
353     cdl_tcl_code& result = null_result;
354     CdlProperty prop = get_property(CdlPropertyId_InitProc);
355     if (0 != prop) {
356         CdlProperty_TclCode tclprop = dynamic_cast<CdlProperty_TclCode>(prop);
357         CYG_ASSERT_CLASSC(tclprop);
358         result = tclprop->get_code();
359     }
360
361     CYG_REPORT_RETURN();
362     return result;
363 }
364
365 const cdl_tcl_code&
366 CdlDialogBody::get_update_proc() const
367 {
368     CYG_REPORT_FUNCNAME("CdlDialog::get_update_proc");
369     CYG_REPORT_FUNCARG1XV(this);
370     CYG_PRECONDITION_THISC();
371
372     static cdl_tcl_code null_result = "";
373     cdl_tcl_code& result = null_result;
374     CdlProperty prop = get_property(CdlPropertyId_UpdateProc);
375     if (0 != prop) {
376         CdlProperty_TclCode tclprop = dynamic_cast<CdlProperty_TclCode>(prop);
377         CYG_ASSERT_CLASSC(tclprop);
378         result = tclprop->get_code();
379     }
380
381     CYG_REPORT_RETURN();
382     return result;
383 }
384
385 const cdl_tcl_code&
386 CdlDialogBody::get_display_proc() const
387 {
388     CYG_REPORT_FUNCNAME("CdlDialog::get_display_proc");
389     CYG_REPORT_FUNCARG1XV(this);
390     CYG_PRECONDITION_THISC();
391
392     CdlProperty prop = get_property(CdlPropertyId_DisplayProc);
393     CYG_ASSERT_CLASSC(prop);
394     CdlProperty_TclCode tclprop = dynamic_cast<CdlProperty_TclCode>(prop);
395     CYG_ASSERT_CLASSC(tclprop);
396
397     const cdl_tcl_code& result = tclprop->get_code();
398
399     CYG_REPORT_RETURN();
400     return result;
401 }
402
403 const cdl_tcl_code&
404 CdlDialogBody::get_confirm_proc() const
405 {
406     CYG_REPORT_FUNCNAME("CdlDialog::get_display_proc");
407     CYG_REPORT_FUNCARG1XV(this);
408     CYG_PRECONDITION_THISC();
409
410     CdlProperty prop = get_property(CdlPropertyId_ConfirmProc);
411     CYG_ASSERT_CLASSC(prop);
412     CdlProperty_TclCode tclprop = dynamic_cast<CdlProperty_TclCode>(prop);
413     CYG_ASSERT_CLASSC(tclprop);
414
415     const cdl_tcl_code& result = tclprop->get_code();
416
417     CYG_REPORT_RETURN();
418     return result;
419 }
420
421 const cdl_tcl_code&
422 CdlDialogBody::get_cancel_proc() const
423 {
424     CYG_REPORT_FUNCNAME("CdlDialog::get_display_proc");
425     CYG_REPORT_FUNCARG1XV(this);
426     CYG_PRECONDITION_THISC();
427
428     CdlProperty prop = get_property(CdlPropertyId_CancelProc);
429     CYG_ASSERT_CLASSC(prop);
430     CdlProperty_TclCode tclprop = dynamic_cast<CdlProperty_TclCode>(prop);
431     CYG_ASSERT_CLASSC(tclprop);
432
433     const cdl_tcl_code& result = tclprop->get_code();
434
435     CYG_REPORT_RETURN();
436     return result;
437 }
438
439 //}}}
440 //{{{  check_this()                     
441
442 // ----------------------------------------------------------------------------
443 // check_this(). There is very little data associated with a dialog itself.
444 // most of the checks happen in the base class.
445
446 bool
447 CdlDialogBody::check_this(cyg_assert_class_zeal zeal) const
448 {
449     if (CdlDialogBody_Magic != cdldialogbody_cookie) {
450         return false;
451     }
452     CYGDBG_MEMLEAK_CHECKTHIS();
453     return CdlUserVisibleBody::check_this(zeal);
454 }
455
456 //}}}
457 //{{{  misc                             
458
459 // ----------------------------------------------------------------------------
460 std::string
461 CdlDialogBody::get_class_name() const
462 {
463     CYG_REPORT_FUNCNAME("CdlDialog::get_class_name");
464     CYG_PRECONDITION_THISC();
465     CYG_REPORT_RETURN();
466     return "dialog";
467 }
468
469 //}}}