Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

htapp.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htapp.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include "analy.h"
00022 #include "cmds.h"
00023 #include "log.h"
00024 #include "mfile.h"
00025 #include "htapp.h"
00026 #include "htatom.h"
00027 #include "htcfg.h"
00028 #include "htclipboard.h"
00029 #include "htdialog.h"
00030 #include "hteval.h"
00031 #include "hthist.h"
00032 #include "htidle.h"
00033 #include "htinfo.h"
00034 #include "htiobox.h"
00035 #include "htkeyb.h"
00036 #include "htmenu.h"
00037 #include "htpal.h"
00038 #include "htsearch.h"
00039 #include "htstring.h"
00040 #include "htsys.h"
00041 #include "httree.h"
00042 #include "infoview.h"
00043 #include "snprintf.h"
00044 #include "stream.h"
00045 #include "terminal.h"
00046 #include "textedit.h"
00047 #include "textfile.h"
00048 #include "tools.h"
00049 
00050 #include "vfsview.h"
00051 
00052 #include "formats.h"
00053 
00054 #include <errno.h>
00055 #include <stdarg.h>
00056 #include <stdlib.h>
00057 #include <string.h>
00058 #include <sys/stat.h>
00059 #include <sys/types.h>
00060 #include <time.h>
00061 #include <unistd.h>
00062 
00063 extern "C" {
00064 #include "regex.h"
00065 }
00066 
00067 #define ATOM_HT_APP                     MAGICD("APP\x00")
00068 #define ATOM_HT_PROJECT                 MAGICD("APP\x01")
00069 #define ATOM_HT_PROJECT_ITEM            MAGICD("APP\x02")
00070 #define ATOM_COMPARE_KEYS_PROJECT_ITEM  MAGICD("APP\x10")
00071 
00072 #define HT_PROJECT_CONFIG_SUFFIX        ".htprj"
00073 #define HT_FILE_CONFIG_SUFFIX           ".htcfg"
00074 
00075 ht_log *loglines;
00076 
00077 /*
00078  *      CLASS ht_help_window
00079  */
00080 
00081 class ht_help_window : public ht_window {
00082 public:
00083 /* overwritten */
00084         virtual void handlemsg(htmsg *msg);
00085 };
00086 
00087 void ht_help_window::handlemsg(htmsg *msg)
00088 {
00089         ht_window::handlemsg(msg);
00090         if (msg->msg == msg_keypressed) {
00091                 switch (msg->data1.integer) {
00092                         case K_Escape: {
00093                                 htmsg m;
00094                                 m.msg = cmd_window_close;
00095                                 ((ht_app*)app)->queuemsg(app, &m);
00096                                 clearmsg(msg);
00097                                 return;
00098                         }                               
00099                 }                               
00100         }
00101 }
00102 
00103 bool file_new_dialog(UINT *mode)
00104 {
00105         bounds b, c;
00106         
00107         app->getbounds(&b);
00108 
00109         b.x = (b.w - 40) / 2,
00110         b.y = (b.h - 8) / 2;
00111         b.w = 40;
00112         b.h = 8;
00113         
00114         ht_dialog *d=new ht_dialog();
00115         d->init(&b, "create new file", FS_KILLER | FS_TITLE | FS_MOVE | FS_RESIZE);
00116         
00117         b.x=0;
00118         b.y=0;
00119                 
00120         /* mode (input) */
00121         c=b;
00122         c.x=0;
00123         c.y=1;
00124         c.w=b.w-2-c.x;
00125         c.h=b.h-2-c.y;
00126 
00127         ht_text_listbox *mode_input=new ht_text_listbox();
00128         mode_input->init(&c);
00129         
00130         mode_input->insert_str(FOM_TEXT, "text");
00131         mode_input->insert_str(FOM_BIN, "binary");
00132         mode_input->update();
00133 
00134         d->insert(mode_input);
00135         
00136         /* mode (text) */
00137         c=b;
00138         c.x=0;
00139         c.y=0;
00140         c.w=12;
00141         c.h=1;
00142 
00143         ht_label *mode_text=new ht_label();
00144         mode_text->init(&c, "choose ~type", mode_input);
00145 
00146         d->insert(mode_text);
00147 
00148         bool retval = false;
00149         if (d->run(false)) {
00150                 struct {
00151                         ht_listbox_data type;
00152                 } data;
00153 
00154                 d->databuf_get(&data, sizeof data);
00155 
00156                 *mode = mode_input->getID(data.type.cursor_ptr);
00157                 
00158                 retval = true;
00159         }
00160 
00161         d->done();
00162         delete d;
00163         return retval;
00164 }
00165 
00166 /*
00167  *      class FileBrowserVfsListbox
00168  */
00169  
00170 class FileBrowser;
00171 
00172 #define FileBrowserVfsListboxData VfsListboxData
00173 
00174 class FileBrowserVfsListbox: public VfsListbox {
00175 protected:
00176         FileBrowser *file_browser;
00177 public:
00178                         void    init(bounds *b, ht_list *vfs_list, ht_text *show_pos, FileBrowser *file_browser);
00179 /* overwritten */
00180         virtual void stateChanged();
00181 };
00182 
00183 /*
00184  *      class FileBrowser
00185  */
00186  
00187 struct FileBrowserData {
00188         ht_strinputfield_data name;
00189         ht_listbox_data listbox;
00190 };
00191 
00192 class FileBrowser: public ht_dialog {
00193 protected:
00194         ht_strinputfield *name_input;
00195         FileBrowserVfsListbox *listbox;
00196 public:
00197         virtual void init(bounds *b, bounds *clientarea, const char *title, const char *starturl);
00198 /* new */
00199         virtual bool extract_url(char *buf);
00200         virtual void listbox_changed();
00201 };
00202 
00203 
00204 void    FileBrowserVfsListbox::init(bounds *b, ht_list *vfs_list, ht_text *show_pos, FileBrowser *fb)
00205 {
00206         file_browser = NULL;
00207         VfsListbox::init(b, vfs_list, show_pos);
00208         file_browser = fb;
00209 }
00210 
00211 void FileBrowserVfsListbox::stateChanged()
00212 {
00213         if (file_browser) file_browser->listbox_changed();
00214         VfsListbox::stateChanged();
00215 }
00216 
00217 
00218 void FileBrowser::init(bounds *n, bounds *clientarea, const char *title, const char *starturl)
00219 {
00220         ht_dialog::init(n, title, FS_KILLER | FS_TITLE | FS_MOVE | FS_RESIZE);
00221         bounds b = *clientarea, c;
00222 
00223         /* name (input) */
00224         c = b;
00225         c.x = 1;
00226         c.y = 1;
00227         c.w -= 2;
00228         c.h = 1;
00229 
00230         ht_list *hist=(ht_list*)find_atom(HISTATOM_FILE);
00231         
00232         name_input=new ht_strinputfield();
00233         name_input->init(&c, 128, hist);
00234 
00235         insert(name_input);
00236         
00237         /* name (text) */
00238         c = b;
00239         c.x = 1;
00240         c.y = 0;
00241         c.w = 9;
00242         c.h = 1;
00243 
00244         ht_label *name_text=new ht_label();
00245         name_text->init(&c, "~name", name_input);
00246 
00247         insert(name_text);
00248 
00249         /* vfslistbox */
00250         c = b;
00251         c.x = 1;
00252         c.y = 4;
00253         c.w -= 2;
00254         c.h -= 4;
00255         listbox = new FileBrowserVfsListbox();
00256         listbox->init(&c, virtual_fs_list, NULL, this);
00257         listbox->changeURL(starturl);
00258 
00259         insert(listbox);
00260 
00261         /* vfslistbox (text) */
00262         c = b;
00263         c.x = 1;
00264         c.y = 3;
00265         c.w = 9;
00266         c.h = 1;
00267 
00268         ht_label *name_listbox=new ht_label();
00269         name_listbox->init(&c, "~files", listbox);
00270 
00271         insert(name_listbox);
00272 }
00273 
00274 bool FileBrowser::extract_url(char *buf)
00275 {
00276         ht_strinputfield_data i;
00277         name_input->databuf_get(&i, sizeof i);
00278 /*      ht_text_listbox_item *t = (ht_text_listbox_item*)listbox->getbyid(d.listbox.cursor_id);
00279         vfs_extra *x = (vfs_extra*)t->extra_data;*/
00280         Vfs *vfs = listbox->getCurVfs();
00281         if (vfs) {
00282                 int buflen = ht_snprintf(buf, VFS_URL_MAX, "%s:", listbox->getCurProto());
00283                 char fname[VFS_URL_MAX];
00284                 bin2str(fname, i.text, i.textlen);
00285                 vfs->canonicalize(buf+buflen, fname, listbox->getCurDir());
00286                 return true;
00287         }
00288         return false;
00289 }
00290 
00291 void FileBrowser::listbox_changed()
00292 {
00293         FileBrowserVfsListboxData l;
00294         listbox->databuf_get(&l, sizeof l);
00295         ht_text_listbox_item *t = (ht_text_listbox_item*)l.cursor_ptr;
00296         if (t) {
00297                 vfs_extra *x = (vfs_extra*)t->extra_data;
00298                 ht_strinputfield_data i;
00299                 i.textlen = strlen(x->name);
00300                 i.text = (byte*)x->name;
00301                 name_input->databuf_set(&i, sizeof i);
00302         }
00303 }
00304 
00305 
00306 bool file_chooser(const char *title, char *buf, int bufsize)
00307 {
00308         bounds b, c;
00309         
00310         app->getbounds(&b);
00311 
00312         c = b;
00313         b.w = 60;
00314         b.h = 20;
00315         b.x = (c.w - b.w) / 2,
00316         b.y = (c.h - b.h) / 2;
00317 
00318         c = b;
00319         c.x = 0;
00320         c.y = 0;
00321         c.w -= 2;
00322         c.h -= 3;
00323 
00324         // FIXME: hacked!
00325         char cwd[HT_NAME_MAX];
00326         strcpy(cwd, "local:");
00327         if (!getcwd(cwd+6, (sizeof cwd)-6)) {
00328                 cwd[6] = 0;
00329         }
00330 
00331         FileBrowser *d = new FileBrowser();
00332         d->init(&b, &c, title, cwd);
00333 
00334         ht_list *hist = (ht_list*)find_atom(HISTATOM_FILE);
00335 
00336         /* go! */
00337         if (d->run(false)) {
00338                 char b[VFS_URL_MAX];
00339                 d->extract_url(b);
00340 
00341                 // FIXME: urls not fully supported...
00342                 if (strncmp(b, "local:", 6) == 0) {
00343                         ht_snprintf(buf, bufsize, "%s", b+6);
00344 
00345                         if (hist) insert_history_entry(hist, buf, 0);
00346 
00347                         d->done();
00348                         delete d;
00349                         return true;
00350                 }
00351         }
00352         d->done();
00353         delete d;
00354         return false;
00355 }
00356 
00357 
00358 bool file_open_dialog(char **name, UINT *mode)
00359 {
00360         bounds b, c;
00361         
00362         app->getbounds(&b);
00363 
00364         c = b;
00365         b.w = 60;
00366         b.h = 20;
00367         b.x = (c.w - b.w) / 2,
00368         b.y = (c.h - b.h) / 2;
00369 
00370         c = b;
00371         c.x = 0;
00372         c.y = 0;
00373         c.w -= 2;
00374         c.h -= 5;
00375 
00376         // FIXME: hacked!
00377         char cwd[HT_NAME_MAX];
00378         strcpy(cwd, "local:");
00379         if (!getcwd(cwd+6, (sizeof cwd)-6)) {
00380                 cwd[6] = 0;
00381         }
00382 
00383         FileBrowser *d = new FileBrowser();
00384         d->init(&b, &c, "open file", cwd);
00385         
00386         ht_list *hist = (ht_list*)find_atom(HISTATOM_FILE);
00387         
00388         /* mode (input) */
00389         c=b;
00390         c.x=6;
00391         c.y=b.h-4;
00392         c.w=12;
00393         c.h=1;
00394 
00395         ht_listpopup *mode_input=new ht_listpopup();
00396         mode_input->init(&c);
00397         
00398         mode_input->insertstring("autodetect");
00399         mode_input->insertstring("binary");
00400         mode_input->insertstring("text");
00401 
00402         d->insert(mode_input);
00403         
00404         /* mode (text) */
00405         c=b;
00406         c.x=1;
00407         c.y=b.h-4;
00408         c.w=9;
00409         c.h=1;
00410 
00411         ht_label *mode_text=new ht_label();
00412         mode_text->init(&c, "~mode", mode_input);
00413 
00414         d->insert(mode_text);
00415 
00416         /* go! */
00417         if (d->run(false)) {
00418                 struct {
00419                         FileBrowserData browser;
00420                         ht_listpopup_data mode;
00421                 } data;
00422 
00423                 d->databuf_get(&data, sizeof data);
00424 
00425                 char buf[VFS_URL_MAX];
00426                 d->extract_url(buf);
00427 
00428                 // FIXME: urls not fully supported...
00429                 if (strncmp(buf, "local:", 6) == 0) {
00430                         *name = strdup(buf+6);
00431 
00432                         if (hist) insert_history_entry(hist, *name, 0);
00433 
00434                         switch (data.mode.cursor_pos) {
00435                                 case 0: *mode=FOM_AUTO; break;
00436                                 case 1: *mode=FOM_BIN; break;
00437                                 case 2: *mode=FOM_TEXT; break;
00438                         }
00439 
00440                         d->done();
00441                         delete d;
00442                         return true;
00443                 }
00444         }
00445         d->done();
00446         delete d;
00447         return false;
00448 }
00449 
00450 UINT autodetect_file_open_mode(char *filename)
00451 {
00452 #define AUTODETECT_SIZE 128
00453         FILE *f=fopen(filename, "rb");
00454         UINT r=FOM_BIN;
00455         if (f) {
00456                 byte buf[AUTODETECT_SIZE];
00457                 int c=fread(buf, 1, AUTODETECT_SIZE, f);
00458                 /* empty files are text files */
00459                 if (!c) return FOM_TEXT;
00460                 bool is_bin=false;
00461                 UINT prob_bin_chars=0;
00462                 for (int i=0; i<c; i++) {
00463                         if (buf[i]==0) {
00464                                 is_bin=true;
00465                                 break;
00466                         } else if (buf[i]<32) {
00467                                 prob_bin_chars++;
00468                         } else if (buf[i]>0xa9) {
00469                                 prob_bin_chars++;
00470                         }
00471                 }
00472                 if (c) {
00473                         if (prob_bin_chars*100/c>=50) is_bin=true;
00474                 } else is_bin=true;
00475                 if (!is_bin) r=FOM_TEXT;
00476                 fclose(f);
00477                 return r;
00478         }
00479         return FOM_BIN;
00480 }
00481 
00482 int file_window_load_fcfg_func(ht_object_stream *f, void *context)
00483 {
00484         ht_file_window *w=(ht_file_window*)context;
00485 
00486         pstat_t p;
00487         dword oldsize = f->getIntDec(4, "filesize");
00488         dword oldtime = f->getIntDec(4, "filetime");
00489         dword newsize = w->file->get_size();
00490         w->file->pstat(&p);
00491         dword newtime = (p.caps & pstat_mtime) ? p.mtime : 0;
00492         
00493         if (f->get_error()) return f->get_error();
00494         
00495         if ((newsize != oldsize) || (newtime != oldtime)) {
00496                 char s_oldtime[64], s_newtime[64];
00497                 struct tm *t;
00498 
00499                 t=gmtime((time_t*)&newtime);
00500                 strftime(s_newtime, sizeof s_newtime, "%X %d %b %Y", t);
00501 
00502                 t=gmtime((time_t*)&oldtime);
00503                 strftime(s_oldtime, sizeof s_oldtime, "%X %d %b %Y", t);
00504 
00505                 if (confirmbox_c("\ecconfig file applies to different version of file '%s'.\n\n\elcurrent: %10d %s\n\elold:     %10d %s\n\n\ecload config file ?", w->file->get_desc(), newsize, s_newtime, oldsize, s_oldtime) != button_yes) {
00506                         return f->get_error();
00507                 }
00508         }
00509 
00510         Analyser *a=(Analyser*)f->getObject("analyser");
00511 
00512         if (f->get_error()) return f->get_error();
00513 
00514         htmsg m;
00515         m.msg=msg_set_analyser;
00516         m.type=mt_broadcast;
00517         m.data1.ptr=a;
00518         w->sendmsg(&m);
00519 
00520         return f->get_error();
00521 }
00522 
00523 void file_window_store_fcfg_func(ht_object_stream *f, void *context)
00524 {
00525         ht_file_window *w=(ht_file_window*)context;
00526         htmsg m;
00527         m.msg=msg_get_analyser;
00528         m.type=mt_broadcast;
00529         m.data1.ptr=NULL;
00530         w->sendmsg(&m);
00531         if ((m.msg==msg_retval) && (m.data1.ptr)) {
00532                 pstat_t s;
00533                 w->file->pstat(&s);
00534                 dword t = (s.caps & pstat_mtime) ? s.mtime : 0;;
00535                 f->putIntDec(w->file->get_size(), 4, "filesize");
00536                 f->putIntDec(t, 4, "filetime");
00537                 
00538                 Analyser *a=(Analyser*)m.data1.ptr;
00539                 f->putObject(a, "analyser");
00540         }
00541 }
00542 
00543 void file_project_store_fcfg_func(ht_object_stream *f, void *context)
00544 {
00545         f->putObject((ht_project*)project, NULL);
00546 }
00547 
00548 int file_project_load_fcfg_func(ht_object_stream *f, void *context)
00549 {
00550         project = f->getObject(NULL);
00551         return f->get_error();
00552 }
00553 
00554 /*
00555  *   app_stream_error_func()
00556  */
00557 
00558 int app_stream_error_func(ht_stream *stream)
00559 {
00560         int err=stream->get_error();
00561         const char *name = stream->get_desc();
00562         if (err & STERR_SYSTEM) {
00563                 err=err&0xffff;
00564                 switch (err) {
00565                         case 4: {       /* EACCES*/
00566 #ifdef DJGPP
00567                                 struct stat sbuf;
00568 
00569                                 stat(name, &sbuf);
00570 
00571                                 if (!(sbuf.st_mode & S_IWUSR)) {
00572                                         if (msgbox(btmask_yes | btmask_no, "title", 1, align_center, "%s: stream error (Permission denied), seems to be a (DOS) read-only file. Change attribute ?", name)==button_yes) {
00573                                                 if (chmod(name, S_IRUSR | S_IWUSR)) {
00574                                                         errorbox_modal("%s: error (%04x) changing attribute", name, errno & 0xffff);
00575                                                 } else {
00576                                                         stat(name, &sbuf);
00577 
00578                                                         if (!(sbuf.st_mode & S_IWUSR)) {
00579                                                                 errorbox_modal("%s: error (%04x) changing attribute", name, errno & 0xffff);
00580                                                         } else {
00581                                                                 return SERR_RETRY;
00582                                                         }
00583                                                 }
00584                                         }
00585                                 }
00586 
00587                                 break;
00588 #endif
00589                         }
00590                         default:
00591                                 errorbox_modal("%s: stream error %04x: %s", name, err, strerror(err));
00592                 }
00593         } else {
00594                 err=err&0xffff;
00595                 errorbox_modal("%s: internal stream error %04x", name, err);
00596         }
00597         return SERR_FAIL;
00598 }
00599 
00600 /*
00601  *   app_out_of_memory_proc()
00602  */
00603 void *app_memory_reserve=0;
00604 
00605 int app_out_of_memory_proc(int size)
00606 {
00607         if (app_memory_reserve) {
00608                 free(app_memory_reserve);
00609                 app_memory_reserve = 0;
00610                 warnbox_modal("the memory is getting low...");
00611                 return OUT_OF_MEMORY_RETRY;
00612         } else {
00613                 return OUT_OF_MEMORY_FAIL;
00614         }
00615 }
00616 
00617 /*
00618  *      CLASS ht_project
00619  */
00620 
00621 static int compare_keys_project_item(Object *key_a, Object *key_b)
00622 {
00623         ht_project_item *a=(ht_project_item *)key_a;
00624         ht_project_item *b=(ht_project_item *)key_b;
00625         int c = sys_filename_cmp(a->get_path(), b->get_path());
00626         return (c == 0) ? sys_filename_cmp(a->get_filename(), b->get_filename()) : c;
00627 }
00628 
00629 void ht_project::init(char *fn)
00630 {
00631         ht_sorted_list::init(compare_keys_project_item);
00632         filename = strdup(fn);
00633 }
00634 
00635 void ht_project::done()
00636 {
00637         free(filename);
00638         ht_sorted_list::done();
00639 }
00640 
00641 char *ht_project::get_filename()
00642 {
00643         return filename;
00644 }
00645 
00646 int ht_project::load(ht_object_stream *s)
00647 {
00648 // FIXME: probably not The Right Thing
00649         filename = strdup(s->get_desc());
00650         return ht_sorted_list::load(s);
00651 }
00652 
00653 OBJECT_ID ht_project::object_id() const
00654 {
00655         return ATOM_HT_PROJECT;
00656 }
00657 
00658 void ht_project::store(ht_object_stream *s)
00659 {
00660         return ht_sorted_list::store(s);
00661 }
00662 
00663 /*
00664  *      CLASS ht_project_item
00665  */
00666 
00667 void ht_project_item::init(char *f, char *p)
00668 {
00669         filename = strdup(f);
00670         path = strdup(p);
00671 }
00672 
00673 void ht_project_item::done()
00674 {
00675         free(filename);
00676         free(path);
00677 }
00678 
00679 const char *ht_project_item::get_filename()
00680 {
00681         return filename;
00682 }
00683 
00684 const char *ht_project_item::get_path()
00685 {
00686         return path;
00687 }
00688 
00689 int ht_project_item::load(ht_object_stream *s)
00690 {
00691         filename = s->getString(NULL);
00692         path = s->getString(NULL);
00693         return s->get_error();
00694 }
00695 
00696 OBJECT_ID ht_project_item::object_id() const
00697 {
00698         return ATOM_HT_PROJECT_ITEM;
00699 }
00700 
00701 void ht_project_item::store(ht_object_stream *s)
00702 {
00703         s->putString(filename, NULL);
00704         s->putString(path, NULL);
00705 }
00706 
00707 /*
00708  *      CLASS ht_project_list
00709  */
00710 
00711 void    ht_project_listbox::init(bounds *b, ht_project *p)
00712 {
00713         project = p;
00714         ht_listbox::init(b);
00715         colwidths[0] = 16;
00716         colwidths[1] = 16;
00717 }
00718 
00719 int  ht_project_listbox::calcCount()
00720 {
00721         return project ? project->count() : 0;
00722 }
00723 
00724 void ht_project_listbox::draw()
00725 {
00726         if (project) {
00727                 ht_listbox::draw();
00728         } else {
00729         
00730                 vcp fc = focused ? getcolor(palidx_generic_list_focused_unselected) :
00731                         getcolor(palidx_generic_list_unfocused_unselected);
00732 
00733                 clear(fc);
00734                 buf_print(0, 0, fc, "<no project>");
00735         }
00736 }
00737 
00738 char *ht_project_listbox::func(UINT i, bool execute)
00739 {
00740         return NULL;
00741 }
00742 
00743 void *ht_project_listbox::getFirst()
00744 {
00745         if (project && project->count()) {
00746                 return (void*)1;
00747         } else {
00748                 return NULL;
00749         }
00750 }
00751 
00752 void *ht_project_listbox::getLast()
00753 {
00754         if (project && project->count()) {
00755                 return (void*)(project->count());
00756         } else {
00757                 return NULL;
00758         }
00759 }
00760 
00761 void *ht_project_listbox::getNext(void *entry)
00762 {
00763         UINT e=(UINT)entry;
00764         if (!e) return NULL;
00765         if (project && (e < project->count())) {
00766                 return (void*)(e+1);
00767         } else {
00768                 return NULL;
00769         }
00770 }
00771 
00772 void *ht_project_listbox::getPrev(void *entry)
00773 {
00774         UINT e=(UINT)entry;
00775         if (e > 1) {
00776                 return (void*)(e-1);
00777         } else {
00778                 return NULL;
00779         }
00780 }
00781 
00782 char *ht_project_listbox::getStr(int col, void *entry)
00783 {
00784         static char mybuf[32];
00785         if (project) switch (col) {
00786                 case 0:
00787                         ht_snprintf(mybuf, sizeof mybuf, "%s", ((ht_project_item*)project->get((int)entry-1))->get_filename());
00788                         break;
00789                 case 1:
00790                         ht_snprintf(mybuf, sizeof mybuf, "%s", ((ht_project_item*)project->get((int)entry-1))->get_path());
00791                         break;
00792                 default:
00793                         strcpy(mybuf, "?");
00794         } else {
00795                 strcpy(mybuf, "<no project>");
00796         }
00797         return mybuf;
00798 }
00799 
00800 void ht_project_listbox::handlemsg(htmsg *msg)
00801 {
00802         switch (msg->msg) {
00803                 case cmd_project_add_item: {
00804                         if (project) {
00805                                 char fn[FILENAME_MAX];
00806                                 if (file_chooser("Add project item", fn, sizeof fn)) {
00807                                         char ffn[HT_NAME_MAX];
00808                                         char dir[HT_NAME_MAX];
00809                                         if ((sys_common_canonicalize(ffn, fn, NULL, sys_is_path_delim) == 0)
00810                                         && (sys_basename(fn, ffn) == 0)
00811                                         && (sys_dirname(dir, ffn) == 0)) {
00812                                                 ht_project_item *p = new ht_project_item();
00813                                                 p->init(fn, dir);
00814                                                 ((ht_project*)project)->insert(p);
00815                                                 app->sendmsg(msg_project_changed);
00816                                         }
00817                                 }
00818                         }
00819                         clearmsg(msg);
00820                         return;
00821                 }
00822                 case cmd_project_remove_item: {
00823                         int p = pos;
00824                         if (calcCount() && confirmbox("Really remove item '%s' ?", ((ht_project_item*)project->get(p))->get_filename()) == button_ok) {
00825                                 cursorUp(1);
00826                                 project->del(p);
00827                                 update();
00828                                 if (p) cursorDown(1);
00829                                 dirtyview();
00830                                 rearrangeColumns();
00831                         }
00832                         clearmsg(msg);
00833                         return;
00834                 }
00835                 case msg_keypressed: {
00836                         switch (msg->data1.integer) {
00837                                 case K_Return: {
00838                                         if (calcCount() && selectEntry(e_cursor)) {
00839                                                 clearmsg(msg);
00840                                                 return;
00841                                         }
00842                                 }
00843                         }
00844                         break;
00845                 }
00846         }
00847         ht_listbox::handlemsg(msg);
00848 }
00849 
00850 int ht_project_listbox::numColumns()
00851 {
00852         return 2;
00853 }
00854 
00855 void *ht_project_listbox::quickfind(char *s)
00856 {
00857         void *item = getFirst();
00858         int slen = strlen(s);
00859         while (item && (ht_strncmp(getStr(0, item), s, slen)!=0)) {
00860                 item = getNext(item);
00861         }
00862         return item;
00863 }
00864 
00865 char    *ht_project_listbox::quickfindCompletition(char *s)
00866 {
00867         void *item = getFirst();
00868         char *res = NULL;
00869         int slen = strlen(s);
00870         while (item) {
00871                 if (ht_strncmp(getStr(0, item), s, slen)==0) {
00872                         if (!res) {
00873                                 res = ht_strdup(getStr(0, item));
00874                         } else {
00875                                 int a = strccomm(res, getStr(0, item));
00876                                 res[a] = 0;
00877                         }
00878                 }
00879                 item = getNext(item);
00880         }
00881         return res;
00882 }
00883 
00884 bool ht_project_listbox::selectEntry(void *entry)
00885 {
00886         int p = pos;
00887         ht_project_item *i = (ht_project_item *)project->get(p);
00888         char fn[HT_NAME_MAX];
00889         if (sys_common_canonicalize(fn, i->get_filename(), i->get_path(), sys_is_path_delim)==0) {
00890                 ((ht_app*)app)->create_window_file(fn, FOM_AUTO, false);
00891         }
00892         return true;
00893 }
00894 
00895 void ht_project_listbox::set_project(ht_project *p)
00896 {
00897         project = p;
00898         update();
00899 }
00900 
00901 /*
00902  *      CLASS ht_project_window
00903  */
00904 
00905 void    ht_project_window::init(bounds *b, char *desc, UINT framestyle, UINT number, ht_project **p)
00906 {
00907         ht_window::init(b, desc, framestyle, number);
00908         project = p;
00909 
00910         bounds c = *b;
00911         c.x = 0;
00912         c.y = 0;
00913         c.w -= 2;
00914         c.h -= 2;
00915         plb = new ht_project_listbox();
00916         plb->init(&c, *p);
00917 
00918         insert(plb);
00919         sendmsg(msg_project_changed);
00920 }
00921 
00922 void ht_project_window::done()
00923 {
00924         ht_window::done();
00925 }
00926 
00927 void ht_project_window::handlemsg(htmsg *msg)
00928 {
00929         switch (msg->msg) {
00930                 case msg_project_changed: {
00931                         char *t = *project ? (*project)->get_filename() : NULL;
00932                         if (t) ht_snprintf(wtitle, sizeof wtitle, "project '%s'", t); else strcpy(wtitle, "project window");
00933                         settitle(wtitle);
00934                         plb->set_project(*project);
00935                         break;
00936                 }
00937                 case msg_contextmenuquery: {
00938                         ht_static_context_menu *projects=new ht_static_context_menu();
00939                         projects->init("~Project");
00940                         projects->insert_entry("~Add item", "Insert", cmd_project_add_item, K_Insert, 1);
00941                         projects->insert_entry("~Remove item", "Delete", cmd_project_remove_item, K_Delete, 1);
00942 //                      projects->insert_entry("~Edit item", NULL, cmd_project_edit_item, 0, 1);
00943 
00944                         msg->msg = msg_retval;
00945                         msg->data1.ptr = projects;
00946                         return;
00947                 }
00948         }
00949         ht_window::handlemsg(msg);
00950 }
00951 
00952 /*
00953  *      CLASS ht_status
00954  */
00955 
00956 void ht_status::init(bounds *b)
00957 {
00958         ht_view::init(b, VO_TRANSPARENT_CHARS, 0);
00959         VIEW_DEBUG_NAME("ht_status");
00960         idle_count = 0;
00961         analy_ani = 0;
00962         clear_len = 0;
00963         format = get_config_string("misc/statusline");
00964         
00965         if (!format) {
00966                 format = strdup(STATUS_DEFAULT_FORMAT);
00967         }
00968         
00969         render();
00970         register_idle_object(this);
00971 }
00972 
00973 void ht_status::done()
00974 {
00975         unregister_idle_object(this);
00976         if (format) free(format);
00977         ht_view::done();
00978 }
00979 
00980 char *ht_status::defaultpalette()
00981 {
00982         return palkey_generic_menu_default;
00983 }
00984 
00985 void ht_status::draw()
00986 {
00987         fill(size.w-clear_len, 0, clear_len, 1, getcolor(palidx_generic_text_focused), ' ');
00988         int len=strlen(workbuf);
00989         clear_len = len;
00990         buf_print(size.w-len, 0, getcolor(palidx_generic_text_focused), workbuf);
00991 }
00992 
00993 void ht_status::handlemsg(htmsg *msg)
00994 {
00995         switch (msg->msg) {
00996                 case msg_config_changed:
00997                         if (format) free(format);
00998                         format = get_config_string("misc/statusline");
00999                         break;
01000         }
01001         ht_view::handlemsg(msg);
01002 }
01003 
01004 bool ht_status::idle()
01005 {
01006         if (idle_count % 100 == 0) {
01007                 char *oldstatus=ht_strdup(workbuf);
01008                 render();
01009                 if (strcmp(oldstatus, workbuf)) {
01010                         dirtyview();
01011                         redraw();
01012                         screen->show();
01013                 }
01014                 free(oldstatus);
01015                 
01016                 analy_ani++;
01017                 analy_ani &= 7;
01018         }
01019         idle_count++;
01020         return false;
01021 }
01022 
01023 void ht_status::render()
01024 {
01025         char *f = format;
01026         char *buf = workbuf;
01027         if (f)
01028         while (*f) {
01029                 if (*f==STATUS_ESCAPE) {
01030                         switch (*(++f)) {
01031                                 case STATUS_ESCAPE:
01032                                         *(buf++) = STATUS_ESCAPE;
01033                                         break;
01034                                 case STATUS_ANALY_ACTIVE:
01035                                         if (some_analyser_active) {
01036                                                 char *analysers[] = {"Analy", "aNaly", "anAly", "anaLy", "analY", "anaLy", "anAly", "aNaly"};
01037                                                 strcpy(buf, analysers[analy_ani]);
01038                                                 buf += 5;
01039                                         }
01040                                         break;
01041                                 case STATUS_ANALY_LINES:
01042                                         if (some_analyser_active) {
01043                                                 buf += sprintf(buf, "(%d)", num_ops_parsed);
01044                                         }
01045                                         break;
01046                                 case STATUS_TIME: {
01047                                         time_t Time;
01048                                         time(&Time);
01049                                         tm *t=localtime(&Time);
01050                                         buf += sprintf(buf, "%02d:%02d", t->tm_hour, t->tm_min);
01051                                         break;
01052                                 }
01053                                 case STATUS_DATE: {
01054                                         time_t Time;
01055                                         time(&Time);
01056                                         tm *t=localtime(&Time);
01057                                         buf += sprintf(buf, "%02d.%02d.%04d", t->tm_mday, t->tm_mon+1, t->tm_year+1900);
01058                                         break;
01059                                 }
01060                         }
01061                 } else {
01062                         *(buf++) = *f;
01063                 }
01064                 f++;
01065         }
01066         *buf = 0;
01067 }
01068 
01069 
01070 /*
01071  *      CLASS ht_keyline
01072  */
01073 
01074 void ht_keyline::init(bounds *b)
01075 {
01076         ht_view::init(b, 0, 0);
01077         VIEW_DEBUG_NAME("ht_keyline");
01078 }
01079 
01080 void ht_keyline::done()
01081 {
01082         ht_view::done();
01083 }
01084 
01085 char *ht_keyline::defaultpalette()
01086 {
01087         return palkey_generic_keys_default;
01088 }
01089 
01090 void ht_keyline::draw()
01091 {
01092         clear(getcolor(palidx_generic_text_disabled));
01093         int x=0;
01094         for (int i=1; i<=10; i++) {
01095                 htmsg msg;
01096                 msg.type=mt_empty;
01097                 msg.msg=msg_funcquery;
01098                 msg.data1.integer=i;
01099                 baseview->sendmsg(&msg);
01100                 buf_printchar(x, 0, getcolor(palidx_generic_text_shortcut), '0'+i%10);
01101                 if (msg.msg==msg_retval) {
01102                         char *s=msg.data1.str;
01103                         if (s) {
01104                                 if (s[0]=='~') {
01105                                         buf_printf(x+1, 0, getcolor(palidx_generic_text_disabled), s+1);
01106                                 } else {
01107                                         for (int j=0; j<size.w/10-1; j++) {
01108                                                 buf_printf(x+j+1, 0, getcolor(palidx_generic_text_focused), " ");
01109                                         }
01110                                         buf_printf(x+1, 0, getcolor(palidx_generic_text_focused), s);
01111                                 }
01112                         }
01113                 }
01114                 x+=size.w/10;
01115         }
01116 }
01117 
01118 void ht_keyline::handlemsg(htmsg *msg)
01119 {
01120         ht_view::handlemsg(msg);
01121 }
01122 
01123 /*
01124  *      CLASS ht_desktop
01125  */
01126 
01127 void ht_desktop::init(bounds *b)
01128 {
01129         ht_view::init(b, VO_OWNBUFFER, 0);
01130         VIEW_DEBUG_NAME("ht_desktop");
01131 }
01132 
01133 void ht_desktop::done()
01134 {
01135         ht_view::done();
01136 }
01137 
01138 char *ht_desktop::defaultpalette()
01139 {
01140         return palkey_generic_desktop_default;
01141 }
01142 
01143 void ht_desktop::draw()
01144 {
01145         fill(0, 0, size.w, size.h, getcolor(palidx_generic_body), CHAR_FILLED_M);
01146 }
01147 
01148 /*
01149  *      CLASS ht_log_msg
01150  */
01151  
01152 ht_log_msg::ht_log_msg(vcp Color, char *Msg)
01153 {
01154         color = Color;
01155         msg = ht_strdup(Msg);
01156 }
01157 
01158 ht_log_msg::~ht_log_msg()
01159 {
01160         free(msg);
01161 }
01162 
01163 /*
01164  *      CLASS ht_log
01165  */
01166 
01167 void ht_log::init(compare_keys_func_ptr compare_keys)
01168 {
01169         ht_clist::init(compare_keys);
01170         maxlinecount = 128;
01171 }
01172 
01173 void ht_log::deletefirstline()
01174 {
01175         del(0);
01176 }
01177 
01178 void    ht_log::insertline(LogColor color, char *line)
01179 {
01180         if (count() >= maxlinecount) deletefirstline();
01181         vcp c;
01182         switch (color) {
01183                 case LOG_NORMAL: c = VCP(VC_WHITE, VC_TRANSPARENT); break;
01184                 case LOG_WARN: c = VCP(VC_LIGHT(VC_YELLOW), VC_TRANSPARENT); break;
01185                 case LOG_ERROR: c = VCP(VC_LIGHT(VC_RED), VC_TRANSPARENT); break;
01186                 default: c = VCP(VC_WHITE, VC_TRANSPARENT); break;
01187         }
01188         insert(new ht_log_msg(c, line));
01189 }
01190 
01191 void ht_log::log(LogColor c, char *line)
01192 {
01193         insertline(c, line);
01194 }
01195 
01196 /*
01197  *      CLASS ht_logviewer
01198  */
01199 
01200 void ht_logviewer::init(bounds *b, ht_window *w, ht_log *l, bool ol)
01201 {
01202         ht_viewer::init(b, "log", 0);
01203         VIEW_DEBUG_NAME("ht_logviewer");
01204         ofs = 0;
01205         xofs = 0;
01206         window = w;
01207         lines = l;
01208         own_lines = ol;
01209         update();
01210 }
01211 
01212 void ht_logviewer::done()
01213 {
01214         if (own_lines) {
01215                 lines->destroy();
01216                 delete lines;
01217         }
01218 
01219         ht_viewer::done();
01220 }
01221 
01222 int ht_logviewer::cursor_up(int n)
01223 {
01224         ofs -= n;
01225         if (ofs < 0) ofs = 0;
01226         return n;
01227 }
01228 
01229 int ht_logviewer::cursor_down(int n)
01230 {
01231         int c = lines->count();
01232         if (c >= size.h) {
01233                 ofs += n;
01234                 if (ofs > c-size.h) ofs = c-size.h;
01235         }
01236         return n;
01237 }
01238 
01239 void ht_logviewer::draw()
01240 {
01241         clear(getcolor(palidx_generic_body));
01242         int c = lines->count();
01243         for (int i=0; i < size.h; i++) {
01244                 if (i+ofs >= c) break;
01245                 ht_log_msg *msg = (ht_log_msg*)lines->get(i+ofs);
01246                 int l = strlen(msg->msg);
01247                 if (xofs<l) buf_print(0, i, /*getcolor(palidx_generic_body)*/msg->color, msg->msg+xofs);
01248         }
01249 }
01250 
01251 bool ht_logviewer::get_vscrollbar_pos(int *pstart, int *psize)
01252 {
01253         return scrollbar_pos(ofs, size.h, lines->count(), pstart, psize);
01254 }
01255 
01256 
01257 void ht_logviewer::handlemsg(htmsg *msg)
01258 {
01259         switch (msg->msg) {
01260                 case msg_get_scrollinfo:
01261                         switch (msg->data1.integer) {
01262 /*                              case gsi_pindicator: {
01263                                         get_pindicator_str((char*)msg->data2.ptr);
01264                                         break;
01265                                 }*/
01266 /*                              case gsi_hscrollbar: {
01267                                         gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
01268                                         if (!get_hscrollbar_pos(&p->pstart, &p->psize)) {
01269                                                 p->pstart = 0;
01270                                                 p->psize = 100;
01271                                         }
01272                                         break;
01273                                 }*/
01274                                 case gsi_vscrollbar: {
01275                                         gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
01276                                         if (!get_vscrollbar_pos(&p->pstart, &p->psize)) {
01277                                                 p->pstart = 0;
01278                                                 p->psize = 100;
01279                                         }
01280                                         clearmsg(msg);
01281                                         return;
01282                                 }
01283                         }
01284                         break;
01285                 case msg_log_changed: {
01286                         ofs = lines->count()-size.h;
01287                         if (ofs < 0) ofs = 0;
01288                         update();
01289                         clearmsg(msg);
01290                         return;
01291                 }
01292                 case msg_keypressed:
01293                         switch (msg->data1.integer) {
01294                                 case K_Up:
01295                                         cursor_up(1);
01296                                         update();
01297                                         clearmsg(msg);
01298                                         return;
01299                                 case K_Down:
01300                                         cursor_down(1);
01301                                         update();
01302                                         clearmsg(msg);
01303                                         return;
01304                                 case K_PageUp:
01305                                         cursor_up(size.h);
01306                                         update();
01307                                         clearmsg(msg);
01308                                         return;
01309                                 case K_PageDown:
01310                                         cursor_down(size.h);
01311                                         update();
01312                                         clearmsg(msg);
01313                                         return;
01314                                 case K_Right: case K_Control_Right:
01315                                         xofs += 2;
01316                                         update();
01317                                         clearmsg(msg);
01318                                         return;
01319                                 case K_Left: case K_Control_Left:
01320                                         if (xofs-2 >= 0) xofs -= 2;
01321                                         update();
01322                                         clearmsg(msg);
01323                                         return;
01324                                 case K_Control_PageUp:
01325                                         ofs = 0;
01326                                         update();
01327                                         clearmsg(msg);
01328                                         return;
01329                                 case K_Control_PageDown:
01330                                         ofs = lines->count()-size.h;
01331                                         if (ofs < 0) ofs = 0;
01332                                         update();
01333                                         clearmsg(msg);
01334                                         return;
01335                         }
01336                         break;
01337         }
01338         ht_viewer::handlemsg(msg);
01339 }
01340 
01341 void ht_logviewer::update()
01342 {
01343         dirtyview();
01344 }
01345 
01346 /*
01347  *      CLASS ht_app_window_entry
01348  */
01349 
01350 ht_app_window_entry::ht_app_window_entry(ht_window *w, UINT n, UINT t, bool m, bool isf, ht_layer_streamfile *l)
01351 {
01352         window=w;
01353         number=n;
01354         type=t;
01355         minimized=m;
01356         isfile=isf;
01357         layer=l;
01358 }
01359 
01360 ht_app_window_entry::~ht_app_window_entry()
01361 {
01362 }
01363 
01364 static int compare_keys_app_window_entry(Object *key_a, Object *key_b)
01365 {
01366         UINT a=((ht_app_window_entry*)key_a)->number;
01367         UINT b=((ht_app_window_entry*)key_b)->number;
01368         if (a>b) return 1; else if (a<b) return -1;
01369         return 0;
01370 }
01371 
01372 /*
01373  *      CLASS ht_app
01374  */
01375 
01376 static bool doFileChecks(ht_file *file)
01377 {
01378 // FIXME: this is notify-user-only. should actually also take the actions it claims to...
01379 //        (its done in stream.cc in ht_file::set_access_mode_internal()
01380         pstat_t s;
01381         file->pstat(&s);
01382         if (s.caps & pstat_mode_type) {
01383                 switch (s.mode & HT_S_IFMT) {
01384                         case HT_S_IFREG: return true;
01385                         default:
01386                                 LOG_EX(LOG_WARN, "file is not regular (but device, fifo or something...).");
01387                                 LOG_EX(LOG_WARN, "Write-access disabled for safety !");
01388                                 return true;
01389                 }
01390         } else {
01391                 LOG_EX(LOG_WARN, "can't determine file type (regular, device, directory...) ! assuming non-regular...");
01392                 LOG_EX(LOG_WARN, "file is not regular (but device, fifo or something...).");
01393                 LOG_EX(LOG_WARN, "Write-access disabled for safety !");
01394                 return true;
01395         }
01396         return false;
01397 }
01398 
01399 /*debug*/
01400 //#define DRAW_TIMINGS
01401 //#define NO_AVG
01402 #define AVG_TIMINGS 10
01403 int timings[AVG_TIMINGS];
01404 int cur_timing=0, max_timing=0;
01405 int h0;
01406 
01407 
01408 void ht_app::init(bounds *pq)
01409 {
01410         ht_dialog::init(pq, 0, 0);
01411         menu = NULL;
01412         setframe(NULL);
01413         VIEW_DEBUG_NAME("ht_app");
01414         exit_program = false;
01415         focused = true;
01416         bounds b;
01417 
01418         windows = new ht_sorted_list();
01419         windows->init(compare_keys_app_window_entry);
01420         
01421         syntax_lexers = new ht_clist();
01422         ((ht_clist*)syntax_lexers)->init();
01423 
01424         ht_c_syntax_lexer *c_lexer = new ht_c_syntax_lexer();
01425         c_lexer->init();
01426 
01427         syntax_lexers->insert(c_lexer);
01428 
01429         ht_html_syntax_lexer *html_lexer = new ht_html_syntax_lexer();
01430         html_lexer->init();
01431 
01432         syntax_lexers->insert(html_lexer);
01433         
01434         /* init timer */
01435         h0=new_timer();
01436 
01437         /* create menu */
01438         getbounds(&b);
01439         b.x=0;
01440         b.y=0;
01441         b.h=1;
01442         ht_menu *m=new ht_menu();
01443         m->init(&b);
01444 
01445         ht_static_context_menu *file=new ht_static_context_menu();
01446         file->init("~File");
01447         file->insert_entry("~New...", NULL, cmd_file_new, 0, 1);
01448         file->insert_entry("~Open...", "F3", cmd_file_open, 0, 1);
01449         file->insert_entry("~Save", NULL, cmd_file_save, 0, 1);
01450         file->insert_entry("Save ~As...", NULL, cmd_file_saveas, 0, 1);
01451         file->insert_separator();
01452         file->insert_entry("Open/Create ~project...", NULL, cmd_project_open, 0, 1);
01453         file->insert_entry("Close p~roject", NULL, cmd_project_close, 0, 1);
01454         file->insert_separator();
01455         file->insert_entry("~Execute", "Alt+Z", cmd_file_exec_cmd, K_Alt_Z, 1);
01456         file->insert_entry("~Quit", "F10", cmd_quit, 0, 1);
01457         m->insert_menu(file);
01458 
01459         ht_static_context_menu *edit=new ht_static_context_menu();
01460         edit->init("~Edit");
01461         edit->insert_entry("Cu~t", "Shift+Del", cmd_edit_cut, 0, 1);
01462         edit->insert_entry("~Delete", "Ctrl+Del", cmd_edit_delete, 0, 1);
01463         edit->insert_entry("~Copy", "Ctrl+Ins", cmd_edit_copy, 0, 1);
01464         edit->insert_entry("~Paste", "Shift+Ins", cmd_edit_paste, 0, 1);
01465         edit->insert_entry("~Show clipboard", 0, cmd_edit_show_clipboard, 0, 1);
01466         edit->insert_entry("C~lear clipboard", 0, cmd_edit_clear_clipboard, 0, 1);
01467         edit->insert_separator();
01468         edit->insert_entry("Copy ~from file...", 0, cmd_edit_copy_from_file, 0, 1);
01469         edit->insert_entry("Paste ~into file...", 0, cmd_edit_paste_into_file, 0, 1);
01470 #ifdef SYS_SUPPORT_NATIVE_CLIPBOARD
01471         edit->insert_separator();
01472         edit->insert_entry("Copy from "SYS_NATIVE_CLIPBOARD_NAME, 0, cmd_edit_copy_native, 0, 1);
01473         edit->insert_entry("Paste into "SYS_NATIVE_CLIPBOARD_NAME, 0, cmd_edit_paste_native, 0, 1);
01474 #endif
01475         edit->insert_separator();
01476         edit->insert_entry("~Evaluate...", 0, cmd_popup_dialog_eval, 0, 1);
01477         m->insert_menu(edit);
01478 
01479         ht_static_context_menu *windows=new ht_static_context_menu();
01480         windows->init("~Windows");
01481         windows->insert_entry("~Size/Move", "Alt+F5", cmd_window_resizemove, K_Alt_F5, 1);
01482         windows->insert_entry("~Close", "Alt+F3", cmd_window_close, K_Alt_F3, 1);
01483         windows->insert_entry("~Close (alt)", "Ctrl+W", cmd_window_close, K_Control_W, 1);
01484         windows->insert_entry("~List", "Alt+0", cmd_popup_dialog_window_list, K_Alt_0, 1);
01485         windows->insert_separator();
01486         windows->insert_entry("Lo~g window", NULL, cmd_popup_window_log, 0, 1);
01487         windows->insert_entry("~Options", NULL, cmd_popup_window_options, 0, 1);
01488         windows->insert_entry("~Project", NULL, cmd_popup_window_project, 0, 1);
01489         m->insert_menu(windows);
01490 
01491         ht_static_context_menu *help=new ht_static_context_menu();
01492         help->init("~Help");
01493         help->insert_entry("~About "ht_name, "", cmd_about, 0, 1);
01494         help->insert_separator();
01495         help->insert_entry("~Help contents", "F1", cmd_popup_window_help, 0, 1);
01496         help->insert_entry("~Open info file...", NULL, cmd_popup_dialog_info_loader, 0, 1);
01497         m->insert_menu(help);
01498 
01499         m->insert_local_menu();
01500 
01501         menu=m;
01502         insert(menu);
01503         
01504         /* create status */
01505         /* the status should have the same bounds as the menu */
01506         ht_status *status = new ht_status();
01507         status->init(&b);
01508         status->setpalette(menu->getpalette());
01509         insert(status);
01510         
01511         /* create desktop */
01512         getbounds(&b);
01513         b.x=0;
01514         b.y=1;
01515         b.h-=2;
01516         desktop=new ht_desktop();
01517         desktop->init(&b);
01518         insert(desktop);
01519         
01520         /* create keyline */
01521         getbounds(&b);
01522         b.x=0;
01523         b.y=b.h-1;
01524         b.h=1;
01525         keyline=new ht_keyline();
01526         keyline->init(&b);
01527         insert(keyline);
01528 
01529         /* create battlefield */
01530         getbounds(&b);
01531         b.x=0;
01532         b.y=1;
01533         b.h-=2;
01534 
01535         battlefield=new ht_group();
01536         battlefield->init(&b, VO_TRANSPARENT_CHARS, "battlefield");
01537         insert(battlefield);
01538 
01539         create_window_log();
01540 }
01541 
01542 void ht_app::done()
01543 {
01544         delete_timer(h0);
01545 
01546         syntax_lexers->destroy();
01547         delete syntax_lexers;
01548 
01549         if (windows) {
01550                 windows->destroy();
01551                 delete windows;
01552         }
01553 
01554         ht_dialog::done();
01555 }
01556 
01557 bool ht_app::accept_close_all_windows()
01558 {
01559         UINT wc=windows->count();
01560         ht_app_window_entry *e;
01561         for (UINT i=0; i<wc; i++) {
01562                 e=(ht_app_window_entry*)windows->get(i);
01563                 htmsg m;
01564                 m.msg=msg_accept_close;
01565                 m.type=mt_empty;
01566                 e->window->sendmsg(&m);
01567                 if (m.msg!=msg_accept_close) return false;
01568         }
01569         return true;
01570 }
01571 
01572 ht_window *ht_app::create_window_log()
01573 {
01574         ht_window *w=get_window_by_type(AWT_LOG);
01575         if (w) {
01576                 focus(w);
01577         } else {
01578                 bounds b;
01579 /*              battlefield->getbounds(&b);
01580                 b.x = 0;
01581                 b.y = 0;*/
01582                 get_stdbounds_file(&b);
01583 
01584                 ht_window *logwindow=new ht_window();
01585                 logwindow->init(&b, "log window", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0);
01586                 
01587                 bounds k=b;
01588                 k.x=b.w-2;
01589                 k.y=0;
01590                 k.w=1;
01591                 k.h-=2;
01592                 ht_scrollbar *hs=new ht_scrollbar();
01593                 hs->init(&k, &logwindow->pal, true);
01594 
01595                 logwindow->setvscrollbar(hs);
01596 
01597                 b.x=0;
01598                 b.y=0;
01599                 b.w-=2;
01600                 b.h-=2;
01601                 ht_logviewer *logviewer=new ht_logviewer();
01602                 logviewer->init(&b, logwindow, loglines, false);
01603                 logwindow->insert(logviewer);
01604                 
01605                 insert_window(logwindow, AWT_LOG, 0, false, NULL);
01606         }
01607         return w;
01608 }
01609 
01610 ht_window *ht_app::create_window_term(const char *cmd)
01611 {
01612         ht_window *w = get_window_by_type(AWT_TERM);
01613         if (w) {
01614                 focus(w);
01615         } else {
01616                 bounds b;
01617                 get_stdbounds_file(&b);
01618 
01619                 ht_window *termwindow=new ht_window();
01620                 termwindow->init(&b, "terminal", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0);
01621                 
01622                 bounds k=b;
01623                 k.x=3;
01624                 k.y=k.h-2;
01625                 k.w-=7;
01626                 k.h=1;
01627                 ht_statictext *ind=new ht_statictext();
01628                 ind->init(&k, NULL, align_left, false, true);
01629                 ind->disable_buffering();
01630                 ind->growmode = MK_GM(GMH_FIT, GMV_BOTTOM);
01631 
01632                 termwindow->setpindicator(ind);
01633 
01634                 k=b;
01635                 k.x=b.w-2;
01636                 k.y=0;
01637                 k.w=1;
01638                 k.h-=2;
01639                 ht_scrollbar *hs=new ht_scrollbar();
01640                 hs->init(&k, &termwindow->pal, true);
01641 
01642                 termwindow->setvscrollbar(hs);
01643 
01644                 ht_streamfile *in, *out, *err;
01645                 int handle;
01646                 int e;
01647                 if ((e = sys_ipc_exec(&in, &out, &err, &handle, cmd, 0)) == 0) {
01648                         Terminal *terminal = new Terminal();
01649                         terminal->init(in, out, err, handle);
01650 
01651                         b.x=0;
01652                         b.y=0;
01653                         b.w-=2;
01654                         b.h-=2;
01655                         TerminalViewer *termviewer=new TerminalViewer();
01656                         termviewer->init(&b, terminal, true);
01657                         termwindow->insert(termviewer);
01658                 
01659                         insert_window(termwindow, AWT_LOG, 0, false, NULL);
01660                 } else {
01661                         errorbox("couldn't create child-process (%d)", e);
01662                         return NULL;
01663                 }
01664         }
01665         return w;
01666 }
01667 
01668 ht_window *ht_app::create_window_clipboard()
01669 {
01670         ht_window *w=get_window_by_type(AWT_CLIPBOARD);
01671         if (w) {
01672                 focus(w);
01673                 return w;
01674         } else {
01675                 bounds b;
01676                 get_stdbounds_file(&b);
01677 /*              ht_file_window *window=new ht_file_window();
01678                 window->init(&b, "clipboard", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0, clipboard);*/
01679                 ht_window *window=new ht_window();
01680                 window->init(&b, "clipboard", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0);
01681                 
01682 /*              bounds k=b;
01683                 k.x=b.w-2;
01684                 k.y=0;
01685                 k.w=1;
01686                 k.h-=2;
01687                 ht_scrollbar *hs=new ht_scrollbar();
01688                 hs->init(&k, &window->pal, true);
01689 
01690                 window->setvscrollbar(hs);*/
01691 
01692                 bounds k;
01693                 k = b;
01694                 k.x=3;
01695                 k.y=k.h-2;
01696                 k.w-=7;
01697                 k.h=1;
01698                 ht_statictext *ind=new ht_statictext();
01699                 ind->init(&k, NULL, align_left, false, true);
01700                 ind->disable_buffering();
01701                 ind->growmode = MK_GM(GMH_FIT, GMV_BOTTOM);
01702 
01703                 window->setpindicator(ind);
01704 
01705                 b.x=0;
01706                 b.y=0;
01707                 b.w-=2;
01708                 b.h-=2;
01709                 ht_clipboard_viewer *v=new ht_clipboard_viewer();
01710                 v->init(&b, "clipboard", VC_EDIT | VC_GOTO | VC_SEARCH, clipboard, 0);
01711 
01712                 window->insert(v);
01713 // FIXME: needs wrapper (layer)
01714 //              insert_window(window, AWT_CLIPBOARD, 0, false, clipboard);
01715                 insert_window(window, AWT_CLIPBOARD, 0, false, NULL);
01716         }
01717         return NULL;
01718 }
01719 
01720 ht_window *ht_app::create_window_file(char *filename, UINT mode, bool allow_duplicates)
01721 {
01722         if (mode==FOM_AUTO) mode=autodetect_file_open_mode(filename);
01723         switch (mode) {
01724                 case FOM_BIN: return create_window_file_bin(filename, allow_duplicates);
01725                 case FOM_TEXT: return create_window_file_text(filename, allow_duplicates);
01726         }
01727         return NULL;
01728 }
01729 
01730 ht_window *ht_app::create_window_file_bin(char *filename, bool allow_duplicates)
01731 {
01732         bounds b;
01733         get_stdbounds_file(&b);
01734         int e;
01735         char fullfilename[FILENAME_MAX];
01736         if ((e=sys_canonicalize(fullfilename, filename))) {
01737                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01738                 return NULL;
01739         }
01740 
01741         ht_window *w;
01742         if (!allow_duplicates && ((w = get_window_by_filename(fullfilename)))) {
01743                 focus(w);
01744                 return w;
01745         }
01746 
01747         ht_file *emfile = new ht_file();
01748         emfile->init(fullfilename, FAM_READ, FOM_EXISTS);
01749 
01750         if ((e = emfile->get_error())) {
01751                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01752                 return NULL;
01753         }
01754 
01755         if (!doFileChecks(emfile)) return NULL;
01756 
01757         ht_streamfile_modifier *mfile = new ht_streamfile_modifier();
01758         mfile->init(emfile, true, 8*1024);
01759 
01760         ht_layer_streamfile *file = new ht_layer_streamfile();
01761         file->init(mfile, true);
01762                          
01763         if ((e=file->get_error())) {
01764                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01765                 return NULL;
01766         }
01767         LOG("loading binary file %s...", fullfilename);
01768         file->set_error_func(app_stream_error_func);
01769 
01770         return create_window_file_bin(&b, file, fullfilename, true);
01771 }
01772 
01773 ht_window *ht_app::create_window_file_bin(bounds *b, ht_layer_streamfile *file, char *title, bool isfile)
01774 {
01775         ht_file_window *window = new ht_file_window();
01776         window->init(b, title, FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0, file);
01777 
01778         bounds k=*b;
01779         k.x=b->w-2;
01780         k.y=0;
01781         k.w=1;
01782         k.h-=2;
01783         ht_scrollbar *hs=new ht_scrollbar();
01784         hs->init(&k, &window->pal, true);
01785 
01786         window->setvscrollbar(hs);
01787 
01788         k=*b;
01789         k.x=3;
01790         k.y=k.h-2;
01791         k.w-=7;
01792         k.h=1;
01793         ht_statictext *ind=new ht_statictext();
01794         ind->init(&k, NULL, align_left, false, true);
01795         ind->disable_buffering();
01796         ind->growmode = MK_GM(GMH_FIT, GMV_BOTTOM);
01797 
01798         window->setpindicator(ind);
01799 
01800         k=*b;
01801         k.x=0;
01802         k.y=0;
01803         k.w-=2;
01804         k.h-=2;
01805         ht_format_group *format_group=new ht_format_group();
01806         format_group->init(&k, VO_SELECTABLE | VO_RESIZE, VIEWERGROUP_NAME, file, true, true, format_viewer_ifs, NULL);
01807 
01808         window->insert(format_group);
01809 
01810         
01811         if (isfile) {
01812                 char cfgfilename[FILENAME_MAX];
01813                 strcpy(cfgfilename, title);
01814                 strcat(cfgfilename, HT_FILE_CONFIG_SUFFIX);
01815 
01816                 int einfo;
01817                 LOG("%s: loading config file...", cfgfilename);
01818                 loadstore_result lsr = load_fileconfig(cfgfilename, ht_fileconfig_magic, ht_fileconfig_fileversion, file_window_load_fcfg_func, window, &einfo);
01819                 if (lsr == LS_ERROR_CORRUPTED) {
01820                         LOG_EX(LOG_ERROR, "%s: error in line %d", cfgfilename, einfo);
01821                         errorbox("%s: error in line %d",cfgfilename,  einfo);
01822                 } else if (lsr == LS_ERROR_MAGIC || lsr == LS_ERROR_FORMAT) {
01823                         LOG_EX(LOG_ERROR, "%s: wrong magic/format", cfgfilename);
01824                         errorbox("%s: wrong magic/format", cfgfilename);
01825                 } else if (lsr == LS_ERROR_VERSION) {
01826                         LOG_EX(LOG_ERROR, "%s: wrong version", cfgfilename);
01827                         errorbox("%s: wrong version", cfgfilename);
01828                 } else if (lsr == LS_ERROR_NOT_FOUND) {
01829                         LOG("%s: not found", cfgfilename);
01830                 } else if (lsr != LS_OK) {
01831                         LOG_EX(LOG_ERROR, "%s: some error", cfgfilename);
01832                         errorbox("%s: some error", cfgfilename);
01833                 } else {
01834                         LOG("%s: ok", cfgfilename);
01835                 }
01836         }
01837 
01838         
01839         if (isfile) LOG("%s: done.", title);
01840 
01841         htmsg m;
01842         m.msg = msg_postinit;
01843         m.type = mt_broadcast;
01844         window->sendmsg(&m);
01845 
01846         insert_window(window, AWT_FILE, 0, isfile, file);
01847         return window;
01848 }
01849 
01850 ht_window *ht_app::create_window_file_text(char *filename, bool allow_duplicates)
01851 {
01852         bounds b, c;
01853         get_stdbounds_file(&c);
01854         b = c;
01855         int e;
01856         char fullfilename[FILENAME_MAX];
01857         if ((e=sys_canonicalize(fullfilename, filename))) {
01858                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01859                 return NULL;
01860         }
01861 
01862         ht_window *w;
01863         if (!allow_duplicates && ((w = get_window_by_filename(fullfilename)))) {
01864                 focus(w);
01865                 return w;
01866         }
01867 
01868         ht_file *emfile = new ht_file();
01869         emfile->init(fullfilename, FAM_READ, FOM_EXISTS);
01870 
01871         if ((e=emfile->get_error())) {
01872                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01873                 return NULL;
01874         }
01875 
01876         if (!doFileChecks(emfile)) return NULL;
01877 
01878         ht_ltextfile *tfile = new ht_ltextfile();
01879         tfile->init(emfile, true, NULL);
01880 
01881         ht_layer_textfile *file=new ht_layer_textfile();
01882         file->init(tfile, true);
01883 
01884         if ((e=file->get_error())) {
01885                 LOG_EX(LOG_ERROR, "error loading file %s: %s", fullfilename, strerror(e & ~STERR_SYSTEM));
01886                 return NULL;
01887         }
01888 
01889         LOG("loading text file %s...", fullfilename);
01890         file->set_error_func(app_stream_error_func);
01891 
01892         return create_window_file_text(&b, file, fullfilename, true);
01893 }
01894 
01895 ht_window *ht_app::create_window_file_text(bounds *c, ht_layer_streamfile *f, char *title, bool isfile)
01896 {
01897         bounds b=*c;
01898 
01899         ht_layer_textfile *file = (ht_layer_textfile *)f;
01900         
01901         ht_file_window *window = new ht_file_window();
01902         window->init(&b, title, FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0, file);
01903 
01904         b.x=0;
01905         b.y=0;
01906         b.w-=2;
01907         b.h-=2;
01908         ht_text_editor *text_editor=new ht_text_editor();
01909         text_editor->init(&b, true, file, syntax_lexers, TEXTEDITOPT_INPUTTABS|TEXTEDITOPT_UNDO);
01910 
01911         char *fn_suf = sys_filename_suffix(file->get_filename());
01912 
01913         if (fn_suf) {
01914                 if ((ht_stricmp(fn_suf, "c") == 0) || (ht_stricmp(fn_suf, "cc") == 0)
01915                 || (ht_stricmp(fn_suf, "cpp") == 0)
01916                 || (ht_stricmp(fn_suf, "h") == 0) || (ht_stricmp(fn_suf, "hpp") == 0)) {
01917                         text_editor->set_lexer((ht_syntax_lexer*)syntax_lexers->get(0), false);
01918                 }
01919 #ifdef HT_HTML_SYNTAX_LEXER
01920                 if (ht_stricmp(fn_suf, "htm") == 0 || ht_stricmp(fn_suf, "html") == 0) {
01921                         text_editor->set_lexer((ht_syntax_lexer*)syntax_lexers->get(1), false);
01922                 }
01923 #endif
01924         }
01925 
01926         bounds k=*c;
01927         k.x=k.w-2;
01928         k.y=0;
01929         k.w=1;
01930         k.h-=2;
01931         ht_scrollbar *hs=new ht_scrollbar();
01932         hs->init(&k, &window->pal, true);
01933 
01934         window->setvscrollbar(hs);
01935 
01936         k=*c;
01937         k.x=3;
01938         k.y=k.h-2;
01939         k.w-=7;
01940         k.h=1;
01941         
01942         ht_statictext *ind=new ht_statictext();
01943         ind->init(&k, NULL, align_left, false, true);
01944         ind->disable_buffering();
01945         ind->growmode = MK_GM(GMH_FIT, GMV_BOTTOM);
01946 
01947         window->setpindicator(ind);
01948 
01949         window->insert(text_editor);
01950         if (isfile) LOG("%s: done.", title);
01951 
01952         insert_window(window, AWT_FILE, 0, isfile, file);
01953         return window;
01954 }
01955 
01956 ht_window *ht_app::create_window_help(char *file, char *node)
01957 {
01958         ht_window *w = get_window_by_type(AWT_HELP);
01959         if (w) {
01960                 focus(w);
01961                 return w;
01962         } else {
01963                 bounds b, c;
01964                 battlefield->getbounds(&c);
01965                 b.w=c.w*7/8;
01966                 b.h=c.h*7/8;
01967                 b.x=(c.w-b.w)/2;
01968                 b.y=(c.h-b.h)/2;
01969                 bounds k = b;
01970 
01971                 ht_help_window *window=new ht_help_window();
01972                 window->init(&b, "help", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0);
01973 
01974                 b.x=0;
01975                 b.y=0;
01976                 b.w-=2;
01977                 b.h-=2;
01978                 c=b;
01979 
01980                 b=c;
01981                 b.x+=b.w;
01982                 b.w=1;
01983                 ht_scrollbar *scrollbar=new ht_scrollbar();
01984                 scrollbar->init(&b, &window->pal, true);
01985                 scrollbar->enable();
01986                 window->setvscrollbar(scrollbar);
01987 
01988                 k.x=3;
01989                 k.y=k.h-2;
01990                 k.w-=7;
01991                 k.h=1;
01992                 ht_statictext *ind=new ht_statictext();
01993                 ind->init(&k, NULL, align_left, false, true);
01994                 ind->disable_buffering();
01995                 ind->growmode = MK_GM(GMH_FIT, GMV_BOTTOM);
01996 
01997                 window->setpindicator(ind);
01998 
01999                 b=c;
02000                 ht_info_viewer *infoviewer=new ht_info_viewer();
02001                 infoviewer->init(&b);
02002                 window->insert(infoviewer);
02003 
02004                 char ff[HT_NAME_MAX], cwd[HT_NAME_MAX];
02005 
02006                 cwd[0] = 0;
02007                 getcwd(cwd, sizeof cwd);
02008                 if (strcmp(file, "hthelp.info")) {
02009                         sys_common_canonicalize(ff, file, cwd, sys_is_path_delim);
02010                 } else {
02011                         strcpy(ff, file);
02012                 }
02013                 if (infoviewer->gotonode(ff, node)) {
02014                         insert_window(window, AWT_HELP, 0, false, NULL);
02015                         
02016                         window->setpalette(palkey_generic_cyan);
02017                         return window;
02018                 }
02019                 errorbox("help topic '(%s)%s' not found", file, node);
02020                 window->done();
02021                 delete window;
02022         }
02023         return NULL;
02024 }
02025 
02026 ht_window *ht_app::create_window_project()
02027 {
02028         ht_window *w=get_window_by_type(AWT_PROJECT);
02029         if (w) {
02030                 focus(w);
02031                 return w;
02032         } else {
02033                 bounds b;
02034                 get_stdbounds_tool(&b);
02035 
02036                 ht_project_window *project_window=new ht_project_window();
02037                 project_window->init(&b, "project window", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0, (ht_project**)&project);
02038 
02039                 bounds k = b;
02040                 k.x = b.w-2;
02041                 k.y = 0;
02042                 k.w = 1;
02043                 k.h -= 2;
02044                 ht_scrollbar *hs = new ht_scrollbar();
02045                 hs->init(&k, &project_window->pal, true);
02046 
02047                 project_window->sethscrollbar(hs);
02048 
02049 /*              b.x = 0;
02050                 b.y = 0;
02051                 b.w -= 2;
02052                 b.h -= 2;
02053                 ht_project_listbox *project_viewer = new ht_project_listbox();
02054                 project_viewer->init(&b, project);
02055                 project_window->insert(project_viewer);*/
02056 
02057                 insert_window(project_window, AWT_PROJECT, 0, false, NULL);
02058                 
02059                 project_window->setpalette(palkey_generic_cyan);
02060                 return project_window;
02061         }
02062 }
02063 
02064 #if 0
02065 ht_view *create_ofm_single(bounds *c, char *url, ht_vfs_viewer **x)
02066 {
02067         bounds b=*c;
02068         b.h-=2;
02069         ht_group *g=new ht_group();
02070         g->init(&b, VO_SELECTABLE, 0);
02071 
02072         bounds d=b;
02073         
02074         b.x=0;
02075         b.y=0;
02076         b.h=1;
02077         ht_vfs_viewer_status *vst=new ht_vfs_viewer_status();
02078         vst->init(&b);
02079            
02080         d.x=0;
02081         d.y=1;
02082         d.h--;
02083         ht_vfs_viewer *v=new ht_vfs_viewer();
02084         v->init(&d, "vfs viewer", 0, 0, 0, vst);
02085            
02086         g->insert(v);
02087 
02088         g->insert(vst);
02089 
02090         ht_vfs_sub *vs=new ht_vfs_sub();
02091         vs->init(url);
02092 
02093         v->insertsub(vs);
02094 
02095         v->sendmsg(msg_complete_init, 0);
02096 
02097         *x=v;
02098         return g;
02099 }
02100 #endif
02101 
02102 ht_window *ht_app::create_window_ofm(char *url1, char *url2)
02103 {
02104         bounds b;
02105         get_stdbounds_file(&b);
02106 
02107         ht_window *window=new ht_window();
02108         window->init(&b, "file manager", FS_KILLER | FS_TITLE | FS_NUMBER | FS_MOVE | FS_RESIZE, 0);
02109 #if 1
02110         b.w-=2;
02111         b.h-=2;
02112 
02113         VfsListbox2 *l = new VfsListbox2();
02114         l->init(&b, virtual_fs_list, window->getframe());
02115 
02116 //      l->changeURL("local:/bp/././..");
02117         l->changeURL(url1);
02118 
02119         window->insert(l);
02120 #else
02121         bounds b1, b2, b3;
02122 
02123         ht_vfs_viewer *v1, *v2=NULL;
02124 
02125         b.w-=2;
02126 
02127         b1=b;
02128         b1.w/=2;
02129         b1.w--;
02130         window->insert(create_ofm_single(&b1, url1, &v1));
02131 
02132         if (url2) {
02133                 b2=b;
02134                 b2.w/=2;
02135                 b2.x=b2.w-1;
02136                 b2.w=1;
02137                 b2.h-=2;
02138                 ht_vbar *x=new ht_vbar();
02139                 x->init(&b2, 0, 0);
02140                 window->insert(x);
02141 
02142                 b3=b;
02143                 b3.w/=2;
02144                 b3.x=b3.w;
02145                 window->insert(create_ofm_single(&b3, url2, &v2));
02146         }
02147 
02148         if (v2) {
02149                 v1->set_assoc_vfs_viewer(v2);
02150                 v2->set_assoc_vfs_viewer(v1);
02151         }
02152 #endif
02153         insert_window(window, AWT_OFM, 0, false, NULL);
02154         return window;
02155 }
02156 
02157 char *ht_app::defaultpalette()
02158 {
02159         return NULL;
02160 }
02161 
02162 char *ht_app::defaultpaletteclass()
02163 {
02164         return NULL;
02165 }
02166 
02167 int analy_id = 0;
02168 void ht_app::draw()
02169 {
02170 /* show draw timings */
02171 #ifdef DRAW_TIMING
02172         int xyz=get_timer_1024tick(h0);
02173         buf->printf(17, 1, 7, "cur: %d (%d msec)", xyz*1024, get_timer_msec(h0));
02174 #ifndef NO_AVG
02175         if (cur_timing>=AVG_TIMINGS-1) cur_timing=0;
02176         timings[cur_timing++]=xyz;
02177         if (cur_timing>max_timing) max_timing=cur_timing;
02178         int avg=0;
02179         for (int i=0; i<max_timing; i++) avg+=timings[i];
02180         avg=avg/max_timing;
02181         buf->printf(57, 1, 7, "avg%d: %d", max_timing+1, avg*1024);
02182 #endif
02183 #endif
02184 }
02185 
02186 void ht_app::delete_window(ht_window *window)
02187 {
02188         UINT i=get_window_listindex(window);
02189         if (i!=LIST_UNDEFINED) {
02190                 battlefield->remove(window);
02191 
02192                 windows->del(i);
02193 
02194                 window->done();
02195                 delete window;
02196         }
02197 }
02198 
02199 UINT ht_app::find_free_window_number()
02200 {
02201         UINT c=windows->count();
02202         UINT k=0;
02203 repeat:
02204         k++;
02205         for (UINT i=0; i<c; i++) {
02206                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02207                 if (e->number==k) goto repeat;
02208         }
02209         return k;
02210 }
02211 
02212 int ht_app::focus(ht_view *view)
02213 {
02214         return ht_dialog::focus(view);
02215 }
02216 
02217 char *ht_app::func(UINT i, bool execute)
02218 {
02219         switch (i) {
02220                 case 1:
02221                         if (execute) sendmsg(cmd_popup_window_help);
02222                         return "help";
02223                 case 3:
02224                         if (execute) sendmsg(cmd_file_open);
02225                         return "open";
02226                 case 6:
02227                         if (execute) sendmsg(cmd_popup_dialog_view_list);
02228                         return "mode";
02229                 /* FIXME: experimental */
02230 /*              case 9:
02231                         if (execute) {
02232                                 create_window_term("make");
02233                         }
02234                         return "make";*/
02235                 case 10:
02236                         if (execute) sendmsg(cmd_quit);
02237                         return "quit";
02238         }
02239         return 0;
02240 }
02241 
02242 void ht_app::get_stdbounds_file(bounds *b)
02243 {
02244         if (project) {
02245                 bounds c;
02246                 get_stdbounds_tool(&c);
02247                 battlefield->getbounds(b);
02248                 b->x = 0;
02249                 b->y = 0;
02250                 b->h -= c.h;
02251         } else {
02252                 battlefield->getbounds(b);
02253                 b->x = 0;
02254                 b->y = 0;
02255         }
02256 }
02257 
02258 void ht_app::get_stdbounds_tool(bounds *b)
02259 {
02260         UINT h = MAX(size.h/4, 3);
02261         battlefield->getbounds(b);
02262         b->x = 0;
02263         b->y = b->h - h;
02264         b->h = h;
02265 }
02266 
02267 ht_window *ht_app::get_window_by_filename(char *filename)
02268 {
02269         UINT c=windows->count();
02270         for (UINT i=0; i<c; i++) {
02271                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02272 // FIXME: filename_compare (taking into account slash/backslash, and case)
02273                 if (strcmp(e->window->desc, filename) == 0) return e->window;
02274         }
02275         return NULL;
02276 }
02277 
02278 ht_window *ht_app::get_window_by_number(UINT number)
02279 {
02280         UINT c=windows->count();
02281         for (UINT i=0; i<c; i++) {
02282                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02283                 if (e->number==number) return e->window;
02284         }
02285         return NULL;
02286 }
02287 
02288 ht_window *ht_app::get_window_by_type(UINT type)
02289 {
02290         UINT c=windows->count();
02291         for (UINT i=0; i<c; i++) {
02292                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02293                 if (e->type==type) return e->window;
02294         }
02295         return NULL;
02296 }
02297 
02298 UINT ht_app::get_window_number(ht_window *window)
02299 {
02300         ht_app_window_entry *e=(ht_app_window_entry*)windows->get(get_window_listindex(window));
02301         if (e) return e->number; else return 0;
02302 }
02303 
02304 UINT ht_app::get_window_listindex(ht_window *window)
02305 {
02306         UINT c=windows->count();
02307         for (UINT i=0; i<c; i++) {
02308                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02309                 if (e->window==window) return i;
02310         }
02311         return LIST_UNDEFINED;
02312 }
02313 
02314 void ht_app::handlemsg(htmsg *msg)
02315 {
02316         switch (msg->msg) {
02317 #ifdef SYS_SUPPORT_NATIVE_CLIPBOARD
02318                 case cmd_edit_copy_native: {
02319                         int dz = sys_get_native_clipboard_data_size();
02320                         if (dz) {
02321                                 void *data = smalloc(dz);
02322                                 if (sys_read_data_from_native_clipboard(data, dz)) {
02323                                         dz = strlen((char*)data);
02324                                         clipboard_copy(SYS_NATIVE_CLIPBOARD_NAME, data, dz);
02325                                 }
02326                                 free(data);
02327                         }
02328                         break;
02329                 }
02330                 case cmd_edit_paste_native: {
02331                         int maxsize = clipboard_getsize();
02332                         byte *buf = (byte*)smalloc(maxsize);
02333                         int r = clipboard_paste(buf, maxsize);
02334                         if (r) {
02335                                 sys_write_data_to_native_clipboard(buf, r);
02336                         }
02337                         free(buf);
02338                 }
02339 #endif
02340                 case cmd_file_save: {
02341                         UINT i = get_window_listindex((ht_window*)battlefield->current);
02342                         ht_app_window_entry *e = (ht_app_window_entry*)windows->get(i);
02343                         if ((e) && (e->layer) && (e->isfile)) break;
02344                 }
02345                 case cmd_file_saveas: {
02346                         UINT i=get_window_listindex((ht_window*)battlefield->current);
02347                         ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02348                         if ((e) && (e->layer)) {
02349                                 char fn[HT_NAME_MAX];
02350                                 fn[0] = 0;
02351                                 if (file_chooser("Save as", fn, sizeof fn)) {
02352                                         int err;
02353                                         bool work = true;
02354 
02355                                         if (access(fn, F_OK) == 0) {
02356                                                 work = (confirmbox("File '%s' already exists. Overwrite ?", fn) == button_yes);
02357                                         }
02358 
02359                                         if (work) {
02360                                                 ht_file *f = new ht_file();
02361                                                 f->init(fn, FAM_WRITE, FOM_CREATE);
02362 
02363                                                 if ((err = f->get_error())) {
02364                                                         f->done();
02365                                                         delete f;
02366                                                         LOG_EX(LOG_ERROR, "error saving file %s: %s", fn, strerror(err & ~STERR_SYSTEM));
02367                                                         errorbox("error saving file %s: %s", fn, strerror(err & ~STERR_SYSTEM));
02368                                                         return;
02369                                                 }
02370 
02371                                                 e->layer->seek(0);
02372                                                 e->layer->copy_to(f);
02373 
02374                                                 ht_streamfile *old = e->layer->get_layered();
02375 
02376                                                 if (f->set_access_mode(old->get_access_mode())) {
02377                                                         e->layer->set_layered(f);
02378                                                         e->isfile = true;
02379 
02380                                                         old->done();
02381                                                         delete old;
02382 
02383                                                         char fullfn[FILENAME_MAX], *ff=fullfn;
02384                                                         if (sys_canonicalize(fullfn, fn)!=0) ff=fn;
02385                                                         e->window->settitle(ff);
02386                                                         clearmsg(msg);
02387                                                 } else errorbox("couldn't inherit access_mode from '%s' to '%s'", old->get_desc(), f->get_desc());
02388                                         }
02389                                 }
02390                         }
02391                         return;
02392                 }
02393                 case msg_kill: {
02394                         htmsg m;
02395                         ht_window *w=(ht_window*)msg->data1.ptr;
02396                         m.msg=msg_accept_close;
02397                         m.type=mt_broadcast;
02398                         m.data1.ptr=NULL;
02399                         m.data2.ptr=NULL;
02400                         w->sendmsg(&m);
02401                         if (m.msg==msg_accept_close) delete_window(w);
02402                         clearmsg(msg);
02403                         return;
02404                 }
02405         }
02406         if (msg->msg==msg_draw) {
02407                 start_timer(h0);
02408                 if (msg->type==mt_broadcast) {
02409                         ht_view *v=first;
02410                         while (v) {
02411                                 v->handlemsg(msg);
02412                                 v=v->next;
02413                         }
02414                 } else {
02415                         current->handlemsg(msg);
02416                 }
02417                 stop_timer(h0);
02418                 draw();
02419                 screen->show();
02420         } else {
02421                 ht_group::handlemsg(msg);
02422         }
02423         switch (msg->msg) {
02424                 case msg_keypressed: {
02425                         int i=0;
02426                         switch (msg->data1.integer) {
02427                                 case K_Alt_9: i++;
02428                                 case K_Alt_8: i++;
02429                                 case K_Alt_7: i++;
02430                                 case K_Alt_6: i++;
02431                                 case K_Alt_5: i++;
02432                                 case K_Alt_4: i++;
02433                                 case K_Alt_3: i++;
02434                                 case K_Alt_2: i++;
02435                                 case K_Alt_1: i++;
02436                                         focus(get_window_by_number(i));
02437                                         clearmsg(msg);
02438                                         return;
02439                                 case K_F12: i++;
02440                                 case K_F11: i++;
02441                                 case K_F10: i++;
02442                                 case K_F9: i++;
02443                                 case K_F8: i++;
02444                                 case K_F7: i++;
02445                                 case K_F6: i++;
02446                                 case K_F5: i++;
02447                                 case K_F4: i++;
02448                                 case K_F3: i++;
02449                                 case K_F2: i++;
02450                                 case K_F1:
02451                                         i++;
02452                                         htmsg m;
02453                                         m.msg=msg_funcquery;
02454                                         m.type=mt_empty;
02455                                         m.data1.integer=i;
02456                                         sendmsg(&m);
02457                                         if (m.msg==msg_retval) {
02458                                                 sendmsg(msg_funcexec, i);
02459                                                 clearmsg(msg);
02460                                                 return;
02461                                         }
02462                                         break;
02463 #if 0
02464                                 /* FIXME: experimental */
02465                                 case K_Control_F9:
02466                                         ((ht_app*)app)->create_window_term("main.exe");
02467                                         clearmsg(msg);
02468                                         return;
02469                                 case K_Alt_R: {
02470                                         char *n = "./ht.reg";
02471                                         ht_file *f = new ht_file();
02472                                         f->init(n, FAM_WRITE, FOM_CREATE);
02473 
02474                                         ht_object_stream_bin *b = new ht_object_stream_bin();
02475                                         b->init(f);
02476 
02477                                         b->putObject(registry, NULL);
02478 
02479                                         b->done();
02480                                         delete b;
02481                                         
02482                                         f->done();
02483                                         delete f;
02484 
02485                                         infobox("registry dumped to '%s'", n);
02486                                         
02487                                         clearmsg(msg);
02488                                         return;
02489                                 }
02490                                 case K_Alt_T:
02491                                         create_window_ofm("reg:/", "local:/");
02492                                         clearmsg(msg);
02493                                         return;*/
02494                                 case K_Control_A:
02495                                         create_window_help("/HT/res/info/intidx.info", "Top");
02496 //                                      create_window_help("c:/djgpp/projects/enew/res/info/ibnidx.info", "Interrupts By Number");
02497                                         dirtyview();
02498                                         clearmsg(msg);
02499                                         return;
02500 #endif
02501                                 case K_Space:
02502                                         sendmsg(cmd_popup_dialog_view_list);
02503                                         clearmsg(msg);
02504                                         return;
02505 /*                              case K_Space: {
02506                                 msgbox(0, "title", 0, align_custom, "test, baby ! aaaaaaaaaaaarghssssssssssssssssssssssssssssssssssssssssssssssss,bf\n\n"
02507 "Was willst DU Ich komm   nicht dahinter Ich zaehm dir das  Feuer      Du schenkst mir "
02508 "nur Winter Wenn du nicht bald anf„ngst mir Antwort zu geben faengt es ohne "
02509 "dich an das richtige Leben Ich hab lange gewartet bin nicht durchgeknallt "
02510 "aber wenn du jetzt nicht \n\n\ecaufspringst wirst du ohne mich alt Erklaer mir ich "
02511 "warte Wohin geht die Reise \n\n\erich kenn doch die Karte Nimm mich nicht als "
02512 "Vorwand nimm mich nicht auf die Schippe sonst kuess ich dich luftleer und "
02513 "zerbeiss dir die Lippe ich kann ohne dich leben auch wenn du nicht glaubst     \n"
02514 "da ist mehr an mir dran als was du mir raubst ");
02515                                         clearmsg(msg);
02516                                         break;
02517                                 }*/
02518                         }
02519                         break;
02520                 }
02521                 case cmd_about:
02522                         msgbox(btmask_ok, "About "ht_name, 0, align_custom, "\n\ec"ht_name" "ht_version" ("HT_SYS_NAME")\n\n\el"ht_copyright1"\n"ht_copyright2"\n\nThis program is GPL'd. See Help for more information.");
02523                         break;
02524                 case msg_funcexec:
02525                         if (func(msg->data1.integer, 1)) {
02526                                 clearmsg(msg);
02527                                 return;
02528                         }
02529                         break;
02530                 case msg_funcquery: {
02531                         char *s=func(msg->data1.integer, 0);
02532                         if (s) {
02533                                 msg->msg=msg_retval;
02534                                 msg->data1.str=s;
02535                         } else clearmsg(msg);
02536                         return;
02537                 }
02538                 case cmd_file_exec_cmd: {
02539                         char cmd[HT_NAME_MAX];
02540                         cmd[0] = 0;
02541                         if (inputbox("execute shell command (experimental!)",
02542                         (sys_get_caps() & SYSCAP_NONBLOCKING_IPC) ? "command"
02543                         : "non-interactive (!) command",
02544                         cmd, sizeof cmd, HISTATOM_FILE) == button_ok) {
02545                                 if (cmd[0]) create_window_term(cmd);
02546                         }
02547                         clearmsg(msg);
02548                         return;
02549                 }
02550                 case cmd_file_extend: {
02551                         ht_streamfile *f = (ht_streamfile *)msg->data1.ptr;
02552                         UINT s = (UINT)msg->data2.integer;
02553                         // don't ask. only for truncates
02554 //                      if (confirmbox("really extend %s to offset %08x/%d ?", f->get_filename(), s, s) == button_ok) {
02555                                 int oam = f->get_access_mode();
02556                                 if (!(oam & FAM_WRITE)) f->set_access_mode(oam | FAM_WRITE);
02557                                 int e = f->extend(s);
02558                                 if (!(oam & FAM_WRITE)) f->set_access_mode(oam);
02559                                 if (e) errorbox("couldn't extend file to offset %08x/%d: %s", s, s, strerror(e));
02560 //                      }
02561                         clearmsg(msg);
02562                         return;
02563                 }
02564                 case cmd_file_truncate: {
02565                         ht_streamfile *f = (ht_streamfile *)msg->data1.ptr;
02566                         UINT s = (UINT)msg->data2.integer;
02567 /*               ht_app_window_entry *e;
02568                         if ((e=windows->enum_first())) {
02569                                 do {
02570                                         if ((e->type==AWT_FILE) && ((ht_streamfile*)e->data==f)) {
02571                                                 check_collide();
02572                                         }
02573                                 } while ((e=windows->enum_first()));
02574                         }*/
02575                         if (confirmbox("really truncate %s at offset %08x/%d ?", f->get_filename(), s, s) == button_ok) {
02576                                 f->truncate(s);
02577                         }
02578                         clearmsg(msg);
02579                         return;
02580                 }
02581                 case cmd_quit:
02582                         if (accept_close_all_windows()) {
02583                                 LOG("terminating...");
02584                                 exit_program = true;
02585                                 sendmsg(cmd_project_close);
02586                                 clearmsg(msg);
02587                         }
02588                         return;
02589                 case cmd_file_open: {
02590                         char *name;
02591                         UINT mode;
02592                         if (file_open_dialog(&name, &mode)) {
02593                                 if (name[0]) create_window_file(name, mode, true);
02594                                 free(name);
02595                         }
02596                         clearmsg(msg);
02597                         return;
02598                 }
02599                 case cmd_file_new: {
02600                         bounds b;
02601                         get_stdbounds_file(&b);
02602                         
02603                         UINT mode;
02604                         
02605                         if (file_new_dialog(&mode)) {
02606                                 ht_mem_file *mfile=new ht_mem_file();
02607                                 mfile->init();
02608                                 switch (mode) {
02609                                         case FOM_TEXT: {
02610                                                 ht_syntax_lexer *lexer = NULL;
02611                         
02612                                                 ht_ltextfile *tfile = new ht_ltextfile();
02613                                                 tfile->init(mfile, true, lexer);
02614                         
02615                                                 ht_layer_textfile *file = new ht_layer_textfile();
02616                                                 file->init(tfile, true);
02617                                 
02618                                                 create_window_file_text(&b, file, "Untitled", false/* because mem_file is underlying, not ht_file, etc.*/);
02619                                                 break;
02620                                         }
02621                                         case FOM_BIN: {
02622                                                 ht_streamfile_modifier *modfile = new ht_streamfile_modifier();
02623                                                 modfile->init(mfile, true, 8*1024);
02624 
02625                                                 ht_layer_streamfile *file = new ht_layer_streamfile();
02626                                                 file->init(modfile, true);
02627 
02628                                                 ht_window *w = create_window_file_bin(&b, file, "Untitled", false);
02629                                                 htmsg m;
02630                                                 m.msg = cmd_file_resize;
02631                                                 m.type = mt_empty;
02632                                                 w->sendmsg(&m);
02633                                         }
02634                                 }
02635                         }
02636                         clearmsg(msg);
02637                         return;
02638                 }
02639                 case cmd_edit_show_clipboard: {
02640                         create_window_clipboard();
02641                         clearmsg(msg);
02642                         return;
02643                 }
02644                 case cmd_edit_clear_clipboard: {
02645                         if (confirmbox("Do you really want to delete the clipboard ?")==button_ok) {
02646                                 clipboard_clear();
02647                         }
02648                         clearmsg(msg);
02649                         return;
02650                 }
02651                 case cmd_edit_paste_into_file: {
02652                         char filename[HT_NAME_MAX];
02653                         filename[0] = 0;
02654                         if (file_chooser("clipboard - paste into file", filename, sizeof filename)) {
02655                                 ht_file *f = new ht_file();
02656                                 f->init(filename, FAM_WRITE, FOM_CREATE);
02657                                 if (!f->get_error()) {
02658                                         clipboard_paste(f, 0);
02659                                 } else errorbox("can't open file '%s'", filename);
02660                                 f->done();
02661                                 delete f;
02662                         }
02663                         clearmsg(msg);
02664                         return;
02665                 }
02666                 case cmd_edit_copy_from_file: {
02667                         char filename[HT_NAME_MAX];
02668                         filename[0] = 0;
02669                         if (file_chooser("clipboard - copy from file", filename, sizeof filename)) {
02670                                 char desc[HT_NAME_MAX+5];
02671                                 ht_file *f = new ht_file();
02672                                 f->init(filename, FAM_READ, FOM_EXISTS);
02673                                 if (!f->get_error()) {
02674                                         ht_snprintf(desc, sizeof desc, "file %s", f->get_filename());
02675                                         clipboard_copy(desc, f, 0, f->get_size());
02676                                 } else errorbox("can't open file '%s'", filename);
02677                                 f->done();
02678                                 delete f;
02679                         }
02680                         clearmsg(msg);
02681                         return;
02682                 }
02683                 case cmd_project_open: {
02684                         char fn[HT_NAME_MAX];
02685                         fn[0] = 0;
02686                         if (file_chooser("Open project", fn, sizeof fn)) {
02687                                 sendmsg(cmd_project_close);
02688                                 project_opencreate(fn);
02689                         }
02690                         clearmsg(msg);
02691                         return;
02692                 }
02693                 case cmd_project_close: {
02694                         if (project) {
02695                                 char *fn = ((ht_project*)project)->get_filename();
02696                                 LOG("%s: saving project", fn);
02697                                 save_fileconfig(fn, ht_projectconfig_magic, ht_projectconfig_fileversion, file_project_store_fcfg_func, NULL);
02698                                 LOG("%s: done", fn);
02699                                 ((ht_project*)project)->destroy();
02700                                 delete ((ht_project*)project);
02701                                 project = NULL;
02702                                 htmsg m;
02703                                 m.type = mt_broadcast;
02704                                 m.msg = msg_project_changed;
02705                                 sendmsg(&m);
02706                         }
02707                         clearmsg(msg);
02708                         return;
02709                 }
02710                 case cmd_window_close:
02711                         if (battlefield->current) sendmsg(msg_kill, battlefield->current);
02712                         clearmsg(msg);
02713                         return;
02714                 case cmd_popup_dialog_eval: {
02715                         eval_dialog();
02716                         clearmsg(msg);
02717                         return;
02718                 }
02719                 case cmd_popup_dialog_view_list: {
02720                         ht_view *v = popup_view_list("select mode");
02721                         if (v) focus(v);
02722                         clearmsg(msg);
02723                         return;
02724                 }
02725                 case cmd_popup_dialog_window_list: {
02726                         ht_window *w = popup_window_list("select window");
02727                         if (w) focus(w);
02728                         clearmsg(msg);
02729                         return;
02730                 }
02731                 case cmd_popup_dialog_info_loader: {
02732                         char file[256];
02733                         file[0] = 0;
02734                         if (inputbox("open info file", "filename", file, sizeof file, HISTATOM_FILE) == button_ok) {
02735                                 char node[256];
02736                                 strcpy(node, "Top");
02737                                 if (inputbox("open info file", "nodename", node, sizeof node, HISTATOM_GOTO) == button_ok) {
02738                                         create_window_help(file, node);
02739                                         dirtyview();
02740                                 }
02741                         }
02742                         clearmsg(msg);
02743                         return;
02744                 }
02745                 case cmd_popup_window_log:
02746                         create_window_log();
02747                         clearmsg(msg);
02748                         return;
02749                 case cmd_popup_window_project:
02750                         create_window_project();
02751                         clearmsg(msg);
02752                         return;
02753                 case cmd_popup_window_options:
02754                         create_window_ofm("reg:/", NULL);
02755                         clearmsg(msg);
02756                         return;
02757                 case cmd_popup_window_help:
02758                         create_window_help(MAGIC_HT_HELP, "Top");
02759                         clearmsg(msg);
02760                         return;
02761                 case msg_project_changed: {
02762                         ht_window *w = ((ht_app*)app)->get_window_by_type(AWT_PROJECT);
02763                         if (w) w->sendmsg(msg_dirtyview);
02764                         app->sendmsg(msg_draw);
02765                         return;
02766                 }
02767         }
02768 }
02769 
02770 void    ht_app::insert_window(ht_window *window, UINT type, bool minimized, bool isfile, ht_layer_streamfile *layer)
02771 {
02772         UINT n=find_free_window_number();
02773         ht_app_window_entry *e=new ht_app_window_entry(window, n, type, minimized, isfile, layer);
02774         windows->insert(e);
02775         window->setnumber(n);
02776         battlefield->insert(window);
02777         focus(window);
02778 }
02779 
02780 int ht_app::load(ht_object_stream *f)
02781 {
02782         ht_registry *temp;
02783         
02784         if (!(temp=(ht_registry*)f->getObject(NULL))) return 1;
02785 
02786         if (registry) {
02787                 registry->done();
02788                 delete registry;
02789         }
02790         registry=temp;
02791         
02792         load_history(f);
02793         
02794         htmsg m;
02795         m.msg=msg_config_changed;
02796         m.type=mt_broadcast;
02797         app->sendmsg(&m);
02798         return f->get_error();
02799 }
02800 
02801 OBJECT_ID ht_app::object_id() const
02802 {
02803         return ATOM_HT_APP;
02804 }
02805 
02806 static int my_compare_func(const char *a, const char *b)
02807 {
02808         return strcmp(a, b);
02809 }
02810 
02811 ht_view *ht_app::popup_view_list(char *dialog_title)
02812 {
02813         if (!battlefield->current) return NULL;
02814         bounds b, c;
02815         getbounds(&b);
02816         b.x=b.w/4;
02817         b.y=b.h/4;
02818         b.w/=2;
02819         b.h/=2;
02820         ht_dialog *dialog=new ht_dialog();
02821         dialog->init(&b, dialog_title, FS_KILLER | FS_TITLE | FS_MOVE);
02822 
02823         /* create listbox */
02824         c=b;
02825         c.x=0;
02826         c.y=0;
02827         c.w-=2;
02828         c.h-=2;
02829         ht_text_listbox *listbox=new ht_text_listbox();
02830         listbox->init(&c, 1, 0, LISTBOX_NORMAL);
02831 
02832         /* insert all browsable views */
02833         ht_clist *structure=new ht_clist();
02834         ((ht_clist*)structure)->init();
02835         int index=0;
02836 /*      int count=*/popup_view_list_dump(battlefield->current, listbox, structure, 0, &index, battlefield->getselected());
02837 /* and seek to the currently selected one */
02838         listbox->update();
02839         listbox->gotoItemByPosition(index);
02840 
02841         ht_text_listbox_sort_order so[1];
02842         so[0].col = 0;
02843         so[0].compare_func = my_compare_func;
02844 /*      so[1].col = 1;
02845         so[1].compare_func = my_compare_func;*/
02846         
02847 //      listbox->sort(1, so);
02848 
02849         dialog->insert(listbox);
02850         dialog->setpalette(palkey_generic_special);
02851 
02852         ht_view *result = NULL;
02853         if (dialog->run(false)) {
02854                 ht_listbox_data data;
02855                 listbox->databuf_get(&data, sizeof data);
02856                 ht_data_ptr *p=(ht_data_ptr*)structure->get(listbox->getID(data.cursor_ptr));
02857                 if (p) result = (ht_view*)p->value;
02858         }
02859 
02860         structure->destroy();
02861         delete structure;
02862 
02863         dialog->done();
02864         delete dialog;
02865         return result;
02866 }
02867 
02868 int ht_app::popup_view_list_dump(ht_view *view, ht_text_listbox *listbox, ht_list *structure, int depth, int *currenti, ht_view *currentv)
02869 {
02870         if (!view) return 0;
02871         char str[256];  /* secure */
02872         char *s=str;
02873         if (!(view->options & VO_BROWSABLE)) {
02874                 depth--;
02875         }
02876 
02877         for (int i=0; i<depth; i++) { *(s++)=' ';*(s++)=' '; }
02878         *s=0;
02879 
02880         int c=view->childcount();
02881         int count=0;
02882         for (int i=0; i<c; i++) {
02883                 ht_view *v=view->getfirstchild();
02884                 while (v) {
02885                         if (v->browse_idx==i) break;
02886                         v=v->next;
02887                 }
02888                 if (!v) return count;
02889 
02890 // FIXME: "viewergroup": dirty hack !!!
02891                 if ((v->desc) && (strcmp(v->desc, VIEWERGROUP_NAME)) && (v->options & VO_BROWSABLE)) {
02892                         ht_snprintf(s, sizeof str-(s-str), "- %s", v->desc);
02893                         structure->insert(new ht_data_ptr(v));
02894                         if (v==currentv)
02895                                 *currenti=structure->count()-1;
02896                         listbox->insert_str(structure->count()-1, str);
02897                         count++;
02898                 }
02899                 count+=popup_view_list_dump(v, listbox, structure, depth+1, currenti, currentv);
02900         }
02901         return count;
02902 }
02903 
02904 ht_window *ht_app::popup_window_list(char *dialog_title)
02905 {
02906         bounds b, c;
02907         getbounds(&b);
02908         c=b;
02909         b.w=b.w*2/3;
02910         b.h=b.h*2/3;
02911         b.x=(c.w-b.w)/2;
02912         b.y=(c.h-b.h)/2;
02913         ht_dialog *dialog=new ht_dialog();
02914         dialog->init(&b, dialog_title, FS_KILLER | FS_TITLE | FS_MOVE);
02915 
02916         /* create listbox */
02917         c=b;
02918         c.x=0;
02919         c.y=0;
02920         c.w-=2;
02921         c.h-=2;
02922         ht_text_listbox *listbox=new ht_itext_listbox();
02923         listbox->init(&c, 2, 1);
02924 
02925         UINT vc=windows->count();
02926         for (UINT i=0; i<vc; i++) {
02927                 ht_app_window_entry *e=(ht_app_window_entry*)windows->get(i);
02928                 char l[16];     /* secure */
02929                 ht_snprintf(l, sizeof l, " %2d", e->number);
02930                 listbox->insert_str(e->number, l, e->window->desc);
02931         }
02932         listbox->update();
02933         if (battlefield->current) listbox->gotoItemByPosition(battlefield->current->getnumber()-1);
02934 
02935         dialog->insert(listbox);
02936         dialog->setpalette(palkey_generic_special);
02937 
02938         ht_window *result = NULL;
02939         if (dialog->run(false)) {
02940                 ht_listbox_data data;
02941                 listbox->databuf_get(&data, sizeof data);
02942                 result = get_window_by_number(listbox->getID(data.cursor_ptr));
02943         }
02944         dialog->done();
02945         delete dialog;
02946         return result;
02947 }
02948 
02949 void ht_app::project_opencreate(char *filename)
02950 {
02951         char fn[HT_NAME_MAX];
02952         char cwd[HT_NAME_MAX];
02953         getcwd(cwd, sizeof cwd);
02954         if (sys_common_canonicalize(fn, filename, cwd, sys_is_path_delim) != 0) {
02955                 LOG("%s: invalid filename", filename);
02956                 return;
02957         }
02958         char *suf = sys_filename_suffix(fn);
02959         /* append HT project file suffix if not already there */
02960         if (!(suf && (strcmp(suf, HT_PROJECT_CONFIG_SUFFIX+1)==0))) {
02961                 strcat(fn, HT_PROJECT_CONFIG_SUFFIX);
02962         }
02963 
02964         void *old_project = project;
02965         project = NULL;
02966         int einfo;
02967         LOG("%s: loading project file...", fn);
02968         bool error = true;
02969         loadstore_result lsr = load_fileconfig(fn, ht_projectconfig_magic, ht_projectconfig_fileversion, file_project_load_fcfg_func, NULL, &einfo);
02970         if (lsr == LS_ERROR_CORRUPTED) {
02971                 LOG_EX(LOG_ERROR, "%s: error in line %d", fn, einfo);
02972                 errorbox("%s: error in line %d", fn,  einfo);
02973         } else if (lsr == LS_ERROR_NOT_FOUND) {
02974                 if (confirmbox("%s: no such project.\nDo you want to create this project ?", fn) == button_yes) {
02975                         project = new ht_project();
02976                         ((ht_project*)project)->init(fn);
02977                         LOG("%s: new project created", fn);
02978                         error = false;
02979                 }
02980         } else if (lsr != LS_OK) {
02981                 LOG_EX(LOG_ERROR, "%s: some error", fn);
02982                 errorbox("%s: some error", fn);
02983         } else {
02984                 LOG("%s: done", fn);
02985                 error = false;
02986         }
02987         if (error) {
02988                 // FIXME: free project ???
02989                 project = old_project;
02990         } else {
02991                 htmsg m;
02992                 m.type = mt_broadcast;
02993                 m.msg = msg_project_changed;
02994                 sendmsg(&m);
02995                 create_window_project();
02996         }
02997 }
02998 
02999 int ht_app::run(bool modal)
03000 {
03001         sendmsg(msg_draw, 0);
03002         while (!exit_program) {
03003                 if (ht_keypressed()) {
03004                         int k = ht_getkey();
03005                         sendmsg(msg_keypressed, k);
03006                         sendmsg(msg_draw);
03007                 }
03008                 ht_queued_msg *q;
03009                 while ((q = dequeuemsg())) {
03010                         htmsg m = q->msg;
03011                         q->target->sendmsg(&m);
03012                         sendmsg(msg_draw);
03013                         delete q;
03014                 }
03015                 do_idle();
03016         }
03017         return 0;
03018 }
03019 
03020 void ht_app::store(ht_object_stream *f)
03021 {
03022         f->putObject(registry, NULL);
03023 
03024         store_history(f);
03025 }
03026 
03027 /*
03028  *      CLASS ht_vstate_history_entry
03029  */
03030 
03031 ht_vstate_history_entry::ht_vstate_history_entry(Object *Data, ht_view *View)
03032 {
03033         data = Data;
03034         view = View;
03035 }
03036 
03037 ht_vstate_history_entry::~ht_vstate_history_entry()
03038 {
03039         data->done();
03040         delete data;
03041 }
03042 
03043 /*
03044  *      CLASS ht_file_window
03045  */
03046 
03047 void ht_file_window::init(bounds *b, char *desc, UINT framestyle, UINT number, ht_streamfile *f)
03048 {
03049         ht_window::init(b, desc, framestyle, number);
03050         file = f;
03051         vstate_history = new ht_clist();
03052         ((ht_clist*)vstate_history)->init();
03053         vstate_history_pos = 0;
03054 }
03055 
03056 void ht_file_window::done()
03057 {
03058         vstate_history->destroy();
03059         delete vstate_history;
03060         ht_window::done();
03061 }
03062 
03063 void ht_file_window::add_vstate_history(ht_vstate_history_entry *e)
03064 {
03065         int c = vstate_history->count();
03066         if (c > vstate_history_pos) {
03067                 vstate_history->del_multiple(vstate_history_pos, c-vstate_history_pos);
03068         }
03069         vstate_history->insert(e);
03070         vstate_history_pos++;
03071 }
03072 
03073 void ht_file_window::handlemsg(htmsg *msg)
03074 {
03075         switch (msg->msg) {
03076                 case cmd_vstate_restore: {
03077                         if (vstate_history_pos) {
03078                                 vstate_history_pos--;
03079                                 ht_vstate_history_entry *e = (ht_vstate_history_entry*)
03080                                         vstate_history->get(vstate_history_pos);
03081                                 htmsg m;
03082                                 m.msg = msg_vstate_restore;
03083                                 m.type = mt_empty;
03084                                 m.data1.ptr = e->data;
03085                                 e->view->sendmsg(&m);
03086                                 focus(e->view);
03087                         }
03088                         clearmsg(msg);
03089                         return;
03090                 }
03091                 case msg_vstate_save: {
03092                         Object *data = (Object*)msg->data1.ptr;
03093                         ht_view *view = (ht_view*)msg->data2.ptr;
03094                         add_vstate_history(new ht_vstate_history_entry(data, view));
03095                         break;
03096                 }
03097                 case msg_accept_close: if (file) {
03098                         bool modified=false;
03099                         if (file->get_filename() != NULL) {
03100                                 file->cntl(FCNTL_MODS_IS_DIRTY, 0, file->get_size(), &modified);
03101                         } else {
03102                                 modified = true;
03103                         }
03104                         if (modified) {
03105                                 char q[1024];
03106                                 if (file->get_filename()) {
03107                                         ht_snprintf(q, sizeof q, "file %s has been modified, save ?", file->get_filename());
03108                                 } else {
03109                                         ht_snprintf(q, sizeof q, "untitled file has been modified, save ?");
03110                                 }
03111                                 switch (msgbox(btmask_yes+btmask_no+btmask_cancel, "confirmation", 0, align_center, q)) {
03112                                         case button_yes: {
03113                                                 app->focus(this);
03114                                                 htmsg msg;
03115                                                 msg.msg = cmd_file_save;
03116                                                 msg.type = mt_empty;
03117                                                 app->sendmsg(&msg);
03118                                                 if ((UINT)msg.msg != cmd_file_save) break;
03119                                         }
03120                                         case button_cancel:
03121                                                 clearmsg(msg);
03122                                                 return;
03123                                 }
03124                         }
03125 
03126                         // flush so that cmd_analyser_save get correct mtime
03127                         file->cntl(FCNTL_FLUSH_STAT);
03128 
03129                         Analyser *a;
03130                         htmsg m;
03131                         m.msg=msg_get_analyser;
03132                         m.type=mt_broadcast;
03133                         m.data1.ptr=NULL;
03134                         sendmsg(&m);
03135                         a = (Analyser*)m.data1.ptr;
03136                         if ((m.msg==msg_retval) && (a) && (a->isDirty())) {
03137                                 sendmsg(cmd_analyser_save);
03138                         }
03139                 }
03140                 break;
03141                 case cmd_analyser_save: {
03142                         char filename[1024];
03143                         ht_snprintf(filename, sizeof filename, "%s%s", file->get_filename(), HT_FILE_CONFIG_SUFFIX);
03144                         LOG("%s: saving config", filename);
03145                         save_fileconfig(filename, ht_fileconfig_magic, ht_fileconfig_fileversion, file_window_store_fcfg_func, this);
03146                         LOG("%s: done", filename);
03147                         clearmsg(msg);
03148                         break;
03149                 }
03150         }
03151         ht_window::handlemsg(msg);
03152         switch (msg->msg) {
03153                 case msg_keypressed:
03154                         switch (msg->data1.integer) {
03155                                 case K_Alt_Backspace:
03156                                 case K_Backspace: {
03157                                         sendmsg(cmd_vstate_restore);
03158                                         clearmsg(msg);
03159                                         return;
03160                                 }
03161                         }
03162                         break;
03163         }
03164 }
03165 
03166 
03167 
03168 ht_list *build_vfs_list()
03169 {
03170 /* build vfs list */
03171         ht_clist *vfslist=new ht_clist();
03172         vfslist->init();
03173 
03174 #if 1
03175         /* LocalFS */
03176         LocalFs *localfs = new LocalFs();
03177         localfs->init();
03178 
03179         /* RegistryFS */
03180         RegistryFs *registryfs = new RegistryFs();
03181         registryfs->init();
03182 
03183         vfslist->insert(localfs);
03184         vfslist->insert(registryfs);
03185 #else
03186         /* file_vfs */
03187         ht_file_vfs *file_vfs = new ht_file_vfs();
03188         file_vfs->init();
03189 
03190         /* reg_vfs */
03191         ht_reg_vfs *reg_vfs = new ht_reg_vfs();
03192         reg_vfs->init();
03193 
03194         vfslist->insert(file_vfs);
03195         vfslist->insert(reg_vfs);
03196 #endif
03197 
03198 
03199         return vfslist;
03200 }
03201 
03202 BUILDER(ATOM_HT_APP, ht_app);
03203 BUILDER(ATOM_HT_PROJECT, ht_project);
03204 BUILDER(ATOM_HT_PROJECT_ITEM, ht_project_item);
03205 
03206 /*
03207  *      INIT
03208  */
03209 
03210 bool init_app()
03211 {
03212         bounds b;
03213         screen = new screendrawbuf(ht_name" "ht_version);
03214 
03215         loglines = new ht_log();
03216         loglines->init();
03217 
03218         virtual_fs_list = build_vfs_list();
03219 
03220         project = NULL;
03221 
03222         b.x = 0;
03223         b.y = 0;
03224         b.w = screen->size.w;
03225         b.h = screen->size.h;
03226         app = new ht_app();
03227         ((ht_app*)app)->init(&b);
03228         baseview = app;
03229 
03230         app_memory_reserve = malloc(16384); // malloc, not smalloc
03231         out_of_memory_func = &app_out_of_memory_proc;
03232 
03233         REGISTER(ATOM_HT_APP, ht_app);
03234         REGISTER(ATOM_HT_PROJECT, ht_project);
03235         REGISTER(ATOM_HT_PROJECT_ITEM, ht_project_item);
03236         register_atom(ATOM_COMPARE_KEYS_PROJECT_ITEM, (void*)compare_keys_project_item);
03237 
03238         return true;
03239 }
03240 
03241 /*
03242  *      DONE
03243  */
03244 
03245 void done_app()
03246 {
03247         UNREGISTER(ATOM_HT_APP, ht_app);
03248         UNREGISTER(ATOM_HT_PROJECT, ht_project);
03249         UNREGISTER(ATOM_HT_PROJECT_ITEM, ht_project_item);
03250         unregister_atom(ATOM_COMPARE_KEYS_PROJECT_ITEM);
03251         
03252         out_of_memory_func = &out_of_memory;
03253         if (app_memory_reserve) free(app_memory_reserve);
03254 
03255         if (project) {
03256                 ((ht_project*)project)->destroy();
03257                 delete ((ht_project*)project);
03258         }
03259 
03260         virtual_fs_list->destroy();
03261         delete virtual_fs_list;
03262 
03263         loglines->destroy();
03264         delete loglines;
03265 
03266         if (app) {
03267                 app->done();
03268                 delete app;
03269         }
03270         
03271         if (screen) delete screen;
03272 }
03273 

Generated on Fri May 7 21:15:31 2004 by doxygen 1.3.5