#include #include #include #include "tlmpdia.h" #include "tlmpdia.m" #include #include #include #include #include using namespace std; class ENTRY; class ENTRIES: public ARRAY{ /*~PROTOBEG~ ENTRIES */ public: ENTRY *getitem (int no)const; /*~PROTOEND~ ENTRIES */ }; PUBLIC ENTRY *ENTRIES::getitem(int no) const { return (ENTRY*)ARRAY::getitem(no); } class ENTRY: public ARRAY_OBJ{ public: ENTRIES entries; SSTRING name; /*~PROTOBEG~ ENTRY */ /*~PROTOEND~ ENTRY */ }; struct _F_edittree_private{ ENTRY top; ENTRIES *loading; // The entries currently beeing loaded DIALOG dia; int buttons; FRAMEWORK_MSGS *fmsgs; DIALOG_TYPE diatype; int level; int ipath[20]; char id[100]; char path[1000]; string namepath[20]; map mapi; map maps; map mapobjs; map mapid2path; set setexpand; // List of all expanded branches // sent by the GUI front-end int height,width; char *dcs; const char *tagdcs; char *defdcs; bool dialog_done; SSTRING guiname; _F_edittree_private() { buttons = MENUBUT_QUIT; fmsgs = NULL; diatype = DIATYPE_STD; resetlookup(); height = 20; width = 40; const char *font = guiid_setfont (12,GFONT_ID_DEFAULT,GFONT_STYLE_DEFAULT,GFONT_WEIGHT_DEFAULT,false); const char *pen = guiid_setpen ("red"); tagdcs = guiid_setdc (font,pen,NULL); defdcs = NULL; dcs = NULL; dialog_done = false; } ~_F_edittree_private (){ free (dcs); free (defdcs); } // Format the ID of the branch or leaf (1/2/n...) and // the "path" void formatid(const char *name) { namepath[level] = name; char *pt = id; char *end = id + 99; char *ptpath = path; char *endpath = path + 999; for (int i=0; i<=level; i++){ pt += snprintf (pt,end-pt,"%d/",ipath[i]); ptpath += snprintf (ptpath,endpath-ptpath,"%s/",namepath[i].c_str()); } *pt = '\0'; *ptpath = '\0'; mapid2path[id] = path; } void formatdcs (char tmpdcs[100]){ tmpdcs[0] = '\0'; if (dcs != NULL){ snprintf (tmpdcs,100-1," $dc=%s",dcs); free (dcs); dcs = NULL; }else if (defdcs != NULL){ snprintf (tmpdcs,sizeof(tmpdcs)-1," $dc=%s",defdcs); } } void resetlookup() { mapi.clear(); maps.clear(); mapid2path.clear(); typedef map::iterator objit; for (objit it = mapobjs.begin(); it != mapobjs.end(); it++){ delete it->second; } mapobjs.clear(); level = 0; memset (ipath,0,sizeof(ipath)); id[0] = '\0'; path[0] = '\0'; } // Record the state of the tree as sent by the GUI front-end void savestate() { int i=0; SSTRING tmp; const char *diapath = dia.setguibasename(tmp); setexpand.clear(); fprintf (stderr,"diapath=%s\n",diapath); while(true){ const char *st = diagui_getval (diapath,'t',i); if (st[0] == '\0') break; string &path = mapid2path[st]; fprintf (stderr,"st[%d]=%s -> %s\n",i,st,path.c_str()); setexpand.insert(path); i++; } } }; void _F_edittree::setsize (int _width, int _height) { priv->width = _width; priv->height = _height; } /* Drawing contexts used to the next entry defined */ void _F_edittree::setnextdcs (const char *dcs) { free (priv->dcs); priv->dcs = NULL; if (dcs != NULL) priv->dcs = strdup(dcs); } /* Select a drawing contexts used for the next entry defined so it represents a "tagged" record. This function must be called before every new_xxxx() called. */ void _F_edittree::setnexttagged () { setnextdcs (priv->tagdcs); } void _F_edittree::setdefaultdcs (const char *dcs) { free (priv->defdcs); priv->defdcs = NULL; if (dcs != NULL) priv->defdcs = strdup(dcs); } void _F_edittree::new_subdir(const char *name, bool isexpanded) { char tmp[1000],tmpdcs[100]; priv->formatdcs(tmpdcs); priv->formatid(name); const char *qname = diagui_quote(name,tmp); if (priv->dialog_done){ diagui_sendcmd (P_Setval,"%s tree %s %d \"\" %s%s\n" ,priv->guiname.get(),priv->id ,isexpanded ? 1 : 0 ,qname,tmpdcs); }else{ priv->dia.gui_passthrough (P_Treesub,"%d \"\" %s%s" ,isexpanded ? 1 : 0 ,qname,tmpdcs); } priv->level++; priv->ipath[priv->level] = 0; } void _F_edittree::new_subdir(const char *name) { priv->formatid(name); bool isexpanded = priv->dialog_done ? priv->setexpand.count(priv->path)>0 : false; new_subdir (name,isexpanded); } void _F_edittree::end_subdir() { priv->formatid(""); if (priv->dialog_done){ // Tell this is the last one in this branch diagui_sendcmd (P_Setval,"%s tree %s _ _ _ $del=1\n" ,priv->guiname.get(),priv->id); }else{ priv->dia.gui_end(); } priv->level--; priv->ipath[priv->level]++; } void _F_edittree::new_file(const char *name) { char tmp[1000],tmpdcs[100]; priv->formatdcs(tmpdcs); priv->formatid(name); const char *qname = diagui_quote(name,tmp); if (priv->dialog_done){ diagui_sendcmd (P_Setval,"%s tree %s 0 \"\" %s%s\n" ,priv->guiname.get(),priv->id ,qname,tmpdcs); }else{ priv->dia.gui_passthrough (P_Treeelem,"\"\" %s%s",qname,tmpdcs); } priv->ipath[priv->level]++; } void _F_edittree::nobutton() { priv->buttons &= ~MENUBUT_QUIT; } /* Record the index of the last new_(file or subdir) */ void _F_edittree::set_lookup(int no) { priv->mapi[priv->id] = no; } /* Record an object related to the last new_(file or subdir). The object will be deleted by the component. */ void _F_edittree::set_lookup(ARRAY_OBJ *obj) { priv->mapobjs[priv->id] = obj; } /* Record the key of the last new_(file or subdir) */ void _F_edittree::set_lookup(const char *key) { priv->maps[priv->id] = key; } void _F_edittree::message(bool &) { } void _F_edittree::init() { } void _F_edittree::handle (FRAMEWORK_MSGS &msgs) { priv->fmsgs = &msgs; msgs.waitfor (priv->dia); } void _F_edittree::waitfor (PRIVATE_MESSAGE &msg) { priv->dia.waitfor (msg); } void _F_edittree::settype (DIALOG_TYPE type) { priv->diatype = type; } /* Parse a path like 1/22/3 */ static int tree_parse (const char *id, int ipath[], int maxlevel) { int ret = 0; while (ret < maxlevel && isdigit(*id)){ ipath[ret++] = atoi(id); id = str_skipdig(id); if (*id == '/') id++; } return ret; } void edittree ( _F_edittree &c, const char *title, const char *intro, HELP_FILE &help) { dialog_clear(); // Make sure the UI toolkit is initialised _F_edittree_private priv; c.priv = &priv; c.init(); priv.dia.settype (priv.diatype); priv.dia.gui_passthrough(P_Treemenu,"tree $mode=1 width=%d height=%d" ,priv.width,priv.height); priv.loading = &priv.top.entries; priv.resetlookup(); c.load(0,"",NULL); priv.dia.gui_end(); priv.dialog_done = true; int nof = 0; bool end = false; while (!end){ MENU_STATUS code = priv.dia.edit (title,intro,help,nof,priv.buttons); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ACCEPT){ priv.savestate(); }else if (code == MENU_MESSAGE){ bool found = false; if (priv.fmsgs != NULL){ if (priv.fmsgs->is_mayend()){ priv.fmsgs->endok(); found = true; }else if (priv.fmsgs->is_ending()){ break; } } if (!found) c.message(end); }else if (code == MENU_NULL){ priv.savestate(); const char *id = diagui_getlast_actionid(); if (id != NULL){ if (id[0] == '+'){ // We expand a directory //int ipath[20]; //int level = tree_parse (id+1,ipath,20); }else{ // We want to do something with the selected item int ipath[20]; int level = tree_parse (id,ipath,20); SSTRING path; ENTRY *ent = &priv.top; for (int i=0; ientries.getitem(no); if (sub == NULL){ break; }else{ if (!path.is_empty()) path.append ("/"); path.append (sub->name.get()); ent = sub; } } int no = priv.mapi[id]; const char *key = priv.maps[id].c_str(); UISTATE uistate; diajava_lastmousestate (uistate); ARRAY_OBJ *obj = priv.mapobjs[id]; c.editone (no,key,obj,path.get(),ipath,level,uistate); } } } priv.dia.setguiname (priv.guiname); priv.resetlookup(); c.load(0,"",NULL); priv.formatid(""); // Tell this is the last one in this branch diagui_sendcmd (P_Setval,"%s tree %s _ _ _ $del=1\n" ,priv.guiname.get(),priv.id); } }