/*

    GEO, Postgres GIS (Geografic Information System) frontend

    Copyright (C) 1991  TNO Institute for Perception, The Netherlands
			Written by: Tom Vijlbrief

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


Note that parts of this distribution are taken from the ET++
distribution. See the et2.2/ subdirectories for details.

===============================================================================
Tom Vijlbrief
TNO Institute for Perception		Phone: +31 34 63 562 11
P.O. Box 23				Fax:   +31 34 63 539 77
3769 ZG  Soesterberg			E-mail: tom@izf.tno.nl
The Netherlands				or: uunet!hp4nl.nluug.nl!tnosoes!tom
===============================================================================

*/

static char *sccs_id= (sccs_id, "@(#)QueryDialog.c	3.12 7/28/92");

#include	"Class.h"
#ifdef ET25
#include	"Stream.h"
#endif
#include	"Geo.h"
#include	"IdDictionary.h"
#include	"ObjList.h"
#include	"Window.h"
#include	"Dialog.h"
#include	"DialogItems.h"
#include	"BorderItems.h"
#include	"RegularExp.h"
#include	"Menu.h"
#include	"Scroller.h"
#include	"Document.h"
#include	"ImageItem.h"
#include	"ByteArray.h"
#include	"Alert.h"
#include	"Filler.h"
#ifdef EXP
#include	"CheapText.h"
#endif

#include	"Composer.h"
#include	"QueryDialog.h"
#include	"GQuery.h"
#include	"TableDialog.h"
#include	"Quel.h"
#include	"IconShape.h"
#include	"OverView.h"
#include	"ClassManager.h"
#include	"Query.h"
#include	"QuelInfo.h"

#ifdef ET23
inline void AllWait(bool) {}
#else
#endif

extern bool	GEOBROWSE;


char *Expand(char *s, int len= 20)
{
  const int	MaxLen= 100;
  static char	ret[MaxLen+1];
  char		*p;

  if (len > MaxLen)
	len= MaxLen;
  for (p= ret; *s; p++)
	*p= *s++;
  while (p-ret < len)
	*p++= ' ';
  *p= '\0';
  return ret;
}



class ChangeImageItem: public ImageItem {
public:
    MetaDef(ChangeImageItem);
    ChangeImageItem( Bitmap* b ) : (b)
        { }
    void ChangeBitmap( Bitmap* );
    Bitmap *GetBitmap()
        { return bmp; }
};

MetaImpl0(ChangeImageItem);

void ChangeImageItem::ChangeBitmap(Bitmap *newbmp)
{
    bmp = newbmp;
    ForceRedraw();
}


Bitmap *QueryDialog::GetIconBitmap()
{
  return GetInfo()->GetBitmapInfo(cur_icon_no)->GetBitmap();
}


static const int cIdChangeTable	= cIdFirstUser + 0,
		 cIdChangeName	= cIdFirstUser + 1,
		 cIdShowTable	= cIdFirstUser + 2,
		 cIdChangeDB	= cIdFirstUser + 3,
		 cIdShowOnMap	= cIdFirstUser + 4,
		 cIdChangeIcon	= cIdFirstUser + 5,
		 cIdChangeColor	= cIdFirstUser + 6,
		 cIdPreview	= cIdFirstUser + 7,
		 cIdCompose	= cIdFirstUser + 8,
		 cIdShowAttr	= cIdFirstUser + 9,
		 cIdEpoch	= cIdFirstUser + 10,
		 cIdRefresh	= cIdFirstUser + 11,
		 cIdChangeWidth	= cIdFirstUser + 12,
		 cIdAttrLabel	= cIdFirstUser + 13,
		 cIdDontPick	= cIdFirstUser + 14,
		 cIdMetaRefresh	= cIdFirstUser + 15,
		 cIdColOverrule = cIdFirstUser + 16,
		 cIdAdd		= cIdFirstUser + 17,
		 cIdTransparent	= cIdFirstUser + 18,
		 cIdLabels	= cIdFirstUser + 19,
		 cIdColors	= cIdFirstUser + 20,
		 cIdShowField	= cIdFirstUser + 100;

static const int MaxSF= 24;

static const char NoField[]= "No Field         ";


MetaImpl(QueryDialog,(
TP(q),TP(query_name),T(query_name_changed),
TP(table_name_s),TP(database_name_s),TP(datab_pu),TP(table_pu),
TP(icon_pu),TP(color_pu),TP(width_pu),T(cur_color_no),
TP(table_menu),TP(icon_menu),TP(color_menu),TP(database_menu),TP(width_menu),
TP(show_on_map),TP(preview_but),T(cancelled),
TP(t),TP(cv),T(cur_icon_no),T(changed_doc),
TVP(show_field,nfields),TVP(show_label,nfields),
TVP(show_attr,nfields),TVP(attr_types,nfields),T(nfields),T(n_showfields),
TP(title),TP(where_s),T(has_dyn),T(has_loc),T(has_pline),0));

QueryDialog::QueryDialog(byte *qt, GQuery *query)
#ifdef ET25
	: ((char *)qt, eWinFixed)
#else
	: ((char *)qt, eBWinFixed)
#endif
{
  q= query;
  t= 0;
  title= qt;
}

QueryDialog::~QueryDialog()
{
  if (IsOpen())
    Close();
    
  for (int i= 0; i < MaxSF; i++) {
    SafeDelete(show_attr[i]);
    SafeDelete(attr_types[i]);
  }
  SafeDelete(show_field);
  SafeDelete(show_attr);
  SafeDelete(attr_types);
  SafeDelete(show_label);
  SafeDelete(where_s);
  SafeDelete(cv);

  if (active_ed) {
    active_ed->FreeAll();
    delete active_ed;
  }
  LooseFree();
  SafeDelete(loose_ed);

  SafeDelete(t);
}


void QueryDialog::ActiveAdd(Object *o)
{
  if (!active_ed)
    active_ed= new Set;
  active_ed->Add(o);
}

void QueryDialog::LooseAdd(Object *o)
{
  if (!loose_ed)
    loose_ed= new Set;
  if (! active_ed->RemovePtr(o))
    abort();
  loose_ed->Add(o);
}


void QueryDialog::LooseFree()
{
  if (loose_ed)
    loose_ed->FreeAll();
}



void QueryDialog::ShowIt()
{
#ifdef ET25
  ShowUnderMouse();
#else
  if (GEOBROWSE)
    Show();
  else
    ShowOnWindow(GetDrawView()->GetWindow());
#endif
}


class MapView * QueryDialog::GetDrawView()
{
  return q->GetDrawView();
}


int QueryDialog::NrTuples()
{
  return q->NrTuples();
}


bool QueryDialog::IsManual()
{
  return cv && cv->IsManual() && cv->IsActive();
}


void QueryDialog::FetchQuery()
{
  q->ForceLoad();
  ObjList *oc= q->GetCol(TRUE, TRUE);
  if (GEOBROWSE)
	return;
  if (preview_but->GetValue())
	DoPreview(oc);
  else if (ShowOnMap()) {
  	MapView *dv= q->GetDrawView();
	if (inval_rect == gRect0)
  	  dv->ForceRedraw();
	else {
	  dv->InvalidateRect(inval_rect);
	  inval_rect= gRect0;
	}
  	dv->UpdateEvent();
  }
}


#ifdef ET25
OStream &QueryDialog::Save(OStream &o)
#else
ostream &QueryDialog::Save(ostream &o)
#endif
{
    o << q NL;
    // o << query_name NL;
    SaveETI(o, query_name);
#ifdef ET25
    o.PrintString(table_name_s ? table_name_s: "");
    o NL;
    o.PrintString(database_name_s);
#else
    PrintString(o, table_name_s ? table_name_s: "");
    o NL;
    PrintString(o, database_name_s);
#endif
    o NL;
    o << cur_color_no NL;
    o << show_on_map->GetValue() NL;
    o << epoch->GetValue() NL;
    o << dont_refresh->GetValue() NL;

    o << col_overrule_but->GetValue() NL;
    o << dont_pick->GetValue() NL;

    o << attr_label->GetValue() NL;
    o << trans_label->GetValue() NL;
    o << cur_icon_no NL;
    o << cur_width_no NL;
    if (!q->IsEmpty()) {
	o << nfields NL;
	for (int i= 0; i < nfields; i++) {
#ifdef ET25
	  o.PrintString(show_attr[i]); o NL;
	  o.PrintString(attr_types[i]); o NL;
#else
	  PrintString(o, show_attr[i]); o NL;
	  PrintString(o, attr_types[i]); o NL;
#endif
	}

	for (i= 0; i < nfields; i++)
	  o << show_field[i]->GetValue() NL;
    }

    bool has_cv= cv != 0;
    o << has_cv NL;
    if (has_cv) {
      cv->Save(o);
    }

    return o;
}


#ifdef ET25
static void SetPU(PopupButton *p, Menu *m, char *s)
{
  Collection *c= m->GetCollection();
  Iter next(c->MakeIterator());
  VObject *o;

  while(o= (VObject*) next()) {
    if (strcmp(o->AsString(), s) == 0) {
      m->SetSelectedItem(o->GetId());
      return;
    }
  }
}
#else
static void SetPU(PopupItem *p, Menu *m, char *s)
{
  Collection *c= m->GetCollection();
  Iter next(c->MakeIterator());
  VObject *o;

  while(o= (VObject*) next()) {
    if (strcmp(o->AsString(), s) == 0) {
      p->SetSelectedItem(o->GetId());
      return;
    }
  }
}
#endif


#ifdef ET25
IStream &QueryDialog::Load(IStream &i)
#else
istream &QueryDialog::Load(istream &i)
#endif
{
    extern int	geo_version;

    i >> q;

    LoadETI(i, query_name);
    SafeDelete(table_name_s);
#ifdef ET25
    i.ReadString(&table_name_s);
#else
    ReadString(i, &table_name_s);
#endif
    if (! table_name_s[0])
      SafeDelete(table_name_s);
    SafeDelete(database_name_s);
#ifdef ET25
    i.ReadString(&database_name_s);
#else
    ReadString(i, &database_name_s);
#endif
    SetDb(database_name_s);
    SetPU(datab_pu, database_menu, database_name_s);
    i >> cur_color_no;
#ifdef ET25
    color_menu->SetSelectedItem(cur_color_no);
#else
    color_pu->SetSelectedItem(cur_color_no);
#endif

    bool b;
#ifdef ET25
    i >> Bool(b); show_on_map->SetValue(b);
    i >> Bool(b); epoch->SetValue(b);
    i >> Bool(b); dont_refresh->SetValue(b);

    if (geo_version > 128) {
      i >> Bool(b); col_overrule_but->SetValue(b);
    }

    if (geo_version > 111) {
      i >> Bool(b); dont_pick->SetValue(b);
    }

    if (geo_version > 0) {
      i >> Bool(b); attr_label->SetValue(b);
    }

    if (geo_version > 132) {
      i >> Bool(b); trans_label->SetValue(b);
    }
#else
    i >> Bool(b); show_on_map->SetState(b);
    i >> Bool(b); epoch->SetState(b);
    i >> Bool(b); dont_refresh->SetState(b);

    if (geo_version > 128) {
      i >> Bool(b); col_overrule_but->SetState(b);
    }

    if (geo_version > 111) {
      i >> Bool(b); dont_pick->SetState(b);
    }

    if (geo_version > 0) {
      i >> Bool(b); attr_label->SetState(b);
    }

    if (geo_version > 132) {
      i >> Bool(b); trans_label->SetState(b);
    }
#endif

    i >> cur_icon_no ;
#ifdef ET25
    icon_menu->SetSelectedItem(cur_icon_no);
    i >> cur_width_no ;
    width_menu->SetSelectedItem(cur_width_no);
#else
    icon_pu->SetSelectedItem(cur_icon_no);
    i >> cur_width_no ;
    width_pu->SetSelectedItem(cur_width_no);
#endif

    if (!q->IsEmpty()) {
	if (geo_version > 103) {
	  i >> nfields;
	  for (int ii= 0; ii < nfields; ii++) {
#ifdef ET25
	    i.ReadString(&show_attr[ii]);
	    i.ReadString(&attr_types[ii]);
#else
	    ReadString(i, &show_attr[ii]);
	    ReadString(i, &attr_types[ii]);
#endif
	  }
	  CheckFields();
	} else
	  FillFields();

	for (int ii= 0; ii < nfields; ii++) {
	  bool b; i >> Bool(b);
	  if (b)
#ifdef ET25
		show_field[ii]->SetValue(TRUE);
#else
		show_field[ii]->SetState(TRUE);
#endif
	}
    }

    bool has_cv;
    i >> Bool(has_cv);
    if (has_cv) {
      GetInfo()->FillAll();
      SetDb(database_name_s);
      cv= new Composer(this, database_name_s, table_name_s, nfields,
		  show_attr, attr_types);
      cv->Load(i);
      cv->AddObserver(this);
    }

    if (has_cv && cv->IsActive()) {
	  SafeDelete(where_s);
	  where_s= strsave(cv->GetWhere());
    }

    if (! GetInfo(TRUE)->TableExists(TableName())) {
      nfields= 0;
      q->SetEmpty(TRUE);
#if 0
      ShowAlert(eAlertNote,
	"Relation @B%s@P does not exist !", TableName());
#else
      fprintf(stderr, "Relation %s does not exist !\n", TableName());
#endif
      SafeDelete(cv);
      SafeDelete(where_s);
    }

    return i;
}


class DynInfo *	QueryDialog::GetDyn() const
{
  return GetInfo(TRUE)->GetDynInfo(TableName());
}


void QueryDialog::CheckFields()
{
  has_color= has_icon= has_dyn= has_loc= has_pline= has_width= FALSE;
  EnableItem(cIdShowAttr);

  // if (!GEOBROWSE && (dinfo= GetInfo(TRUE)->GetDynInfo(TableName()))) {
  if (!GEOBROWSE && GetDyn())
	has_dyn= TRUE;

  for (int i= 0; i < nfields; i++) {
#ifdef ET25
	show_field[i]->SetValue(FALSE);
#else
	show_field[i]->SetState(FALSE);
#endif
	show_label[i]->SetString(show_attr[i], TRUE);
#if 0
	if (has_dyn)
		continue;
#endif

	if (!has_loc && strcmp(show_attr[i], "geo_loc") == 0)
		has_loc= TRUE;
	else if (!has_pline && strcmp(show_attr[i], "geo_pline") == 0)
		has_pline= TRUE;
	else if (!has_color && strcmp(show_attr[i], "geo_color") == 0)
		has_color= TRUE;
	else if (!has_icon && strcmp(show_attr[i], "geo_icon") == 0)
		has_icon= TRUE;
	else if (!has_width && strcmp(show_attr[i], "geo_width") == 0)
		has_width= TRUE;
  }

  EnableItem(cIdShowAttr, has_loc || has_pline || has_dyn);
  if (i < MaxSF) {
    for (; i < MaxSF; i++) {
#ifdef ET25
	show_field[i]->SetValue(FALSE);
#else
	show_field[i]->SetState(FALSE);
#endif
	show_label[i]->SetString(show_attr[i]= strsave(NoField), TRUE);
	DisableItem(cIdShowField+i);
    }
  }
}


void QueryDialog::FillFields()
{
  AllWait(TRUE);
  SetDb(DataBaseName());

  QuelInfo	*qinfo= GetInfo(TRUE);
  int		i;

  if ((nfields= qinfo->GetNrAttr(TableName())) > MaxSF)
	nfields= MaxSF;

  for (i= 0; i < MaxSF; i++) {
      SafeDelete(show_attr[i]);
      SafeDelete(attr_types[i]);
  }

  Iter	next(qinfo->GetAttrIter(TableName()));
  for (i= 0; i < nfields; i++) {
	AttrInfo *ai= (AttrInfo*) next();

	show_attr[i]= strsave(ai->Str());
	attr_types[i]= strsave(qinfo->GetTypeStr(ai->GetType()));
  }

  CheckFields();

  AllWait(FALSE);
}

char **QueryDialog::GetAttr(bool all)
{
  static char	*retf[MaxSF+100];	// Allow adding "oid", etc
  char		**p= retf;

  n_showfields= 0;
  for (int i= 0; i < nfields; i++) {
	bool sf= FALSE;
	if ((sf= show_field[i]->GetValue()) || all) {
	  *p++= show_attr[i];
	  if (sf)
	    n_showfields++;
	}
  }
  *p= 0;
  return retf;
}


#ifdef EXP
static long	start_time;

static char *LOGFILE= "Log";

void LogExp(char *form, char *s2, char *s3, char *s4)
{
  static FILE *logfile;

  if (!logfile) {
    if (! (logfile= fopen(LOGFILE, "a"))) {
      perror(LOGFILE);
      exit(1);
    }
  }

  long curtime;
  time(&curtime);
  fprintf(logfile, "%d:%d ", (cur_time-start_time)/60,
			(cur_time-start_time)%60);
  fprintf(logfile, form, s2, s3, s4);
  fflush(logfile);
}


void SetText(TextView *tv)
{
  const char	*QFILE= "questions";
  const int	MAX_MSG= 1000;

  char		msg[MAX_MSG];
  char		m[MAX_MSG];
  static int	msg_cnt;
  static FILE	*f;

  if (!f) {
    if ((f= fopen(QFILE, "r")) == NULL) {
      perror(QFILE);
      exit(1);
    }
  }

  do {
    fgets(msg, MAX_MSG, f);
  } while (msg[0] == '#');

  if (strncmp(msg, "end", 3) == 0)
    exit(1);

  sprintf(m, "Question number: %d\n\n%s", ++msg_cnt, msg);
  tv->SetString(m, strlen(m));
  tv->UpdateEvent();

  time(&start_time);
}
#endif



const int	cNoneId= 1000;
static VObject	*none_item;

VObject *QueryDialog::DoCreateDialog()
{
  AllWait(TRUE);

  // InitImages();

  int		i;
  OrdCollection *c1= new OrdCollection;
  OrdCollection *c2= new OrdCollection;
  OrdCollection *c3= new OrdCollection;

  show_field= new ToggleButton * [MaxSF];
  show_attr= new char * [MaxSF];
  attr_types= new char * [MaxSF];
  show_label= new TextItem * [MaxSF];
  for (i= 0; i < MaxSF; i++) {
#ifdef ET25
	(i%3 ? (i%3 == 1 ? c2: c3): c1)->Add(show_field[i]=
		new ToggleButton(cIdShowField+i,
		  show_label[i]= new TextItem(NoField))
	);
#else
	(i%3 ? (i%3 == 1 ? c2: c3): c1)->Add(new LabeledButton(cIdShowField+i,
		show_field[i]= new ToggleButton,
		show_label[i]= new TextItem(NoField),
		gPoint10, eVObjVCenter)
	);
#endif
	attr_types[i]= show_attr[i]= 0;
  }

#ifdef ET25
  color_menu= new Menu("Change color to:", FALSE, TRUE, 8, 0);
  width_menu= new Menu("Change width to:", FALSE, TRUE, 4, 0);
  icon_menu= new Menu("Change Icon to:", FALSE, TRUE, 4, 0);
  icon_menu->SetFlag(eMenuNoScroll);
  database_menu= new Menu("Change Database to:", FALSE, TRUE);

  table_menu= new Menu("Change Table to:", FALSE, TRUE, 0, 2);
#else
  color_menu= new Menu("Change color to:", FALSE, 8, 0);
  width_menu= new Menu("Change width to:", FALSE, 4, 0);
  icon_menu= new Menu("Change Icon to:", FALSE, 4, 0);
  icon_menu->SetFlag(eMenuNoScroll);
  database_menu= new Menu("Change Database to:", TRUE);

  table_menu= new Menu("Change Table to:", TRUE, 0, 2);
#endif
  table_menu->SetFlag(eMenuNoScroll);
  if (!none_item)
    none_item= table_menu->MakeMenuItem(Expand("None", 22), cNoneId);
  table_menu->Append(none_item);

  static OrdCollection *doc;
  if (!doc) {
    QueryIter	qi("pg_database", 0, "", "datname", 0);
    char	**a;
    doc= new OrdCollection;
    while (a= qi.Next())
    	doc->Add(new TextItem(a[0]));
  }
  int		geo_entry= 0;
  Iter		DatabNext(doc);
  TextItem	*ti;

  for (i= 0; ti= (TextItem*) DatabNext(); i++) {
	char *as;
	database_menu->AppendItem(as= ti->AsString(), i);
	if (strcmp(as, GetGeoDB()) == 0)
		geo_entry= i;
  }
  database_name_s= strsave(GetGeoDB());
#ifdef ET25
  // database_menu->EnableAll();
#endif

  if (!GEOBROWSE) {
    BitmapInfo	*bi;
#ifdef ET25
    DictionaryIterator	*bmnext= GetInfo()->GetBitmapValueIter();
#else
    Iter		bmnext(GetInfo()->GetBitmapIter());
#endif
  
#ifdef ET25
    while (bi= (BitmapInfo*) bmnext->NextValue()) {
#else
    while (bi= (BitmapInfo*) bmnext()) {
#endif
      icon_menu->Append(bi->GetImageItem());
    }
#ifdef ET25
    delete bmnext;
#endif
    cur_icon_no= 0;

    for (i= 0; i < NrInks(); i++)
	color_menu->AppendItem(itoa(i), i);
    color_menu->SetFlag(eMenuNoScroll);

    for (i= 1; i <= 16; i++)
	width_menu->AppendItem(itoa(i), i);
    width_menu->SetFlag(eMenuNoScroll);
  }

#ifdef ET25
  VObject *epochbut= epoch= new ToggleButton(
	cIdEpoch, new TextItem("Since the Epoch"));
#else
  VObject *epochbut= new LabeledButton(cIdEpoch,
		  epoch= new ToggleButton,
		  new TextItem("Since the Epoch"));
#endif

  VObject *v=
    new Cluster(cIdNone, eVObjHLeft, 10,
#ifdef EXP
	      new BorderItem(new Clipper(tv= new TextView(0, Rectangle(350,100),
		new CheapText(), eLeft, eOne, TRUE, eTextViewReadOnly))),
	      table_pu= new PopupItem(cIdChangeTable, cNoneId, "Table:",
		table_menu),
	      new ActionButton(cIdCompose, "Compose Query..."),
	      0);
#else
      new BorderItem("Query Dialog Name",
#ifdef ET25
        query_name= new RegExpField(cIdChangeName,
	  new RegularExp("[a-z.0-9/_ ]*"),
	  30, 0, title)),
#else
        query_name= new RestrTextItem(cIdChangeName,
	  new RegularExp("[a-z.0-9/_ ]*"),
	  title, 300)),
#endif
      new BorderItem("Database",
	  new Cluster(cIdNone, eVObjVCenter, 5,
#ifdef ET25
	      datab_pu= new PopupButton(cIdChangeDB, geo_entry, database_menu),
#else
	      datab_pu= new PopupItem(cIdChangeDB, geo_entry, "Database:", database_menu),
#endif
	      new ActionButton(cIdMetaRefresh, "Refresh Table Info"),
	  0)),
      new BorderItem("Table",
	  new Cluster(cIdNone, eVObjVCenter, 5,
#ifdef ET25
	      table_pu= new PopupButton(cIdChangeTable, cNoneId, table_menu),
#else
	      table_pu= new PopupItem(cIdChangeTable, cNoneId, "Table:",
		table_menu),
#endif
	      new ActionButton(cIdShowTable, "Show Table..."),
	      new ActionButton(cIdCompose, "Compose Query..."),
	      new ActionButton(cIdAdd, "Add Data..."),
	  0)),
      GEOBROWSE ?
	epochbut:
        new BorderItem("Presentation",
	  new Cluster(cIdNone, eVObjVCenter, 5,
	    new BorderItem(
	      new Cluster(cIdNone, eVObjHLeft, gPoint1,
#ifdef ET25
		show_on_map= new ToggleButton(cIdShowOnMap, "Show"),
		dont_refresh= new ToggleButton(cIdRefresh, "Don't refresh", TRUE),
		dont_pick= new ToggleButton(cIdDontPick, "Don't pick"),
#else
		new LabeledButton(cIdShowOnMap,
		  show_on_map= new ToggleButton,
		  new TextItem("Show")),
	        new LabeledButton(cIdRefresh,
		  dont_refresh= new ToggleButton(cIdNone, TRUE),
		  new TextItem("Don't refresh")),
	        new LabeledButton(cIdDontPick,
		  dont_pick= new ToggleButton,
		  new TextItem("Don't pick")),
#endif
		new BorderItem("Labels", new Cluster(cIdLabels, eVObjHLeft, gPoint2,
#ifdef ET25
		  attr_label= new ToggleButton(cIdAttrLabel, "Show Attr. Name"),
		  trans_label= new ToggleButton(cIdTransparent, "Transparent"),
		  0)),
#else
	          new LabeledButton(cIdAttrLabel,
		    attr_label= new ToggleButton,
		    new TextItem("Show Attr. Name")),
	          new LabeledButton(cIdTransparent,
		    trans_label= new ToggleButton,
		    new TextItem("Transparent")),
		  0), gPoint1),
#endif
		epochbut,
		new BorderItem(new Cluster(cIdColors, eVObjVCenter, gPoint8,
#ifdef ET25
		  new TextItem("Color:"),
	  	  color_pu= new PopupButton(cIdChangeColor, cur_color_no= 2, color_menu),
	  	  col_overrule_but= new RadioButton(cIdColOverrule, "Overrule"),
		  0
	  	)),
#else
	  	  color_pu= new PopupItem(cIdChangeColor, cur_color_no= 2, "Color:", color_menu),
		  new LabeledButton(cIdColOverrule,
	  	    col_overrule_but= new RadioButton,
	  	    new TextItem("Overrule"), gPoint2),
		  0
	  	), gPoint1),
#endif
#ifdef ET25
		new TextItem("Width:"),
	        width_pu= new PopupButton(cIdChangeWidth, cur_width_no= 1, width_menu),
		new TextItem("Icon:"),
	        icon_pu= new PopupButton(cIdChangeIcon, 0, icon_menu),
#else
	        width_pu= new PopupItem(cIdChangeWidth, cur_width_no= 1, "Width:", width_menu),
	        icon_pu= new PopupItem(cIdChangeIcon, 0, "Icon:", icon_menu),
#endif
	      0)),
	    new BorderItem("Show Attr",
	      new Cluster(cIdShowAttr, eVObjVCenter, 5,
	        new Cluster(cIdNone, eVObjHLeft, 5, c1),
	        new Cluster(cIdNone, eVObjHLeft, 5, c2),
	        new Cluster(cIdNone, eVObjHLeft, 5, c3),
	      0)),
	  0)),

      new Cluster(cIdNone, eVObjVCenter, 5,
        new ActionButton(cIdOk, "Done", TRUE),
        GEOBROWSE ?
         new Filler(gPoint0):
#ifdef ET25
         new BorderItem(preview_but= new RadioButton(cIdPreview, "Preview")),
#else
         new BorderItem(new LabeledButton(cIdPreview,
	  preview_but= new RadioButton,
	  new TextItem("Preview"))),
#endif
	0),
      0);
#endif

#ifdef EXP
  SetText(tv);
#endif

  AllWait(FALSE);
  return v;
}

int QueryDialog::GetColor()
{ 
  return cur_color_no;
}

int QueryDialog::GetWidth()
{ 
  return cur_width_no;
}


void QueryDialog::FillTableMenu()
{
  AllWait(TRUE);

  SetDb(DataBaseName());

  // Remove "none" so it will not be freeed
  table_menu->GetCollection()->RemovePtr(none_item);

  table_menu->GetCollection()->FreeAll();

#ifdef ET25
  DictionaryIterator *next= GetInfo(TRUE)->GetTableKeyIter();
#else
  Iter		next(GetInfo(TRUE)->GetTableIter());
#endif
  ByteArray	*ti;
#ifdef ET25
  Menu		*pr= new Menu("Postgres", FALSE, TRUE, 0, 2);
  Menu		*gm= new Menu("Geo", FALSE, TRUE, 0, 2);
#else
  Menu		*pr= new Menu("Postgres", TRUE, 0, 2);
  Menu		*gm= new Menu("Geo", TRUE, 0, 2);
#endif

  pr->SetFlag(eMenuNoScroll);
#ifdef ET25
  for (int i= 0; ti= (ByteArray*) (*next)(); i++) {
    char *str= ti->CharStr();
#else
  for (int i= 0; ti= (ByteArray*) next(); i++) {
    char *str= ti->Str();
#endif
    if (strncmp(str, "pg_", 3) == 0) {
      pr->AppendItem(str, i);
    } else if (strncmp(str, "geo_", 4) == 0) {
      gm->AppendItem(str, i);
    } else
      table_menu->AppendItem(str, i);
  }
#ifdef ET25
  delete next;
#endif
  table_menu->AppendMenu(pr);
  table_menu->AppendMenu(gm);

  if (table_name_s)
	SetPU(table_pu, table_menu, table_name_s);
#ifdef ET25
  // table_menu->EnableAll();
  // pr->EnableAll();
  // gm->EnableAll();
#endif
  AllWait(FALSE);
}


bool QueryDialog::ColOverruled() const
{
  return col_overrule_but->GetValue();
}


void QueryDialog::DoSetup()
{
  query_name_changed= FALSE;
  cancelled= FALSE;

  FillTableMenu();

  if (q->IsEmpty()) {
    DisableItem(cIdShowTable);
    DisableItem(cIdAdd);
    DisableItem(cIdCompose);
    DisableItem(cIdEpoch);
  }
  if (GEOBROWSE)
    return;

#ifdef ET25
  preview_but->SetValue(FALSE);
#else
  preview_but->SetState(FALSE);
#endif
  changed_doc= FALSE;

  EnableItem(cIdShowOnMap, has_loc || has_pline || has_dyn);
  if (q->IsEmpty())
    DisableItem(cIdShowAttr);
  EnableItem(cIdChangeIcon, ShowOnMap() && has_loc && !HasIcon());
#ifdef notdef
  icon_pu->Enable(cIdChangeIcon, ShowOnMap() && has_loc && !HasIcon());
#endif
  EnableItem(cIdPreview, ShowOnMap());
  EnableItem(cIdRefresh, ShowOnMap());
  EnableItem(cIdDontPick, ShowOnMap());
  //EnableItem(cIdAttrLabel, ShowOnMap());
  EnableItem(cIdLabels, ShowOnMap());
  EnableItem(cIdChangeColor, ShowOnMap()
  	&& (!has_color || ColOverruled()));
  EnableItem(cIdColOverrule, has_color);
  EnableItem(cIdChangeWidth, ShowOnMap() && has_pline && !HasWidth());
}


void QueryDialog::DoPreview(Collection *cp)
{
  MapView *dv= q->GetDrawView();

  dv->SetShowCol(cp);
  dv->ForceRedraw();
  dv->UpdateEvent();
}


void QueryDialog::UpdatePreview(bool update)
{
  if (GEOBROWSE)
	return;
  changed_doc= TRUE;
  if (update)
	q->ForceLoad();
  if (preview_but->GetValue() || force_update) {
	DoPreview(q->GetCol(TRUE, update));
	force_update= FALSE;
	if (!preview_but->GetValue())
	  q->GetDrawView()->SetShowCol(0);
  }
}
	

bool QueryDialog::Epoch()
{
  return epoch->GetValue();
}

bool QueryDialog::DontRefresh()
{
  return !GEOBROWSE && dont_refresh->GetValue();
}

bool QueryDialog::DontPick()
{
  return dont_pick->GetValue();
}

bool QueryDialog::TransLabel()
{
  return trans_label->GetValue();
}

bool QueryDialog::ShowAttrLabel()
{
  return attr_label->GetValue();
}

bool QueryDialog::ShowOnMap()
{
  return !GEOBROWSE && show_on_map->GetValue();
}

void QueryDialog::Control(int id, int p, void *v)
{
  switch (id) {
  case cIdCancel:
	cancelled= TRUE;
  case cIdOk:
	if (!GEOBROWSE) {
	  MapView *dv= q->GetDrawView();
	  if (preview_but->GetValue())
	    dv->SetShowCol(0);
	}
	Send(cQUERYDONE);
	Dialog::Control(id, p, v);
	return;
  case cIdEpoch:
	if (p != cPartToggle)
	  return;
	SafeDelete(t);
	UpdatePreview(TRUE);
	return;
  case cIdTransparent:
	if (p != cPartToggle)
	  return;
	UpdatePreview(TRUE);
	return;
  case cIdAttrLabel:
	if (p != cPartToggle)
	  return;
	UpdatePreview(TRUE);
	return;
  case cIdShowOnMap:
	if (p != cPartToggle)
	  return;
	SafeDelete(t);
	if (GEOBROWSE)
	  return;
#if 0
	if (preview_but->GetValue())
	  DoPreview(0);
#endif
	EnableItem(cIdRefresh, ShowOnMap());
	EnableItem(cIdDontPick, ShowOnMap());
	// EnableItem(cIdAttrLabel, ShowOnMap());
	EnableItem(cIdLabels, ShowOnMap());
	EnableItem(cIdPreview, ShowOnMap());
	// EnableItem(cIdChangeColor, ShowOnMap() && !HasColor());
  	EnableItem(cIdChangeColor, ShowOnMap()
  	  && (!has_color || ColOverruled()));
	EnableItem(cIdColOverrule, ShowOnMap() && has_color);
	EnableItem(cIdChangeWidth, ShowOnMap() && HasPline() && !HasWidth());
	EnableItem(cIdChangeIcon, ShowOnMap() && HasLoc() && !HasIcon());
	UpdatePreview(TRUE);
	return;
  case cIdChangeIcon:
#ifdef ET25
#else
	if (v != 0 || p < 0)
		return;
#endif
	if (old_icon_size == gPoint0)
	  old_icon_size= GetInfo()->GetBitmapInfo(cur_icon_no)
		->GetBitmap()->Size();
#ifdef ET25
	cur_icon_no= v;
#else
	cur_icon_no= p;
#endif
	Bitmap *bm= GetInfo()->GetBitmapInfo(cur_icon_no)->GetBitmap();
	Point new_icon_size= bm->Size();
	if (preview_but->GetValue() && old_icon_size == new_icon_size) {
	  { q->GetCol(FALSE, FALSE)->ForEach(IconShape,SetBitmap)(bm); }
	  UpdatePreview(FALSE);
	} else {
	  UpdatePreview(TRUE);
	}
	old_icon_size= new_icon_size;
	return;
  case cIdChangeColor:
#ifdef ET25
	cur_color_no= v;
#else
	if (v != 0 || p < 0)
		return;
	cur_color_no= p;
#endif
	if (preview_but->GetValue()) {
	  { q->GetCol(FALSE, FALSE)->ForEach(QueryShape,SetColor)(cur_color_no); }
	  UpdatePreview(FALSE);
	} else {
	  UpdatePreview(TRUE);
	}
	return;
  case cIdChangeWidth:
#ifdef ET25
	cur_width_no= v;
#else
	if (v != 0 || p < 0)
		return;
	cur_width_no= p;
#endif
	if (preview_but->GetValue()) {
	  { q->GetCol(FALSE, FALSE)->ForEach(PlineShape,SetWidth)(cur_width_no); }
	  UpdatePreview(FALSE);
	} else {
	  UpdatePreview(TRUE);
	}
	return;
  case cIdColOverrule:
	if (p != cPartToggle)
	  return;
	EnableItem(cIdChangeColor, ColOverruled());
	if (preview_but->GetValue() && ColOverruled()) {
	  { q->GetCol(FALSE, FALSE)->ForEach(QueryShape,SetColor)
		(cur_color_no);
	  }
	  UpdatePreview(FALSE);
	} else {
	  UpdatePreview(TRUE);
	}
	return; 	
  case cIdPreview:
	if (p != cPartToggle)
	  return;
	if (!preview_but->GetValue())
	  DoPreview(0);
	else
	  UpdatePreview(FALSE);
	return;
  case cIdChangeTable:
#ifdef ET25
#else
	if (v != 0 || p < 0)
		return;
#endif
	q->SetEmpty(FALSE);
	SafeDelete(t);
	SafeDelete(table_name_s);
	SafeDelete(cv);
	SafeDelete(where_s);
	table_name_s= strsave(
#ifdef ET25
		table_menu->FindItem(int(v))->AsString());
#else
		table_menu->FindItem(p)->AsString());
#endif

	changed_doc= TRUE;
	query_name_changed= TRUE;
#ifndef EXP
	query_name->SetString(table_name_s);
#endif
#ifdef ET25
	SetName(table_name_s);
#else
	SetTitle(table_name_s);
#endif

	EnableItem(cIdShowTable);
	EnableItem(cIdAdd);
	EnableItem(cIdCompose);
	EnableItem(cIdEpoch);
	FillFields();
	if (GEOBROWSE)
	  return;
#ifdef ET25
	show_on_map->SetValue(FALSE);
#else
	show_on_map->SetState(FALSE);
#endif
	EnableItem(cIdShowOnMap, has_loc || has_pline || has_dyn);
	DisableItem(cIdChangeIcon);
	DisableItem(cIdChangeColor);
#ifdef ET25
	col_overrule_but->SetValue(FALSE);
#else
	col_overrule_but->SetState(FALSE);
#endif
	DisableItem(cIdColOverrule);
	DisableItem(cIdChangeWidth);
	DisableItem(cIdPreview);
	DisableItem(cIdRefresh);
	DisableItem(cIdDontPick);
	// DisableItem(cIdAttrLabel);
	DisableItem(cIdLabels);
	if (preview_but->GetValue()) {
#ifdef ET25
	  preview_but->SetValue(FALSE);
#else
	  preview_but->SetState(FALSE);
#endif
	  UpdatePreview(TRUE);
	  DoPreview(0);
	} else
	  UpdatePreview(TRUE);
	return;
  case cIdChangeDB:
#ifdef ET25
#else
	if (v != 0 || p < 0)
		return;
#endif
	if (!GEOBROWSE && preview_but->GetValue()) {
#ifdef ET25
	  preview_but->SetValue(FALSE);
#else
	  preview_but->SetState(FALSE);
#endif
	  DoPreview(0);
	}
	q->SetEmpty(TRUE);
	has_dyn= has_loc= has_pline= FALSE;
	SafeDelete(t);
	SafeDelete(database_name_s);
	SafeDelete(cv);
	SafeDelete(where_s);
	database_name_s= strsave(
#ifdef ET25
	    database_menu->FindItem(int(v))->AsString());
#else
	    database_menu->FindItem(p)->AsString());
#endif
	SetDb(database_name_s);
	FillTableMenu();

	changed_doc= TRUE;
	query_name_changed= TRUE;
	query_name->SetString("NoName");
#ifdef ET25
	SetName(table_name_s);
#else
	SetTitle(table_name_s);
#endif

	DisableItem(cIdShowTable);
	DisableItem(cIdAdd);
	DisableItem(cIdCompose);
	DisableItem(cIdEpoch);
	if (GEOBROWSE)
	  return;
#ifdef ET25
	show_on_map->SetValue(FALSE);
#else
	show_on_map->SetState(FALSE);
#endif
	DisableItem(cIdShowOnMap);
	DisableItem(cIdRefresh);
	DisableItem(cIdDontPick);
	// DisableItem(cIdAttrLabel);
	DisableItem(cIdLabels);
	DisableItem(cIdChangeWidth);
    	DisableItem(cIdChangeColor);
#ifdef ET25
	col_overrule_but->SetValue(FALSE);
#else
	col_overrule_but->SetState(FALSE);
#endif
	DisableItem(cIdColOverrule);
	DisableItem(cIdShowAttr);
    	DisableItem(cIdChangeIcon);
	DisableItem(cIdPreview);
	UpdatePreview(TRUE);
	return;
  case cIdChangeName:
	changed_doc= TRUE;
	query_name_changed= TRUE;
#ifdef ET25
	SetName(query_name->AsString());
#else
	SetTitle(query_name->GetText()->AsString());
#endif
	return;
  case cIdMetaRefresh:
	GetInfo()->RefetchInfo();
	GetInfo()->FillAll();
	FillTableMenu();
	return;
  case cIdShowTable:
	if (q->IsEmpty())
	    return;
	if (!t)
	    t= new TableDialog((byte*) TableName(), this);
#ifdef ET25
	t->ShowUnderMouse();
#else
	t->ShowOnWindow(GetWindow());
#endif
	return;
  case cIdAdd:
  	if (q->IsEmpty())
	    return;
	AddTuple();
	Dialog::Control(cIdOk, p, v);
	return;
  case cIdCompose:
	if (!cv) {
	    GetInfo()->FillAll();
	    // SetDb(DataBaseName());
	    cv= new Composer(this, DataBaseName(), table_name_s, nfields,
		  show_attr, attr_types);
	    cv->AddObserver(this);
	}
	if (cv->IsOpen())
	  cv->GetWindow()->Top();
	else
	  cv->Show();
	return;
  default:
	if (id >= cIdShowField && id < cIdShowField + MaxSF
	&& p == cPartToggle) {
	  SafeDelete(t);
	  UpdatePreview(TRUE);
	}
	return;
  }
}


void QueryDialog::UpdateWhere(bool update_pv)
{
  SafeDelete(where_s);
  if (cv && cv->IsActive()) {
    where_s= strsave(cv->GetWhere());
  }
  if (update_pv) {
    if (t && ! t->IsOpen())
      SafeDelete(t);
    UpdatePreview(TRUE);
  }
}

void QueryDialog::DoObserve(int id, int part, void *data, Object *o)
{
  switch (id) {
  case cCOMPOSE_DONE:
    if (Guard(o,Composer)->IsChanged() || ((Composer*)o)->IsManual()) {
      if (!IsOpen())
	force_update= TRUE;
      UpdateWhere();
    }
#ifdef EXP
    SetText(tv);
    DisableItem(cIdCompose);
#endif
    break;
  case cCOMPOSE_UPDATE:
    force_update= TRUE;
    UpdateWhere();
#ifdef EXP
    SetText(tv);
    DisableItem(cIdCompose);
#endif
    break;
  }
}


void QueryDialog::AddTuple()
{
  TableDialog *tempt= new TableDialog((byte*) TableName(), this);
  tempt->MakeLoose();
  tempt->ShowAddTuple();
}


bool QueryDialog::EditShape(long oid)
{
  char where[1000];
  bool editq;

  DynInfo *di= GetDyn();
  sprintf(where, "%s.%s = \"%d\"::oid", TableName(),
	di && di->TheOid() ? di->TheOid(): "oid", oid);
  TableDialog *tempt= new TableDialog((byte*) TableName(), this, where);
  tempt->MakeLoose();
  if (! tempt->EditShape(oid, &editq))
	delete tempt;
  return editq;
}
