00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include <sys/types.h>
00049 #include <sys/wait.h>
00050 #include <unistd.h>
00051 #include <signal.h>
00052 #include <stdarg.h>
00053 #include <time.h>
00054 #include <string.h>
00055 #include <errno.h>
00056
00057 #include "DaVinci.h"
00058
00059 #define MAX_MENU_LABEL_LEN 100
00060
00061 #define CALLBACK_DEBUG
00062
00063
00064
00065
00066
00067 void
00068 DaVinci_Callback::Node_Select(const INT n_ids, const NODE_ID id_array[])
00069 {
00070 #ifdef CALLBACK_DEBUG
00071 fprintf(stderr, "Node_Select([");
00072 char *sep = " ";
00073 for (INT i = 0; i < n_ids; ++i) {
00074 fprintf(stderr, "%s%p", sep, id_array[i]);
00075 sep = ", ";
00076 }
00077 fprintf(stderr, " ])\n");
00078 #endif
00079 }
00080
00081 void
00082 DaVinci_Callback::Edge_Select(const EDGE_ID& id)
00083 {
00084 #ifdef CALLBACK_DEBUG
00085 fprintf(stderr, "Edge_Select(%p,%p)\n", id.src, id.dst);
00086 #endif
00087 }
00088
00089 void
00090 DaVinci_Callback::Menu_Select(const char *menu_id)
00091 {
00092 #ifdef CALLBACK_DEBUG
00093 fprintf(stderr, "Menu_Select(%s)\n", menu_id);
00094 #endif
00095 }
00096
00097
00098
00099
00100
00101 NODE_TYPE&
00102 NODE_TYPE::Name(const char *typ_name)
00103 {
00104 if ( typ_name ) {
00105 strncpy(_type_name, typ_name, sizeof(_type_name) - 1);
00106 }
00107
00108
00109 return *this;
00110 }
00111
00112 NODE_TYPE&
00113 NODE_TYPE::Color(const char *rgb)
00114 {
00115 strncpy(_node_color, rgb, sizeof(_node_color) - 1);
00116
00117 return *this;
00118 }
00119
00120 EDGE_TYPE&
00121 EDGE_TYPE::Name(const char *typ_name)
00122 {
00123 if ( typ_name ) {
00124 strncpy(_type_name, typ_name, sizeof(_type_name) - 1);
00125 }
00126
00127
00128 return *this;
00129 }
00130
00131
00132 EDGE_TYPE&
00133 EDGE_TYPE::Color(const char *rgb)
00134 {
00135 strncpy(_edge_color, rgb, sizeof(_edge_color) - 1);
00136
00137 return *this;
00138 }
00139
00140
00141
00142
00143
00144
00145 const char *
00146 Menu_info::Add(const char *cp)
00147 {
00148 Item_info::iterator it = items.find( cp );
00149
00150 if ( cp == NULL ) return NULL;
00151
00152 if ( it != items.end() ) {
00153 return (*it).first;
00154 } else {
00155 char *buf = CXX_NEW_ARRAY(char, strlen(cp)+1, _m);
00156 const char *cpy = strcpy( buf, cp );
00157 items[ cpy ] = DM_UNKNOWN;
00158 return cpy;
00159 }
00160 }
00161
00162 void
00163 Menu_info::Set(const char *cp, Item_status status)
00164 {
00165 if ( cp ) {
00166 if ( items.find( cp ) == items.end() ) {
00167 char *buf = CXX_NEW_ARRAY(char, strlen(cp)+1, _m);
00168 cp = strcpy( buf, cp );
00169 }
00170 items[ cp ] = status;
00171 }
00172 }
00173
00174
00175
00176
00177
00178 DaVinci::IO::~IO()
00179 {
00180 Close ();
00181 }
00182
00183 void
00184 DaVinci::IO::Close()
00185 {
00186 if ( _to_fp ) (void)fclose( _to_fp );
00187 if ( _from_fp ) (void)fclose( _from_fp );
00188 }
00189
00190 void
00191 DaVinci::IO::Out_Fmt(const char *fmt, ...)
00192 {
00193 if ( _to_fp == NULL ) {
00194 fprintf(stderr, "DaVinci::IO::Out_Fmt _to_fp not set!\n");
00195 return;
00196 }
00197 va_list ap;
00198 va_start(ap, fmt);
00199
00200 vfprintf(_to_fp, fmt, ap);
00201
00202 if ( _trace_fp ) {
00203 if ( ! _trace_tagged ) {
00204 fprintf(_trace_fp, "TO-DAVINCI: ");
00205 _trace_tagged = true;
00206 }
00207 vfprintf(_trace_fp, fmt, ap);
00208
00209 if ( strchr( fmt, '\n' ) ) {
00210 _trace_tagged = false;
00211 }
00212 fflush(_trace_fp);
00213 }
00214
00215 va_end(ap);
00216 }
00217
00218 char *
00219 DaVinci::IO::In_Line()
00220 {
00221 static char buf[10000];
00222
00223 if ( _from_fp == NULL ) {
00224 fprintf(stderr, "DaVinci::IO::Out_Fmt _from_fp not set!\n");
00225 return NULL;
00226 }
00227 char *rp = fgets( buf, sizeof(buf), _from_fp );
00228
00229 if ( rp ) {
00230 char *np = strchr( rp, '\n' );
00231 if ( np ) {
00232 *np = '\0';
00233 } else {
00234 fprintf(stderr, "in_line truncation! (%.50s ..)\n", buf);
00235 }
00236 if (strlen(rp) >= sizeof(buf) ) {
00237 fprintf(stderr, "INTERNAL ERROR! DaVinci::IO:in_line buf overflow\n");
00238 abort();
00239 }
00240 }
00241 if ( _trace_fp && rp ) {
00242 fprintf(_trace_fp, "FROM-DAVINCI: %s\n", buf);
00243 fflush(_trace_fp);
00244
00245 _trace_tagged = false;
00246 }
00247 return rp;
00248 }
00249
00250
00251
00252
00253
00254 #define FT_DAVINCI FTAG(1 << 0)
00255 #define FT_TITLE FTAG(1 << 1)
00256 #define FT_SHOW_STATUS FTAG(1 << 2)
00257 #define FT_SHOW_MESSAGE FTAG(1 << 3)
00258 #define FT_MENU_CREATE FTAG(1 << 4)
00259 #define FT_MENU_ACTIVATE FTAG(1 << 5)
00260 #define FT_MENU_DEACTIVATE FTAG(1 << 6)
00261 #define FT_GRAPH_BEGIN FTAG(1 << 7)
00262 #define FT_NODE_BEGIN FTAG(1 << 8)
00263 #define FT_OUT_EDGE FTAG(1 << 9)
00264 #define FT_NODE_END FTAG(1 << 10)
00265 #define FT_GRAPH_END FTAG(1 << 11)
00266 #define FT_CHANGE_ATTR FTAG(1 << 12)
00267 #define FT_UPDATE_BEGIN FTAG(1 << 13)
00268 #define FT_NEW_NODE FTAG(1 << 14)
00269 #define FT_NEW_EDGE FTAG(1 << 15)
00270 #define FT_UPDATE_END FTAG(1 << 16)
00271
00272 #define BASE_SET ( \
00273 FT_DAVINCI | FT_TITLE | FT_SHOW_STATUS | FT_SHOW_MESSAGE \
00274 | FT_MENU_CREATE | FT_MENU_ACTIVATE | FT_MENU_DEACTIVATE \
00275 | FT_GRAPH_END | FT_CHANGE_ATTR | FT_UPDATE_END \
00276 )
00277
00278 const char *
00279 DaVinci::Ft_Str(const FTAG ftag)
00280 {
00281 char *s = "<<ft_str: unknown tag>>";
00282
00283 switch ( ftag ) {
00284 case FT_DAVINCI: s = "DaVinci"; break;
00285 case FT_TITLE: s = "title"; break;
00286 case FT_SHOW_STATUS: s = "show_status"; break;
00287 case FT_SHOW_MESSAGE: s = "show_message"; break;
00288 case FT_MENU_CREATE: s = "menu_create"; break;
00289 case FT_MENU_ACTIVATE: s = "menu_activate"; break;
00290 case FT_MENU_DEACTIVATE: s = "menu_deactivate"; break;
00291 case FT_GRAPH_BEGIN: s = "graph_begin"; break;
00292 case FT_NODE_BEGIN: s = "node_begin"; break;
00293 case FT_OUT_EDGE: s = "out_edge"; break;
00294 case FT_NODE_END: s = "node_end"; break;
00295 case FT_GRAPH_END: s = "graph_end"; break;
00296 case FT_CHANGE_ATTR: s = "change_attr"; break;
00297 case FT_UPDATE_BEGIN: s = "update_begin"; break;
00298 case FT_NEW_NODE: s = "new_node"; break;
00299 case FT_NEW_EDGE: s = "new_edge"; break;
00300 case FT_UPDATE_END: s = "update_end"; break;
00301 default:
00302 ;
00303 }
00304 return s;
00305 }
00306
00307 void
00308 DaVinci::Usage_Error(FTAG curr, FTAGS prereq)
00309 {
00310 fprintf(stderr, "Error while Calling DaVinci::%s - ", Ft_Str(curr));
00311
00312 if ( ! _display_ok ) {
00313 fprintf(stderr, "DaVinci display not ok\n");
00314 } else {
00315 fprintf(stderr, "preceeding %s expected member of {", Ft_Str(_ftag_last));
00316 FTAGS fts = prereq;
00317 char *comma = "";
00318 for (FTAGS ft = FT_DAVINCI; fts != 0; ft <<= 1) {
00319 if ( ft & fts ) {
00320 fprintf(stderr, "%s %s", comma, Ft_Str(ft));
00321 comma = ",";
00322 fts ^= ft;
00323 }
00324 }
00325 fprintf(stderr, " }\n");
00326 }
00327 }
00328
00329 DA_ACK
00330 DaVinci::Wait_For_Ack()
00331 {
00332 EVENT_T event;
00333 char *line;
00334
00335
00336
00337
00338
00339
00340
00341
00342 while ( (line = _io.In_Line()) != NULL ) {
00343 if ( Parse_Event( line, &event ) ) {
00344 switch ( event.kind ) {
00345 case EK_OK:
00346 return NULL;
00347 case EK_COM_ERROR:
00348 return event.u.com_error.msg;
00349 default:
00350 _event_q.push( event );
00351 }
00352 }
00353 }
00354 _display_ok = false;
00355
00356 return "Unexpected EOF from DaVinci";
00357 }
00358
00359 bool
00360 DaVinci::Parse_Node_Ids(const char *epfx, INT *n_nodes, NODE_ID **node_ids)
00361 {
00362 INT n_alloc = 5;
00363 NODE_ID *ids = CXX_NEW_ARRAY(NODE_ID, n_alloc, _m);
00364 INT cnt = 0;
00365 const char *cp = epfx;
00366 const char *sp;
00367 NODE_ID id;
00368
00369
00370
00371
00372
00373
00374 if ( cp[0] != '(' || cp[1] != '[' ) {
00375 fprintf(stderr, "BAD NODE_ID list (lp): %s\n", epfx);
00376 return false;
00377 }
00378 cp += 2;
00379
00380 while ( *cp != ']' ) {
00381 sp = strchr( cp, ',' );
00382 if ( sp == NULL ) {
00383 sp = strchr( cp, ']' );
00384 if ( sp == NULL ) {
00385 fprintf(stderr, "BAD NODE_ID list (sep): %s\n", epfx);
00386 return false;
00387 }
00388 }
00389 if ( sscanf( cp, "\"%p\"", &id ) != 1 ) {
00390 fprintf(stderr, "BAD NODE_ID (id): .. %s\n", cp);
00391 return false;
00392 }
00393 if ( cnt >= n_alloc ) {
00394 n_alloc = cnt + 10;
00395 NODE_ID *nids = CXX_NEW_ARRAY(NODE_ID, n_alloc, _m);
00396 for (INT i = 0; i < cnt; ++i) {
00397 nids[i] = ids[i];
00398 }
00399 ids = nids;
00400 }
00401 ids[ cnt++ ] = id;
00402
00403 cp = ( *sp == ',' ? sp + 1 : sp );
00404 }
00405 *n_nodes = cnt;
00406 *node_ids = ids;
00407
00408 return true;
00409 }
00410
00411 bool
00412 Parse_Edge_Id( const char *epfx, EVENT_T *event )
00413 {
00414 if ( sscanf(epfx, "(\"%p:%p\")",
00415 &event->u.sel_edge.edge_src,
00416 &event->u.sel_edge.edge_dst) != 2 ) {
00417 fprintf(stderr, "Malformed EDGE_ID %s\n", epfx);
00418 return false;
00419 }
00420 return true;
00421 }
00422
00423 const char *
00424 DaVinci::Parse_Menu_Label( const char *epfx )
00425 {
00426 char label[MAX_MENU_LABEL_LEN];
00427 INT len = strlen( epfx );
00428
00429 if ( epfx[0] != '('
00430 || epfx[1] != '"'
00431 || epfx[len - 2] != '"'
00432 || epfx[len - 1] != ')' ) {
00433 fprintf(stderr, "parse_menu_label: not wrapped as expected\n");
00434 return NULL;
00435 }
00436 strncpy( label, epfx + 2, len - 4 );
00437 label[ len - 4 ] = '\0';
00438
00439
00440
00441
00442 return _menu_state.Add( label );
00443 }
00444
00445 static struct {
00446 const char *name;
00447 EVENT_KIND kind;
00448 } Event_Tbl[] = {
00449 { "communication_error", EK_COM_ERROR },
00450 { "edge_selection_label", EK_SEL_EDGE },
00451 { "menu_selection", EK_SEL_MENU },
00452 { "node_selections_labels", EK_SEL_NODES },
00453 { "ok", EK_OK },
00454 { "quit", EK_QUIT }
00455 };
00456 #define N_EVENT ( sizeof(Event_Tbl) / sizeof(Event_Tbl[0]) )
00457
00458 bool
00459 DaVinci::Parse_Event(const char *line, EVENT_T *event)
00460 {
00461 char *epfx;
00462
00463 epfx = (char *)strchr( line, '(' );
00464 if ( epfx == NULL ) {
00465 epfx = (char *)strchr( line, '\0' );
00466 }
00467 INT nchr = epfx - line;
00468 INT lo = 0;
00469 INT hi = N_EVENT - 1;
00470 INT mid;
00471 INT cmp;
00472
00473 while ( lo <= hi ) {
00474 mid = ( lo + hi ) / 2;
00475 cmp = strncmp( Event_Tbl[ mid ].name, line, nchr );
00476 if ( cmp == 0 ) break;
00477 if ( cmp < 0 ) {
00478 lo = mid + 1;
00479 } else {
00480 hi = mid - 1;
00481 }
00482 }
00483 if ( cmp != 0 ) {
00484 #ifndef REPORT_FONT_WARNINGS
00485 if ( strncmp(line, "Font ", 5) == 0 ) {
00486 return false;
00487 }
00488 #endif
00489 fprintf(stderr, "DaVinci::Parse_Event UNKNOWN: %s\n", line);
00490 return false;
00491 }
00492 event->kind = Event_Tbl[ mid ].kind;
00493
00494 switch ( event->kind ) {
00495 case EK_COM_ERROR:
00496 event->u.com_error.msg = line;
00497 break;
00498 case EK_QUIT:
00499 case EK_OK:
00500
00501 break;
00502 case EK_SEL_EDGE:
00503 if ( ! Parse_Edge_Id( epfx, event ) ) {
00504 return false;
00505 }
00506 break;
00507 case EK_SEL_MENU:
00508 {
00509 const char *ss = Parse_Menu_Label( epfx );
00510 if ( ss == NULL ) return false;
00511 event->u.sel_menu.label = ss;
00512 }
00513 break;
00514 case EK_SEL_NODES:
00515 if ( ! Parse_Node_Ids( epfx, &event->u.sel_nodes.n_nodes,
00516 &event->u.sel_nodes.node_ids ) ) {
00517 return false;
00518 }
00519 break;
00520 default:
00521 fprintf(stderr, "INTERNAL ERROR: missing event case %d\n", event->kind);
00522 return false;
00523 }
00524 return true;
00525 }
00526
00527 void
00528 DaVinci::Emit_Menu(INT n_items, const MENU_INFO *items)
00529 {
00530 for (INT i = 0; i < n_items; ++i) {
00531 if ( items[i].subitems && items[i].n_subitems > 0 ) {
00532 _io.Out_Fmt( "submenu_entry(\"%s\", \"%s\",[",
00533 items[i].id, items[i].label);
00534 Emit_Menu( items[i].n_subitems, items[i].subitems );
00535 _io.Out_Fmt( "])" );
00536 } else {
00537 _io.Out_Fmt( "menu_entry(\"%s\", \"%s\")",
00538 items[i].id, items[i].label);
00539 }
00540 if ( i < n_items - 1 ) _io.Out_Fmt( "," );
00541
00542 _menu_state.Set( items[i].id,
00543 (items[i].initially_active ? DM_ACTIVE : DM_INACTIVE));
00544 }
00545 }
00546
00547 void
00548 DaVinci::Emit_Attr(const NODE_TYPE& nt, char **comma)
00549 {
00550 char *val = NULL;
00551
00552 if ( nt._node_color[0] != '\0' ) {
00553 _io.Out_Fmt( ",a(\"COLOR\",\"%s\")", nt._node_color);
00554 }
00555
00556 switch ( nt._node_shape ) {
00557 case NS_UNSET: val = NULL; break;
00558 case NS_BOX: val = "box"; break;
00559 case NS_CIRCLE: val = "circle"; break;
00560 case NS_ELLIPSE: val = "ellipse"; break;
00561 case NS_RHOMBUS: val = "rhombus"; break;
00562 case NS_TEXT: val = "text"; break;
00563 default:
00564 fprintf(stderr, "DaVinci::emit_attr/node unexpected shape %d\n",
00565 nt._node_shape);
00566 }
00567 if ( val) {
00568 _io.Out_Fmt( "%sa(\"_GO\",\"%s\")", *comma, val);
00569 *comma = ",";
00570 }
00571
00572 switch ( nt._border ) {
00573 case NB_UNSET: val = NULL; break;
00574 case NB_SINGLE: val = "single"; break;
00575 case NB_DOUBLE: val = "double"; break;
00576 default:
00577 fprintf(stderr, "DaVinci:emit_attr/node unexpected border type %d\n",
00578 nt._border);
00579 }
00580 if ( val ) {
00581 _io.Out_Fmt( "%sa(\"BORDER\",\"%s\")", *comma, val);
00582 *comma = ",";
00583 }
00584
00585 switch ( nt._hide ) {
00586 case NH_UNSET: val = NULL; break;
00587 case NH_HIDE: val = "true"; break;
00588 case NH_SHOW: val = "false"; break;
00589 default:
00590 fprintf(stderr, "DaVinci:emit_attr/node unexpected hide/show value %d\n",
00591 nt._hide);
00592 }
00593 if ( val ) {
00594 _io.Out_Fmt( "%sa(\"HIDDEN\",\"%s\")", *comma, val);
00595 *comma = ",";
00596 }
00597 }
00598
00599 void
00600 DaVinci::Emit_Attr(const EDGE_TYPE& et)
00601 {
00602
00603 char *val = NULL;
00604 char *comma = "";
00605
00606 if ( et._edge_color[0] != '\0' ) {
00607 _io.Out_Fmt( "a(\"EDGECOLOR\",\"%s\")", et._edge_color );
00608 comma = ",";
00609 }
00610
00611 switch ( et._edge_pattern ) {
00612 case EP_UNSET: val = NULL; break;
00613 case EP_SOLID: val = "solid"; break;
00614 case EP_DOTTED: val = "dotted"; break;
00615 case EP_DASHED: val = "dashed"; break;
00616 case EP_THICK: val = "thick"; break;
00617 case EP_DOUBLE: val = "double"; break;
00618 default:
00619 fprintf(stderr, "DaVinci::emit_attr/edge unexpected edge pattern %d\n",
00620 et._edge_pattern);
00621 }
00622 if ( val ) {
00623 _io.Out_Fmt( "%sa(\"EDGEPATTERN\",\"%s\")", comma, val );
00624 comma = ",";
00625 }
00626
00627 switch ( et._edge_dir ) {
00628 case ED_UNSET: val = NULL; break;
00629 case ED_NORMAL: val = "normal"; break;
00630 case ED_INVERSE: val = "inverse"; break;
00631 case ED_BOTH: val = "both"; break;
00632 case ED_NONE: val = "none"; break;
00633 }
00634 if ( val ) {
00635 _io.Out_Fmt( "%sa(\"_DIR\",\"%s\")", comma, val );
00636 comma = ",";
00637 }
00638 }
00639
00640 void
00641 DaVinci::Menu_Basic_Do( const char *label )
00642 {
00643 if ( strcmp( label, "exit_event_loop" ) == 0 ) {
00644 Exit_Event_Loop();
00645 }
00646 }
00647
00648 DA_ACK
00649 DaVinci::Menu_Set_Active()
00650 {
00651 bool first = true;
00652
00653 _io.Out_Fmt( "app_menu(activate_menus([" );
00654 for (Item_info::iterator m_iter = _menu_state.items.begin();
00655 m_iter != _menu_state.items.end(); ++m_iter) {
00656 if ( (*m_iter).second == DM_ACTIVE) {
00657 const char *menu_id = (*m_iter).first;
00658 _io.Out_Fmt( "%s\"%s\"", (first ? "" : ","), menu_id );
00659 first = false;
00660 }
00661 }
00662 _io.Out_Fmt( "]))\n" );
00663
00664 return Wait_For_Ack();
00665 }
00666
00667 void
00668 DaVinci::Kill_Davinci()
00669 {
00670 INT stat;
00671
00672 _display_ok = false;
00673 kill (_pid, SIGINT);
00674 waitpid (_pid, &stat, WNOHANG);
00675
00676 _io.Close();
00677 }
00678
00679
00680
00681
00682
00683 DaVinci::DaVinci(MEM_POOL *m, FILE *_trace_fp, bool usage_check) :
00684 _menu_state(m)
00685 {
00686 _m = m;
00687 _basic_menu_added = false;
00688 _in_event_loop = false;
00689 _display_ok = false;
00690 _usage_check = usage_check;
00691 _ftag_last = FT_DAVINCI;
00692 _node_cnt = 0;
00693 _edge_cnt = 0;
00694
00695 INT read_pipe[2];
00696 INT write_pipe[2];
00697
00698 if ( pipe( read_pipe ) == -1 || pipe(write_pipe) == -1 ) {
00699 perror( "DaVinci" );
00700 return;
00701 }
00702 FILE *from_display = fdopen(read_pipe[0], "r");
00703 FILE *to_display = fdopen(write_pipe[1], "w");
00704 char *logfile = getenv("DAVINCI_LOGFILE");
00705
00706 setbuf(from_display, NULL);
00707 setbuf(to_display, NULL);
00708
00709 switch ( _pid = fork() ) {
00710 case -1:
00711 fprintf(stderr, "Unable to fork (for daVinci)\n");
00712 close (read_pipe[0]);
00713 close (read_pipe[1]);
00714 close (write_pipe[0]);
00715 close (write_pipe[1]);
00716 return;
00717 case 0:
00718 dup2 (write_pipe[0], 0);
00719 dup2 (read_pipe[1], 1);
00720 dup2 (read_pipe[1], 2);
00721
00722 close (write_pipe[0]);
00723 close (read_pipe[1]);
00724
00725 if ( logfile ) {
00726 char fname[1000];
00727
00728
00729
00730 sprintf(fname, "%s.%ld", logfile, time(NULL));
00731 execlp ("daVinci", "daVinci", "-pipe", "-log", fname, 0);
00732 } else {
00733 execlp ("daVinci", "daVinci", "-pipe", 0);
00734 }
00735
00736
00737 printf("communication_error(\"execlp of daVinci: %s %s\")\n",
00738 strerror(errno), "(define $DAVINCIHOME; need daVinci on $PATH)");
00739 exit (1);
00740
00741 default:
00742 close (read_pipe[1]);
00743 close (write_pipe[0]);
00744 }
00745 _io.Init( to_display, from_display );
00746 _io.Trace( _trace_fp );
00747
00748 DA_ACK msg = Wait_For_Ack();
00749 if ( msg ) {
00750 fprintf(stderr, "DaVinci connection failed: %s\n", msg);
00751 return;
00752 }
00753 _display_ok = true;
00754
00755 Emit_Do( "set(font_size(6))" );
00756 Emit_Do( "set(gap_height(40))" );
00757 Emit_Do( "set(gap_width(20))" );
00758 }
00759
00760 DaVinci::~DaVinci()
00761 {
00762
00763 }
00764
00765
00766
00767
00768 static MENU_INFO Menu_basic[] = {
00769 { "exit_event_loop", "exit_event_loop", true, 0, NULL }
00770 };
00771 #define N_MENU_BASIC ( sizeof(Menu_basic) / sizeof(Menu_basic[0]) )
00772
00773 void
00774 DaVinci::Event_Loop(DaVinci_Callback *cb_hook)
00775 {
00776 static DaVinci_Callback dflt_cb_hook;
00777
00778 EVENT_T event;
00779 INT i;
00780
00781 if ( _in_event_loop || ! _display_ok ) return;
00782
00783 if ( cb_hook == NULL ) {
00784 cb_hook = &dflt_cb_hook;
00785 }
00786 if ( ! _basic_menu_added ) {
00787 DA_ACK msg = Menu_Create( N_MENU_BASIC, Menu_basic );
00788 if ( msg ) {
00789 fprintf(stderr, "Unable to add Basic Menu -- %s.\n",
00790 "best to not start event_loop");
00791 return;
00792 }
00793 _basic_menu_added = true;
00794 }
00795 _in_event_loop = true;
00796
00797 while ( _display_ok ) {
00798 while ( ! _event_q.empty() ) {
00799 event = _event_q.front();
00800 _event_q.pop();
00801 switch ( event.kind ) {
00802 case EK_COM_ERROR:
00803 fprintf(stderr, "event_loop: Unexpected: %s\n", event.u.com_error.msg);
00804 break;
00805 case EK_OK:
00806 fprintf(stderr, "event_loop: Unexpected: OK\n");
00807 break;
00808 case EK_SEL_EDGE:
00809 {
00810 EDGE_ID edge_id(event.u.sel_edge.edge_src,
00811 event.u.sel_edge.edge_dst);
00812 cb_hook->Edge_Select( edge_id );
00813 }
00814 break;
00815 case EK_SEL_MENU:
00816 for (i = 0; i < N_MENU_BASIC; ++i) {
00817 if ( strcmp( event.u.sel_menu.label, Menu_basic[i].id ) == 0 ) {
00818 Menu_Basic_Do( event.u.sel_menu.label );
00819 break;
00820 }
00821 }
00822 if ( i >= N_MENU_BASIC ) {
00823 cb_hook->Menu_Select( event.u.sel_menu.label );
00824 }
00825 break;
00826 case EK_SEL_NODES:
00827 cb_hook->Node_Select( event.u.sel_nodes.n_nodes,
00828 event.u.sel_nodes.node_ids );
00829 break;
00830 case EK_QUIT:
00831 _display_ok = false;
00832 _in_event_loop = false;
00833 break;
00834 default:
00835 fprintf(stderr, "ERROR: event_loop missing event case %d\n",
00836 event.kind);
00837 }
00838 if ( ! _in_event_loop ) {
00839 return;
00840 }
00841 }
00842 char *line = _io.In_Line();
00843
00844 if ( line == NULL ) {
00845 _display_ok = false;
00846 break;
00847 }
00848 if ( Parse_Event( line, &event ) ) {
00849 _event_q.push( event );
00850 }
00851 }
00852
00853 }
00854
00855 void
00856 DaVinci::Exit_Event_Loop()
00857 {
00858 _in_event_loop = false;
00859 }
00860
00861 DA_ACK
00862 DaVinci::Title(const char *title)
00863 {
00864 if ( ! Usage_Ok( FT_TITLE, BASE_SET ) ) return "Usage-error";
00865
00866 _io.Out_Fmt( "window(title(\"%s\"))\n", title );
00867 return Wait_For_Ack();
00868 }
00869
00870 DA_ACK
00871 DaVinci::Show_Status(const char *status)
00872 {
00873 if ( ! Usage_Ok( FT_SHOW_STATUS, BASE_SET ) ) return "Usage-error";
00874
00875 _io.Out_Fmt( "window(show_status(\"%s\"))\n", status );
00876 return Wait_For_Ack();
00877 }
00878
00879 DA_ACK
00880 DaVinci::Show_Message(const char *msg)
00881 {
00882 if ( ! Usage_Ok( FT_SHOW_MESSAGE, BASE_SET ) ) return "Usage-error";
00883
00884 _io.Out_Fmt( "window(show_message(\"%s\"))\n", msg );
00885 return Wait_For_Ack();
00886 }
00887
00888 DA_ACK
00889 DaVinci::Menu_Create(INT n_items, const MENU_INFO *items)
00890 {
00891 if ( ! Usage_Ok( FT_MENU_CREATE, BASE_SET ) ) return "Usage-error";
00892
00893 if ( n_items == 0 ) return NULL;
00894
00895 _io.Out_Fmt( "app_menu(create_menus([" );
00896 Emit_Menu( n_items, items );
00897 _io.Out_Fmt( "]))\n" );
00898
00899 DA_ACK msg = Wait_For_Ack();
00900 if ( msg ) return msg;
00901
00902 return Menu_Set_Active();
00903 }
00904
00905 DA_ACK
00906 DaVinci::Menu_Activate(INT n_ids, const char *id[])
00907 {
00908 if ( ! Usage_Ok( FT_MENU_ACTIVATE, BASE_SET ) ) return "Usage-error";
00909
00910 for (INT i = 0; i < n_ids; ++i) {
00911 _menu_state.Set( id[i], DM_ACTIVE );
00912 }
00913 return Menu_Set_Active();
00914 }
00915
00916 DA_ACK
00917 DaVinci::Menu_Deactivate(INT n_ids, const char *id[])
00918 {
00919 if ( ! Usage_Ok( FT_MENU_DEACTIVATE, BASE_SET ) ) return "Usage-error";
00920
00921 for (INT i = 0; i < n_ids; ++i) {
00922 _menu_state.Set( id[i], DM_INACTIVE );
00923 }
00924 return Menu_Set_Active();
00925 }
00926
00927 void
00928 DaVinci::Graph_Begin()
00929 {
00930 if ( ! Usage_Ok( FT_GRAPH_BEGIN, BASE_SET ) ) return;
00931
00932 _io.Out_Fmt( "graph(new_placed([" );
00933 _node_cnt = 0;
00934 }
00935
00936 void
00937 DaVinci::Node_Begin(NODE_ID id, const char *label, const NODE_TYPE& node_type)
00938 {
00939 if ( ! Usage_Ok( FT_NODE_BEGIN, (FT_GRAPH_BEGIN|FT_NODE_END) ) ) return;
00940
00941 if ( _usage_check ) {
00942 if ( _node_def_set.count(id) > 0 ) {
00943 fprintf(stderr, "DaVinci::Node_Begin USAGE-ERROR, %s 0x%p\n",
00944 "duplicate def for node", id);
00945 } else {
00946 _node_def_set.insert(id);
00947 }
00948 }
00949 _io.Out_Fmt( "%sl(\"%x\",n(\"%s\",[a(\"OBJECT\",\"%s\")",
00950 ( _node_cnt > 0 ? "," : "" ),
00951 id, node_type._type_name, label);
00952 _node_cnt += 1;
00953 _edge_cnt = 0;
00954 char *comma = ",";
00955 Emit_Attr( node_type, &comma );
00956 _io.Out_Fmt( "],[" );
00957
00958 }
00959
00960 void
00961 DaVinci::Out_Edge(const EDGE_ID& edge_id,
00962 const EDGE_TYPE& edge_type,
00963 const NODE_ID dest_id)
00964 {
00965 if ( ! Usage_Ok( FT_OUT_EDGE, (FT_NODE_BEGIN|FT_OUT_EDGE) ) ) return;
00966
00967 if ( _usage_check ) {
00968 _node_ref_set.insert(edge_id.dst);
00969 }
00970 _io.Out_Fmt( "%sl(\"%x:%x\",e(\"%s\",[",
00971 ( _edge_cnt > 0 ? "," : "" ),
00972 edge_id.src, edge_id.dst, edge_type._type_name);
00973 _edge_cnt += 1;
00974
00975 Emit_Attr( edge_type );
00976 _io.Out_Fmt( "],r(\"%x\")))", dest_id);
00977 }
00978
00979 void
00980 DaVinci::Node_End()
00981 {
00982 if ( ! Usage_Ok( FT_NODE_END, (FT_NODE_BEGIN|FT_OUT_EDGE) ) ) return;
00983
00984 _io.Out_Fmt( "]))" );
00985 }
00986
00987 DA_ACK
00988 DaVinci::Graph_End()
00989 {
00990 if ( _usage_check ) {
00991 for (set<NODE_ID>::iterator it_ref = _node_ref_set.begin();
00992 it_ref != _node_ref_set.end(); ++it_ref) {
00993 NODE_ID ref_id = *it_ref;
00994
00995 if ( _node_def_set.count(ref_id) == 0 ) {
00996 fprintf(stderr, "ERROR DaVinci node 0x%p referenced, %s\n",
00997 ref_id, "but not defined.");
00998 }
00999 }
01000 }
01001 if ( ! Usage_Ok( FT_GRAPH_END, (FT_NODE_END|FT_GRAPH_BEGIN) ) ) {
01002 return "Usage-error";
01003 }
01004 _io.Out_Fmt( "]))\n" );
01005
01006 return Wait_For_Ack();
01007 }
01008
01009 DA_ACK
01010 DaVinci::Change_Attr(const NODE_ID id,
01011 const NODE_TYPE& nt,
01012 const char *new_label)
01013 {
01014 if ( ! Usage_Ok( FT_CHANGE_ATTR, BASE_SET ) ) return "Usage-error";
01015
01016 char *comma = "";
01017
01018 _io.Out_Fmt( "graph(change_attr([node(\"%x\",[", id);
01019
01020 if ( new_label ) {
01021 _io.Out_Fmt( "a(\"OBJECT\",\"%s\")", new_label );
01022 comma = ",";
01023 }
01024 Emit_Attr( nt, &comma );
01025
01026 _io.Out_Fmt( "])]))\n");
01027
01028 return Wait_For_Ack();
01029 }
01030
01031 DA_ACK
01032 DaVinci::Change_Attr(const EDGE_ID& edge_id, const EDGE_TYPE& et)
01033 {
01034 if ( ! Usage_Ok( FT_CHANGE_ATTR, BASE_SET ) ) return "Usage-error";
01035
01036 _io.Out_Fmt( "graph(change_attr([edge(\"%x:%x\",[",
01037 edge_id.src, edge_id.dst );
01038 Emit_Attr( et );
01039 _io.Out_Fmt( "])]))\n");
01040
01041 return Wait_For_Ack();
01042 }
01043
01044 void
01045 DaVinci::Update_Begin()
01046 {
01047 if ( ! Usage_Ok( FT_UPDATE_BEGIN, BASE_SET ) ) return;
01048
01049 _io.Out_Fmt( "graph(update([" );
01050 _node_cnt = 0;
01051 _edge_cnt = 0;
01052 }
01053
01054 void
01055 DaVinci::New_Node(NODE_ID id, const char *label, const NODE_TYPE& nt )
01056 {
01057 if ( ! Usage_Ok( FT_NEW_NODE, (FT_UPDATE_BEGIN|FT_NEW_NODE) ) ) return;
01058
01059 if ( _edge_cnt > 0 ) {
01060 fprintf(stderr, "Must list ALL new_nodes before first new_edge\n");
01061 fprintf(stderr, "Skipping this node to avoid DaVinci error.\n");
01062 return;
01063 }
01064 _io.Out_Fmt( "%snew_node(\"%x\",[a(\"OBJECT\",\"%s\")",
01065 (_node_cnt > 0 ? "," : ""), id, label );
01066 char *comma = ",";
01067 Emit_Attr( nt, &comma );
01068 _node_cnt += 1;
01069 }
01070
01071 void
01072 DaVinci::New_Edge(const EDGE_ID& id,
01073 const EDGE_TYPE& et,
01074 NODE_ID src,
01075 NODE_ID dst)
01076 {
01077 if ( ! Usage_Ok( FT_NEW_EDGE, (FT_UPDATE_BEGIN|FT_NEW_NODE|FT_NEW_EDGE) ) ) {
01078 return;
01079 }
01080 if ( _edge_cnt == 0 ) {
01081 _io.Out_Fmt( "],[" );
01082 }
01083 _io.Out_Fmt( "%snew_edge(\"%x:%x\",\"\",[", (_edge_cnt > 0 ? "," : ""),
01084 id.src, id.dst );
01085 Emit_Attr( et );
01086 _io.Out_Fmt( "],\"%x\",\"%x\")", src, dst);
01087 _edge_cnt += 1;
01088 }
01089
01090 DA_ACK
01091 DaVinci::Update_End()
01092 {
01093 if ( ! Usage_Ok( FT_UPDATE_END,
01094 (FT_UPDATE_BEGIN|FT_NEW_NODE|FT_NEW_EDGE) ) ) {
01095 return "Usage-error";
01096 }
01097 if ( _edge_cnt == 0 ) {
01098 _io.Out_Fmt( "],[" );
01099 }
01100 _io.Out_Fmt( "]))\n");
01101
01102 return Wait_For_Ack();
01103 }