/*
 * File:	bapp.cc
 * Purpose:	wxWindows GUI builder
 * Author:	Julian Smart
 * Created:	1993
 * Updated:	
 * Copyright:	(c) 1993, AIAI, University of Edinburgh
 */

static const char sccsid[] = "%W% %G%";

#include "wx.h"
#include "wx_help.h"
#include "wx_types.h"
#include <ctype.h>
#include <stdlib.h>
#ifdef wx_msw
#include <time.h>
#else
#include <sys/time.h>
#endif

#include "wxbuild.h"
#include "namegen.h"
#include "bapp.h"
#include "bframe.h"
#include "bmenu.h"
#include "bsubwin.h"
#include "bitem.h"
#include "btoolbar.h"
#include "bactions.h"
#include "bgdi.h"
#include "btree.h"

#define BUILDERSECTION "wxBuilder"

extern void ClearTree(void);
extern Bool isModified;

// This statement initialises the whole application
BuildApp     buildApp;

// Bitmaps for palette
wxBitmap *PaletteFrameBitmap = NULL;
wxBitmap *PaletteDialogBoxBitmap = NULL;
wxBitmap *PalettePanelBitmap = NULL;
wxBitmap *PaletteCanvasBitmap = NULL;
wxBitmap *PaletteTextWindowBitmap = NULL;
wxBitmap *PaletteMessageBitmap = NULL;
wxBitmap *PaletteButtonBitmap = NULL;
wxBitmap *PaletteCheckBoxBitmap = NULL;
wxBitmap *PaletteListBoxBitmap = NULL;
wxBitmap *PaletteRadioBoxBitmap = NULL;
wxBitmap *PaletteChoiceBitmap = NULL;
wxBitmap *PaletteTextBitmap = NULL;
wxBitmap *PaletteMultiTextBitmap = NULL;
wxBitmap *PaletteSliderBitmap = NULL;
wxBitmap *PaletteArrowBitmap = NULL;
wxBitmap *PaletteGroupBitmap = NULL;
wxBitmap *PaletteGaugeBitmap = NULL;

#ifdef wx_x
#include "bitmaps/frame.xbm"
#include "bitmaps/dialog.xbm"
#include "bitmaps/panel.xbm"
#include "bitmaps/canvas.xbm"
#include "bitmaps/textsw.xbm"
#include "bitmaps/message.xbm"
#include "bitmaps/button.xbm"
#include "bitmaps/check.xbm"
#include "bitmaps/listbox.xbm"
#include "bitmaps/radio.xbm"
#include "bitmaps/choice.xbm"
#include "bitmaps/text.xbm"
#include "bitmaps/mtext.xbm"
#include "bitmaps/slider.xbm"
#include "bitmaps/arrow.xbm"
#include "bitmaps/group.xbm"
#include "bitmaps/gauge.xbm"
#endif

// Bitmaps for toolbar
wxBitmap *ToolbarLoadBitmap = NULL;
wxBitmap *ToolbarSaveBitmap = NULL;
wxBitmap *ToolbarVertBitmap = NULL;
wxBitmap *ToolbarAlignTBitmap = NULL;
wxBitmap *ToolbarAlignBBitmap = NULL;
wxBitmap *ToolbarHorizBitmap = NULL;
wxBitmap *ToolbarAlignLBitmap = NULL;
wxBitmap *ToolbarAlignRBitmap = NULL;
wxBitmap *ToolbarCPPBitmap = NULL;
wxBitmap *ToolbarTreeBitmap = NULL;
wxBitmap *ToolbarHelpBitmap = NULL;

#ifdef wx_x
#include "bitmaps/load.xbm"
#include "bitmaps/save.xbm"
#include "bitmaps/vert.xbm"
#include "bitmaps/alignt.xbm"
#include "bitmaps/alignb.xbm"
#include "bitmaps/horiz.xbm"
#include "bitmaps/alignl.xbm"
#include "bitmaps/alignr.xbm"
#include "bitmaps/cpp.xbm"
#include "bitmaps/tree.xbm"
#include "bitmaps/help.xbm"
#endif

static void ObjectMenuProc(wxMenu& menu, wxCommandEvent& event);

// The `main program' equivalent, creating the windows and returning the
// main frame
wxFrame *BuildApp::OnInit(void)
{
#ifdef wx_msw
  resourceFile = NULL;
#endif
#ifdef wx_x
  resourceFile = new char[400];
  (void)wxGetHomeDir(resourceFile);
  strcat(resourceFile, "/.wxbuildrc");
#endif
  int i = 1;
  
  // Read input file if given without using -f
  if (argc > i && (argv[i][0] != '-'))
  {
    projectFilename = copystring(argv[i]);
    i ++;
  }

  while (i < argc)
  {
    if (strcmp(argv[i], "-f") == 0)
    {
      i ++;
      if (i == argc)
      {
        wxError("-f must take a filename!", "Warning");
      }
      else
      {
        projectFilename = copystring(argv[i]);
        i ++;
      }
    }
    else
    {
      char buf[200];
      sprintf(buf, "Unrecognised wxBuilder option %s", argv[i]);
      wxError(buf, "Warning");
      i++;
    }
  }

  wxAllTypes.AddType(wxTYPE_TOOLBAR, wxTYPE_CANVAS, "toolbar");

  handCursor = new wxCursor(wxCURSOR_HAND);
  crossCursor = new wxCursor(wxCURSOR_CROSS);
  // Create a small font
  SmallButtonFont = new wxFont(11, wxROMAN, wxNORMAL, wxNORMAL);
  SmallLabelFont = new wxFont(12, wxROMAN, wxITALIC, wxBOLD);
  TextWindowFont = new wxFont(12, wxSWISS, wxNORMAL, wxNORMAL);
  InitializeDefaults();
  
  // Create the main frame window
  MainFrame = new BuildFrame(NULL, "wxBuilder [unnamed]", mainX, mainY, mainWidth, mainHeight);

  // Load palette bitmaps
#ifdef wx_msw
  ToolbarLoadBitmap = new wxBitmap("LOADTOOL");
  ToolbarSaveBitmap = new wxBitmap("SAVETOOL");
  ToolbarVertBitmap = new wxBitmap("VERTTOOL");
  ToolbarAlignTBitmap = new wxBitmap("ALIGNTTOOL");
  ToolbarAlignBBitmap = new wxBitmap("ALIGNBTOOL");
  ToolbarHorizBitmap = new wxBitmap("HORIZTOOL");
  ToolbarAlignLBitmap = new wxBitmap("ALIGNLTOOL");
  ToolbarAlignRBitmap = new wxBitmap("ALIGNRTOOL");
  ToolbarCPPBitmap = new wxBitmap("CPPTOOL");
  ToolbarTreeBitmap = new wxBitmap("TREETOOL");
  ToolbarHelpBitmap = new wxBitmap("HELPTOOL");
#endif
#ifdef wx_x
  ToolbarLoadBitmap = new wxBitmap(load_bits, load_width, load_height);
  ToolbarSaveBitmap = new wxBitmap(save_bits, save_width, save_height);
  ToolbarVertBitmap = new wxBitmap(vert_bits, vert_width, vert_height);
  ToolbarAlignTBitmap = new wxBitmap(alignt_bits, alignt_width, alignt_height);
  ToolbarAlignBBitmap = new wxBitmap(alignb_bits, alignb_width, alignb_height);
  ToolbarHorizBitmap = new wxBitmap(horiz_bits, horiz_width, horiz_height);
  ToolbarAlignLBitmap = new wxBitmap(alignl_bits, alignl_width, alignl_height);
  ToolbarAlignRBitmap = new wxBitmap(alignr_bits, alignr_width, alignr_height);
  ToolbarCPPBitmap = new wxBitmap(cpp_bits, cpp_width, cpp_height);
  ToolbarTreeBitmap = new wxBitmap(tree_bits, tree_width, tree_height);
  ToolbarHelpBitmap = new wxBitmap(help_bits, help_width, help_height);
#endif

  // Create the toolbar
  MainFrame->toolbar = new EditorToolBar(MainFrame, 0, 0, -1, -1, 0,
                                        wxHORIZONTAL, 30);
  MainFrame->toolbar->SetMargins(2, 2);
  MainFrame->toolbar->GetDC()->SetBackground(wxLIGHT_GREY_BRUSH);
  CreateObjectMenu();

#ifdef wx_msw
  int width = 24;
  int dx = 2;
  int gap = 6;
#else
  int width = ToolbarLoadBitmap->GetWidth();
  int dx = 2;
  int gap = 6;
#endif
  int currentX = gap;
  MainFrame->toolbar->AddTool(TOOLBAR_LOAD_FILE, ToolbarLoadBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_SAVE_FILE, ToolbarSaveBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx + gap;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_HORIZ, ToolbarVertBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_VERT_TOP_ALIGN, ToolbarAlignTBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_VERT_BOT_ALIGN, ToolbarAlignBBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_VERT, ToolbarHorizBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN, ToolbarAlignLBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
  MainFrame->toolbar->AddTool(TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN, ToolbarAlignRBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx + gap;
  MainFrame->toolbar->AddTool(TOOLBAR_GEN_CPP, ToolbarCPPBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
/*
  MainFrame->toolbar->AddTool(TOOLBAR_TREE, ToolbarTreeBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;
*/
  MainFrame->toolbar->AddTool(TOOLBAR_HELP, ToolbarHelpBitmap, NULL,
                   FALSE, (float)currentX, -1, NULL);
  currentX += width + dx;

  MainFrame->OnSize(-1, -1);

  // Load palette bitmaps
#ifdef wx_msw
  PaletteFrameBitmap = new wxBitmap("FRAMETOOL");
  PaletteDialogBoxBitmap = new wxBitmap("DIALOGBOXTOOL");
  PalettePanelBitmap = new wxBitmap("PANELTOOL");
  PaletteCanvasBitmap = new wxBitmap("CANVASTOOL");
  PaletteTextWindowBitmap = new wxBitmap("TEXTWINDOWTOOL");
  PaletteMessageBitmap = new wxBitmap("MESSAGETOOL");
  PaletteButtonBitmap = new wxBitmap("BUTTONTOOL");
  PaletteCheckBoxBitmap = new wxBitmap("CHECKBOXTOOL");
  PaletteListBoxBitmap = new wxBitmap("LISTBOXTOOL");
  PaletteRadioBoxBitmap = new wxBitmap("RADIOBOXTOOL");
  PaletteChoiceBitmap = new wxBitmap("CHOICETOOL");
  PaletteTextBitmap = new wxBitmap("TEXTTOOL");
  PaletteMultiTextBitmap = new wxBitmap("MULTITEXTTOOL");
  PaletteSliderBitmap = new wxBitmap("SLIDERTOOL");
  PaletteArrowBitmap = new wxBitmap("ARROWTOOL");
  PaletteGroupBitmap = new wxBitmap("GROUPTOOL");
  PaletteGaugeBitmap = new wxBitmap("GAUGETOOL");
#endif
#ifdef wx_x
  PaletteFrameBitmap = new wxBitmap(frame_bits, frame_width, frame_height);
  PaletteDialogBoxBitmap = new wxBitmap(dialog_bits, dialog_width, dialog_height);
  PalettePanelBitmap = new wxBitmap(panel_bits, panel_width, panel_height);
  PaletteCanvasBitmap = new wxBitmap(canvas_bits, canvas_width, canvas_height);
  PaletteTextWindowBitmap = new wxBitmap(textsw_bits, textsw_width, textsw_height);
  PaletteMessageBitmap = new wxBitmap(message_bits, message_width, message_height);
  PaletteButtonBitmap = new wxBitmap(button_bits, button_width, button_height);
  PaletteCheckBoxBitmap = new wxBitmap(check_bits, check_width, check_height);
  PaletteListBoxBitmap = new wxBitmap(listbox_bits, listbox_width, listbox_height);
  PaletteRadioBoxBitmap = new wxBitmap(radio_bits, radio_width, radio_height);
  PaletteChoiceBitmap = new wxBitmap(choice_bits, choice_width, choice_height);
  PaletteTextBitmap = new wxBitmap(text_bits, text_width, text_height);
  PaletteMultiTextBitmap = new wxBitmap(mtext_bits, mtext_width, mtext_height);
  PaletteSliderBitmap = new wxBitmap(slider_bits, slider_width, slider_height);
  PaletteArrowBitmap = new wxBitmap(arrow_bits, arrow_width, arrow_height);
  PaletteGroupBitmap = new wxBitmap(group_bits, group_width, group_height);
  PaletteGaugeBitmap = new wxBitmap(gauge_bits, gauge_width, gauge_height);
#endif

  EditorPaletteFrame = new EditorToolPaletteFrame(MainFrame, "wxWin Objects", paletteX, paletteY, 100, 200,
  // Under Motif, looks better with a thick border than no border.
#ifdef wx_motif
         wxSDI | wxTHICK_FRAME | wxTINY_CAPTION_HORIZ);
#else
         wxSDI | wxTINY_CAPTION_HORIZ);
#endif
  EditorPaletteFrame->palette = new EditorToolPalette(EditorPaletteFrame, 0, 0, -1, -1, 0,
                                        wxHORIZONTAL, 6);
  EditorPaletteFrame->palette->SetMargins(2, 2);
  EditorPaletteFrame->palette->GetDC()->SetBackground(wxLIGHT_GREY_BRUSH);
  EditorPaletteFrame->palette->AddTool(PALETTE_ARROW, PaletteArrowBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_FRAME, PaletteFrameBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_DIALOG_BOX, PaletteDialogBoxBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_PANEL, PalettePanelBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_CANVAS, PaletteCanvasBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_TEXT_WINDOW, PaletteTextWindowBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_MESSAGE, PaletteMessageBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_BUTTON, PaletteButtonBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_CHECKBOX, PaletteCheckBoxBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_RADIOBOX, PaletteRadioBoxBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_LISTBOX, PaletteListBoxBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_CHOICE, PaletteChoiceBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_TEXT, PaletteTextBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_MULTITEXT, PaletteMultiTextBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_SLIDER, PaletteSliderBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_GROUPBOX, PaletteGroupBitmap, NULL, TRUE);
  EditorPaletteFrame->palette->AddTool(PALETTE_GAUGE, PaletteGaugeBitmap, NULL, TRUE);

  EditorPaletteFrame->palette->Layout();
  float maxWidth, maxHeight;
  EditorPaletteFrame->palette->GetMaxSize(&maxWidth, &maxHeight);
  EditorPaletteFrame->SetClientSize((int)maxWidth, (int)maxHeight);
  EditorPaletteFrame->palette->ToggleTool(PALETTE_ARROW, TRUE);
  EditorPaletteFrame->palette->currentlySelected = PALETTE_ARROW;
  EditorPaletteFrame->Show(TRUE);
  EditorPaletteFrame->palette->OnPaint();

  HelpInstance = new wxHelpInstance(TRUE);
  HelpInstance->Initialize("wxbuild");

  if (projectFilename)
  {
    LoadProject(projectFilename, FALSE);
  }

  return MainFrame;
}

BuildApp::BuildApp(void)
{
  newObjectX = 0;
  newObjectY = 0;
  usePosition = FALSE;
  objectMenu = NULL;
  objectParent = NULL;
  
  revision = 0;
  topLevelFrame = NULL;
  projectFilename = NULL;
  buildName = copystring("noname");
  buildDescription = NULL;

#ifdef wx_x
  // Determine the user's full name
  {
    /* Fullname <email> */
    char answer[190+32+4+1];
    char name[127];
    char hostname[65];
    char id[32];

    if (wxGetUserName(name, 126)) {
      if (wxGetHostName(hostname, 64)) {
	if (wxGetUserId(id, 31) == FALSE) id[0] = '\0';
	sprintf(answer, "%s <%s@%s>"
	  ,name
	  ,id
	  ,hostname);
      } else
	strcpy(answer, name);
      buildAuthors = copystring(answer);
    } else buildAuthors = NULL;
  }
#else
  buildAuthors = NULL;
#endif
  buildDate = NULL;
  appClass = copystring("AppClass");
  buildMDIType = wxSDI;
  extensionCPP = copystring(".cc");
  currentMenuItemId = 1;
  testMode = FALSE;

  mainX = 250;
  mainY = 10;
#ifdef wx_x
  mainWidth = 500;
#else
  mainWidth = 400;
#endif
  mainHeight = 400;

  paletteX = 10;
  paletteY = 150;

  reportX = 50;
  reportY = 50;
  reportWidth = 350;
  reportHeight = 200;

  treeX = 50;
  treeY = 200;
  treeWidth = 250;
  treeHeight = 250;

  projectDirUNIX = copystring("project");
  projectDirDOS = copystring("c:\\project");
  commandLine = copystring("");
  genMakefiles = TRUE;
  genRCFile = TRUE;
  genDefFile = TRUE;
  separateFiles = FALSE;
  useResourceMethod = TRUE;

  XIncludes = copystring("-I/usr/include/X11R5 -I/usr/include/motif1.2");
  XLibs = copystring("-L/usr/lib/X11R5 -L/usr/lib/motif1.2");
  /* People compiling wxBuilder locally may prefer this 
   * more intelligent approach instead of the above.
   * In which case, uncomment.
   */
/*
#ifdef XINCLUDES
  XIncludes = copystring(XINCLUDES);
#elif defined(wx_motif)
  XIncludes = copystring("-I/usr/include/X11R5 -I/usr/include/motif1.2");
#else
  XIncludes = copystring("-I$(OPENWINHOME)/include");
#endif

#ifdef XLIBS
  XLibs = copystring(XLIBS);
#elif defined(wx_xview)
  Xlibs = copystring("-L$(OPENWINHOME)/lib");
#else 
  XLibs = copystring("-L/usr/lib/X11R5 -L/usr/lib/motif1.2");
#endif
*/

  windowsInclude = copystring("-Ic:\\c700\\include");
  wxDirUNIX = copystring("/usr/lib/wx");
  wxDirDOS = copystring("c:\\wx");

#ifdef hpux
  guiTarget = copystring("hp");
#elif defined(wx_xview)
  guiTarget = copystring("xview");
#else
  guiTarget = copystring("motif");
#endif

  extraIncludesX = copystring("");
  extraLibsX = copystring("");
  extraIncludesMSW = copystring("");
  extraLibsMSW = copystring("");

  autoCompile = FALSE;
  autoRun = FALSE;

  compilerDOS = copystring("Microsoft C/C++ Vsn 7");
  compilerUNIX = copystring("gcc");

  fileHistoryN = 0;
  for (int i = 0; i < MAX_FILE_HISTORY; i++)
    fileHistory[i] = NULL;
}

BuildApp::~BuildApp(void)
{
  delete objectMenu;
}

void BuildApp::AddFileToHistory(char *file)
{
  int i;

  // Check we don't already have this file
  for (i = 0; i < fileHistoryN; i++)
  {
    if (fileHistory[i] && (strcmp(fileHistory[i], file) == 0))
      return;
  }
  
  // Add to the project file history:
  // Move existing files (if any) down so we can insert file at beginning.
  
  // First delete filename that has popped off the end of the array (if any)
  if (fileHistoryN == MAX_FILE_HISTORY)
  {
    delete[] fileHistory[MAX_FILE_HISTORY-1];
    fileHistory[MAX_FILE_HISTORY-1] = NULL;
  }
  if (fileHistoryN < MAX_FILE_HISTORY)
  {
    if (fileHistoryN == 0)
      fileMenu->AppendSeparator();
    fileMenu->Append(BUILD_FILE1+fileHistoryN, "[EMPTY]");
    fileHistoryN ++;
  }
  // Shuffle filenames down
  for (i = (fileHistoryN-1); i > 0; i--)
  {
    fileHistory[i] = fileHistory[i-1];
  }
  fileHistory[0] = copystring(file);
  
  for (i = 0; i < fileHistoryN; i++)
    if (fileHistory[i])
    {
      char buf[400];
      sprintf(buf, "&%d %s", i+1, buildApp.fileHistory[i]);
      fileMenu->SetLabel(BUILD_FILE1+i, buf);
    }
}

// Set up defaults from WIN.INI/.Xdefaults
void BuildApp::InitializeDefaults(void)
{
  wxGetResource(BUILDERSECTION, "target", &guiTarget, resourceFile);
  wxGetResource(BUILDERSECTION, "autoRun", &autoRun, resourceFile);
  wxGetResource(BUILDERSECTION, "autoCompile", &autoCompile, resourceFile);
  wxGetResource(BUILDERSECTION, "compilerDOS", &compilerDOS, resourceFile);
  wxGetResource(BUILDERSECTION, "compilerUNIX", &compilerUNIX, resourceFile);
  wxGetResource(BUILDERSECTION, "xIncludes", &XIncludes, resourceFile);
  wxGetResource(BUILDERSECTION, "xLib", &XLibs, resourceFile);
  wxGetResource(BUILDERSECTION, "windowsInclude", &windowsInclude, resourceFile);
  wxGetResource(BUILDERSECTION, "wxDirUNIX", &wxDirUNIX, resourceFile);
  wxGetResource(BUILDERSECTION, "wxDirDOS", &wxDirDOS, resourceFile);
  wxGetResource(BUILDERSECTION, "extraIncludesX", &extraIncludesX, resourceFile);
  wxGetResource(BUILDERSECTION, "extraLibsX", &extraLibsX, resourceFile);
  wxGetResource(BUILDERSECTION, "extraIncludesMSW", &extraIncludesMSW, resourceFile);
  wxGetResource(BUILDERSECTION, "extraLibsMSW", &extraLibsMSW, resourceFile);

  wxGetResource(BUILDERSECTION, "mainX", &mainX, resourceFile);
  wxGetResource(BUILDERSECTION, "mainY", &mainY, resourceFile);
  wxGetResource(BUILDERSECTION, "mainWidth", &mainWidth, resourceFile);
  wxGetResource(BUILDERSECTION, "mainHeight", &mainHeight, resourceFile);

  wxGetResource(BUILDERSECTION, "reportX", &reportX, resourceFile);
  wxGetResource(BUILDERSECTION, "reportY", &reportY, resourceFile);
  wxGetResource(BUILDERSECTION, "reportWidth", &reportWidth, resourceFile);
  wxGetResource(BUILDERSECTION, "reportHeight", &reportHeight, resourceFile);

  wxGetResource(BUILDERSECTION, "treeX", &treeX, resourceFile);
  wxGetResource(BUILDERSECTION, "treeY", &treeY, resourceFile);
  wxGetResource(BUILDERSECTION, "treeWidth", &treeWidth, resourceFile);
  wxGetResource(BUILDERSECTION, "treeHeight", &treeHeight, resourceFile);

  wxGetResource(BUILDERSECTION, "paletteX", &paletteX, resourceFile);
  wxGetResource(BUILDERSECTION, "paletteY", &paletteY, resourceFile);

  fileHistoryN = 0;
  char buf[100];
  sprintf(buf, "file%d", fileHistoryN+1);
  char *historyFile = NULL;
  while ((fileHistoryN <= MAX_FILE_HISTORY) && wxGetResource(BUILDERSECTION, buf, &historyFile, resourceFile) && historyFile)
  {
    // wxGetResource allocates memory so this is o.k.
    fileHistory[fileHistoryN] = historyFile;
    fileHistoryN ++;
    sprintf(buf, "file%d", fileHistoryN+1);
    historyFile = NULL;
  }
}

// Write defaults into WIN.INI (not .Xdefaults!)
void BuildApp::WriteDefaults(void)
{
  wxWriteResource(BUILDERSECTION, "target", guiTarget, resourceFile);
  wxWriteResource(BUILDERSECTION, "autoRun", autoRun, resourceFile);
  wxWriteResource(BUILDERSECTION, "autoCompile", autoCompile, resourceFile);
  wxWriteResource(BUILDERSECTION, "compilerDOS", compilerDOS, resourceFile);
  wxWriteResource(BUILDERSECTION, "compilerUNIX", compilerUNIX, resourceFile);
  wxWriteResource(BUILDERSECTION, "xIncludes", XIncludes, resourceFile);
  wxWriteResource(BUILDERSECTION, "xLib", XLibs, resourceFile);
  wxWriteResource(BUILDERSECTION, "windowsInclude", windowsInclude, resourceFile);
  wxWriteResource(BUILDERSECTION, "wxDirUNIX", wxDirUNIX, resourceFile);
  wxWriteResource(BUILDERSECTION, "wxDirDOS", wxDirDOS, resourceFile);
  wxWriteResource(BUILDERSECTION, "extraIncludesX", extraIncludesX, resourceFile);
  wxWriteResource(BUILDERSECTION, "extraLibsX", extraLibsX, resourceFile);
  wxWriteResource(BUILDERSECTION, "extraIncludesMSW", extraIncludesMSW, resourceFile);
  wxWriteResource(BUILDERSECTION, "extraLibsMSW", extraLibsMSW, resourceFile);

  wxWriteResource(BUILDERSECTION, "mainX", mainX, resourceFile);
  wxWriteResource(BUILDERSECTION, "mainY", mainY, resourceFile);
  wxWriteResource(BUILDERSECTION, "mainWidth", mainWidth, resourceFile);
  wxWriteResource(BUILDERSECTION, "mainHeight", mainHeight, resourceFile);
  wxWriteResource(BUILDERSECTION, "reportX", reportX, resourceFile);
  wxWriteResource(BUILDERSECTION, "reportY", reportY, resourceFile);
  wxWriteResource(BUILDERSECTION, "reportWidth", reportWidth, resourceFile);
  wxWriteResource(BUILDERSECTION, "reportHeight", reportHeight, resourceFile);
  wxWriteResource(BUILDERSECTION, "treeX", treeX, resourceFile);
  wxWriteResource(BUILDERSECTION, "treeY", treeY, resourceFile);
  wxWriteResource(BUILDERSECTION, "treeWidth", treeWidth, resourceFile);
  wxWriteResource(BUILDERSECTION, "treeHeight", treeHeight, resourceFile);
  wxWriteResource(BUILDERSECTION, "paletteX", paletteX, resourceFile);
  wxWriteResource(BUILDERSECTION, "paletteY", paletteY, resourceFile);

  char buf[100];
  for (int i = 0; i < fileHistoryN; i++)
  {
    sprintf(buf, "file%d", i+1);
    wxWriteResource(BUILDERSECTION, buf, fileHistory[i], resourceFile);
  }
}

void BuildApp::EditGlobalSettings(void)
{
  wxBeginBusyCursor();
  wxDialogBox *dialog = new wxDialogBox(NULL, "Global Settings", TRUE, 10, 10);
  dialog->SetLabelFont(SmallLabelFont);
  dialog->SetButtonFont(SmallButtonFont);

  BuildForm *form = new BuildForm("Global settings");
  
  form->Add(wxMakeFormString("Windows compiler", &compilerDOS, wxFORM_CHOICE,
              new wxList(wxMakeConstraintStrings(
    "Borland C++ 4.x",
    "Borland C++ 3.1",
    "Microsoft C/C++ Vsn 7",
    "Microsoft Visual C++",
    "Microsoft C++ for NT",
    "Symantec C++",
    "Watcom C++",
    NULL), NULL), NULL, wxVERTICAL, 200));
  form->Add(wxMakeFormNewLine());

  form->Add(wxMakeFormString("UNIX compiler", &compilerUNIX, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               200));
  form->Add(wxMakeFormString("X GUI target", &guiTarget, wxFORM_CHOICE,
              new wxList(wxMakeConstraintStrings("xview", "motif", "hp", NULL), NULL),
            NULL, wxVERTICAL, 150));
  form->Add(wxMakeFormNewLine());

  form->Add(wxMakeFormString("X includes", &XIncludes, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());

  form->Add(wxMakeFormString("X libs", &XLibs, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("Extra includes (UNIX)", &extraIncludesX, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               150));
//  form->Add(wxMakeFormNewLine());

  form->Add(wxMakeFormString("Extra libs (UNIX)", &extraLibsX, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               150));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("Extra includes (Windows)", &extraIncludesMSW, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               150));
//  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("Extra libs (Windows)", &extraLibsMSW, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               150));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("wxWindows home (Windows)", &wxDirDOS, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("wxWindows home (UNIX)", &wxDirUNIX, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
/* OPTIONS TO BE IMPLEMENTED
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormBool("Auto compile", &autoCompile));
  form->Add(wxMakeFormBool("Auto run", &autoRun));
*/
  form->AssociatePanel(dialog);
  form->dialog = dialog;

  dialog->Fit();
  dialog->Centre(wxBOTH);

  wxEndBusyCursor();
  dialog->Show(TRUE);
}

void BuildApp::EditProjectSettings(void)
{
  wxBeginBusyCursor();
  wxDialogBox *dialog = new wxDialogBox(NULL, "Project Settings", TRUE, 10, 10);
  dialog->SetLabelFont(SmallLabelFont);
  dialog->SetButtonFont(SmallButtonFont);

  BuildForm *form = new BuildForm("Project settings");
  
  form->Add(wxMakeFormString("Root name", &buildName, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));

  form->Add(wxMakeFormString("C++ Extension", &extensionCPP, wxFORM_CHOICE,
	new wxList(wxMakeConstraintStrings(
    ".cc",
    ".cpp",
    ".ccx",
#ifdef wx_x
    ".C",
#endif
    NULL), NULL), 
    NULL, wxVERTICAL, 120));

  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("Directory under Windows", &projectDirDOS, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormString("Directory under UNIX", &projectDirUNIX, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());
/*
  form->Add(wxMakeFormString("Command line", &commandLine, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
               300));
  form->Add(wxMakeFormNewLine());
*/
  form->Add(wxMakeFormBool("Generate makefiles", &genMakefiles));
  form->Add(wxMakeFormBool("Generate RC file", &genRCFile));
  form->Add(wxMakeFormBool("Generate DEF file", &genDefFile));
  form->Add(wxMakeFormNewLine());
  form->Add(wxMakeFormBool("Generate wxWindows resources", &useResourceMethod));

/*** NOT YET IMPLEMENTED
  form->Add(wxMakeFormNewLine());

  form->Add(wxMakeFormBool("Generate separate file per window", &separateFiles));
*/

  form->AssociatePanel(dialog);
  form->dialog = dialog;

  dialog->Fit();
  dialog->Centre(wxBOTH);

  wxEndBusyCursor();
  dialog->Show(TRUE);
}

Bool BuildApp::WritePrologAttributes(PrologExpr *expr, PrologDatabase *database)
{
  expr->AddAttributeValue("wxbuilder_version", buildVersion);
#if !defined(AIXV3)
  expr->AddAttributeValue("revision", (long)revision);
  {
    time_t now = time(NULL);
    char *date = ctime(&now); 
    date[24] = '\0';
    expr->AddAttributeValueString("updated", date);
  }
#endif
  if (topLevelFrame)
    expr->AddAttributeValue("top_level_frame", topLevelFrame->id);
  if (buildName)
    expr->AddAttributeValueString("name", buildName);
  if (buildDescription)
    expr->AddAttributeValueString("description", buildDescription);
  if (buildAuthors)
    expr->AddAttributeValueString("authors", buildAuthors);
  if (buildDate)
    expr->AddAttributeValueString("date", buildDate);
  if (projectDirDOS)
    expr->AddAttributeValueString("project_dir_dos", projectDirDOS);
  if (projectDirUNIX)
    expr->AddAttributeValueString("project_dir_unix", projectDirUNIX);
  if (commandLine)
    expr->AddAttributeValueString("command_line", commandLine);

  expr->AddAttributeValue("generate_makefiles", (long)genMakefiles);
  expr->AddAttributeValue("generate_rc_file", (long)genRCFile);
  expr->AddAttributeValue("generate_def_file", (long)genDefFile);
  expr->AddAttributeValue("generate_separate_files", (long)separateFiles);
  expr->AddAttributeValue("use_resources", (long)useResourceMethod);
  
  expr->AddAttributeValue("mdi", (long)buildMDIType);
  if (extensionCPP)
    expr->AddAttributeValueString("extension", extensionCPP);
  return TRUE;
}

Bool BuildApp::ReadPrologAttributes(PrologExpr *expr, PrologDatabase *database)
{
  expr->AssignAttributeValue("top_level_frame", &topLevelFrameId);
  expr->AssignAttributeValue("name", &buildName);
  expr->AssignAttributeValue("description", &buildDescription);
  expr->AssignAttributeValue("authors", &buildAuthors);
  expr->AssignAttributeValue("date", &buildDate);
  expr->AssignAttributeValue("project_dir_dos", &projectDirDOS);
  expr->AssignAttributeValue("project_dir_unix", &projectDirUNIX);
  expr->AssignAttributeValue("command_line", &commandLine);
  expr->AssignAttributeValue("generate_makefiles", &genMakefiles);
  expr->AssignAttributeValue("generate_rc_file", &genRCFile);
  expr->AssignAttributeValue("generate_def_file", &genDefFile);
  expr->AssignAttributeValue("generate_separate_files", &separateFiles);
  expr->AssignAttributeValue("use_resources", &useResourceMethod);
  expr->AssignAttributeValue("mdi", &buildMDIType);
  expr->AssignAttributeValue("extension", &extensionCPP);
  expr->AssignAttributeValue("revision", &revision);
  revision++; /* increment */
  
  return TRUE;
}

Bool BuildApp::SaveProject(char *filename)
{
  if (filename && !projectFilename)
    projectFilename = copystring(filename);
    
  if (!filename || !projectFilename)
  {
    char *file = wxFileSelector("Select a project file to save to", PathOnly(projectFilename),  FileNameFromPath(projectFilename), "wxp", "*.wxp");
    if (file && *file)
    {
      projectFilename = copystring(file);
    }
    else return FALSE;
  }
  if (projectFilename)
  {
    wxBeginBusyCursor();

    char buf[300];
    sprintf(buf, "wxBuilder [%s]", FileNameFromPath(projectFilename));
    MainFrame->SetTitle(buf);

    PrologDatabase database;

    // First write the project header
    PrologExpr *clause = new PrologExpr("project");
    WritePrologAttributes(clause, &database);
    database.Append(clause);

    // Now all the top-level windows
    wxNode *node = topLevelWindows.First();
    while (node)
    {
      BuildWindowData *win = (BuildWindowData *)node->Data();

      win->WriteRecursively(&database);
      node = node->Next();
    }
    TheFontManager.WriteFonts(&database);
    
    ofstream stream(projectFilename);
    database.WriteProlog(stream);
    MakeModified(FALSE);
    AddFileToHistory(projectFilename);

    wxEndBusyCursor();
  }
  else return FALSE;

  return TRUE;
}

Bool BuildApp::LoadProject(char *f, Bool interactive)
{
  if (interactive)
    if (Modified())
      if (wxNO == wxMessageBox("Discard modified project?", "Please confirm", wxYES_NO))
        return FALSE;

  char filename[256];
  filename[0] = 0;
  if (f) strcpy(filename, f);
  if (interactive)
  {
    char *file = wxFileSelector("Select a project file to load from", PathOnly(filename),  FileNameFromPath(filename), "wxp", "*.wxp");
    if (file)
    {
      strcpy(filename, file);
    }
    else return FALSE;
  }

  if (strlen(filename) > 0)
  {
    // Create a database hashing on the "id" attribute,
    // so we can quickly find structures we've built up so far.
    PrologDatabase database(PrologInteger, "id");

    wxBeginBusyCursor();

    if (!database.ReadProlog(filename))
    {
      wxEndBusyCursor();
      wxMessageBox("Could not load file.", "Error");
      return FALSE;
    }
    TheFontManager.Show(FALSE);
    database.BeginFind();
    PrologExpr *header = database.FindClauseByFunctor("project");
    if (!header)
    {
      wxEndBusyCursor();
      wxMessageBox("Not a valid project file.", "Error");
      return FALSE;
    }
    ReadPrologAttributes(header, &database);

    // Only now clear the current project, when we're more
    // confident of progressing.
    ClearProject();
    if (projectFilename) delete[] projectFilename;
    projectFilename = copystring(filename);

    // Find all the menus
    database.BeginFind();
    PrologExpr *expr = database.FindClauseByFunctor("menu_item");
    while (expr)
    {
      long parentId = 0;
      long id = 0;

      BuildMenuItem *item = new BuildMenuItem;
      item->ReadPrologAttributes(expr, &database);
      expr->AssignAttributeValue("parent", &parentId);
      expr->AssignAttributeValue("id", &id);
      RegisterId(id);
      expr->SetClientData(item);

      PrologExpr *parentExpr = database.HashFind("menu_item", parentId);
      if (parentExpr)
      {
        item->parent = (BuildMenuItem *)parentExpr->GetClientData();
        if (item->parent)
          item->parent->menus.Append(item);
      }

      expr = database.FindClauseByFunctor("menu_item");
    }

    // Find all the windows
    database.BeginFind();
    expr = database.FindClauseByFunctor("window");
    while (expr)
    {
      int windowType = 0;
      long parentId = 0;
      int id = 0;
      expr->AssignAttributeValue("type", &windowType);
      expr->AssignAttributeValue("parent", &parentId);
      expr->AssignAttributeValue("id", &id);
      RegisterId(id);

      switch (windowType)
      {
        case wxTYPE_FRAME:
        {
          BuildFrameData *data = new BuildFrameData(NULL);
          expr->SetClientData(data);
          
          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);

          if (topLevelFrameId == data->id)
            topLevelFrame = data;
          topLevelWindows.Append(data);

          // Add menu bar
          int menuBarId = 0;
          expr->AssignAttributeValue("menu_bar", &menuBarId);
          PrologExpr *menuExpr = database.HashFind("menu_item", menuBarId);
          if (menuExpr)
          {
            BuildMenuItem *menuBar = (BuildMenuItem *)menuExpr->GetClientData();
            if (menuBar)
            {
              delete data->buildMenuBar;
              data->buildMenuBar = menuBar;
            }
          }

          // Add toolbar
          int toolBarId = 0;
          expr->AssignAttributeValue("tool_bar", &toolBarId);
          PrologExpr *toolbarExpr = database.HashFind("window", toolBarId);
          if (toolbarExpr)
          {
            BuildToolbarData *toolBar = (BuildToolbarData *)toolbarExpr->GetClientData();
            if (toolBar)
            {
              data->toolbar = toolBar;
              toolBar->buildParent = data;
            }
          }
          break;
        }
        case wxTYPE_DIALOG_BOX:
        {
          BuildDialogBoxData *data = new BuildDialogBoxData(NULL);
          expr->SetClientData(data);
          
          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);

          topLevelWindows.Append(data);

          break;
        }
        case wxTYPE_PANEL:
        {
          BuildFrameData *parentFrame = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentFrame = (BuildFrameData *)parentExpr->GetClientData();

          if (!parentFrame)
          {
            wxMessageBox("Subwindow has no parent frame!", "Error");
            break;
          }

          BuildPanelData *data = new BuildPanelData(parentFrame);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);

          break;
        }
        case wxTYPE_CANVAS:
        {
          BuildFrameData *parentFrame = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentFrame = (BuildFrameData *)parentExpr->GetClientData();

          if (!parentFrame)
          {
            wxMessageBox("Subwindow has no parent frame!", "Error");
            break;
          }

          BuildCanvasData *data = new BuildCanvasData(parentFrame);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);

          break;
        }
        case wxTYPE_TEXT_WINDOW:
        {
          BuildFrameData *parentFrame = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentFrame = (BuildFrameData *)parentExpr->GetClientData();

          if (!parentFrame)
          {
            wxMessageBox("Subwindow has no parent frame!", "Error");
            break;
          }

          BuildTextWindowData *data = new BuildTextWindowData(parentFrame);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);

          break;
        }
        case wxTYPE_BUTTON:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildButtonData *data = new BuildButtonData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_CHECK_BOX:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildCheckBoxData *data = new BuildCheckBoxData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_MESSAGE:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildMessageData *data = new BuildMessageData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_TEXT:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildTextData *data = new BuildTextData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_MULTI_TEXT:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildMultiTextData *data = new BuildMultiTextData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_LIST_BOX:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildListBoxData *data = new BuildListBoxData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_RADIO_BOX:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildRadioBoxData *data = new BuildRadioBoxData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_SLIDER:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildSliderData *data = new BuildSliderData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_GAUGE:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildGaugeData *data = new BuildGaugeData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_GROUP_BOX:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildGroupBoxData *data = new BuildGroupBoxData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_TOOLBAR:
        {
          // Parent will be assigned later
          BuildToolbarData *data = new BuildToolbarData(NULL, FALSE);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        case wxTYPE_CHOICE:
        {
          BuildPanelData *parentPanel = NULL;
          PrologExpr *parentExpr = database.HashFind("window", parentId);
          if (parentExpr)
            parentPanel = (BuildPanelData *)parentExpr->GetClientData();

          if (!parentPanel)
          {
            wxMessageBox("Panel item has no parent panel!", "Error");
            break;
          }

          BuildChoiceData *data = new BuildChoiceData(parentPanel);
          expr->SetClientData(data);

          data->ReadPrologAttributes(expr, &database);
          data->ReadActions(expr, &database);
          break;
        }
        default:
        {
          wxMessageBox("Unrecognised window type.", "Error");
          break;
        }
      }
      expr = database.FindClauseByFunctor("window");
    }
    ResolveActionReferences(&database);
    TheFontManager.ReadFonts(&database);
    char buf[300];
    sprintf(buf, "wxBuilder [%s]", FileNameFromPath(filename));
    MainFrame->SetTitle(buf);
    UpdateWindowList(topLevelFrame);

    // Add to the project file history
    AddFileToHistory(filename);

    buildApp.ShowObjectEditor(topLevelFrame);

    wxEndBusyCursor();
  }
  else return FALSE;
  return TRUE;
}

void BuildApp::ResolveActionReferences(PrologDatabase *database)
{
  // Find all the windows
  database->BeginFind();
  PrologExpr *expr = database->FindClauseByFunctor("window");
  while (expr)
  {
    BuildWindowData *win = (BuildWindowData *)expr->GetClientData();
    if (win)
    {
      wxNode *node = win->buildActions.First();
      while (node)
      {
        BuildAction *action = (BuildAction *)node->Data();
        if (action->actionWindowId > -1)
        {
          PrologExpr *winExpr = database->HashFind("window", action->actionWindowId);
          if (winExpr)
            action->actionWindow = (BuildWindowData *)winExpr->GetClientData();
        }
        node = node->Next();
      }
    }
    expr = database->FindClauseByFunctor("window");
  }
}

Bool BuildApp::ClearProject(void)
{
  wxNode *node = topLevelWindows.First();
  while (node)
  {
    BuildWindowData *data = (BuildWindowData *)node->Data();
    DeleteWindow(data);
    node = topLevelWindows.First();
  }
  ClearTree();
  if (projectFilename) delete[] projectFilename;
  projectFilename = NULL;
  MainFrame->SetTitle("wxBuilder [unnamed]");
  MakeModified(FALSE);
  return TRUE;
}

Bool BuildApp::Modified(void)
{
/*
  if (topLevelFrame || (topLevelWindows.Number() > 0))
    return TRUE;
  else
    return FALSE;
 */
 return isModified;
}

// Format panel items
Bool BuildApp::FormatItems(int formatTool)
{
  if (BuildSelections.Number() == 0)
  {
    wxMessageBox("Please select panel items to format", "Warning");
    return FALSE;
  }
  // Ensure all panel items have the same parent
  BuildWindowData *parent = NULL;
  wxNode *node = BuildSelections.First();
  while (node)
  {
    BuildWindowData *data = (BuildWindowData *)node->Data();
    if (!parent)
      parent = data->buildParent;
    if ((!data->buildParent) ||
        (!wxSubType(data->buildParent->windowType, wxTYPE_PANEL)) ||
        (data->buildParent != parent))
    {
      wxMessageBox("Selections must be panel items and have same parent.", "Error");
      return FALSE;
    }
    node = node->Next();
  }

  BuildWindowData *first = GetFirstSelection();
  int firstX, firstY;
  int firstW, firstH;
  first->userWindow->GetPosition(&firstX, &firstY);
  first->userWindow->GetSize(&firstW, &firstH);
  int centreX = (int)(firstX + (firstW / 2));
  int centreY = (int)(firstY + (firstH / 2));

  node = BuildSelections.First();
  while (node)
  {
    BuildWindowData *win = (BuildWindowData *)node->Data();
    wxNode *next = node->Next();
    if (win->userWindow && (win != first))
    {
      int x, y, w, h;
      win->userWindow->GetPosition(&x, &y);
      win->userWindow->GetSize(&w, &h);

      int newX, newY;

      switch (formatTool)
      {
        case TOOLBAR_FORMAT_HORIZ:
        {
          newX = x;
          newY = (int)(centreY - (h/2.0));
          break;
        }
        case TOOLBAR_FORMAT_VERT:
        {
          newX = (int)(centreX - (w/2.0));
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN:
        {
          newX = firstX;
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_VERT_TOP_ALIGN:
        {
          newX = x;
          newY = firstY;
          break;
        }
        case TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN:
        {
          newX = firstX + firstW - w;
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_VERT_BOT_ALIGN:
        {
          newX = x;
          newY = firstY + firstH - h;
          break;
        }
        default:
          newX = x; newY = y;
          break;
      }

      win->userWindow->SetSize(newX, newY, w, h);
    }
    node = next;
  }
  if (parent && parent->userWindow && wxSubType(parent->userWindow->__type, wxTYPE_PANEL))
  {
    wxPanel *panel = (wxPanel *)parent->userWindow;
    panel->GetPanelDC()->Clear();
    panel->Refresh();
  }

  return TRUE;
}

void BuildApp::AssociateObjectWithEditor(BuildWindowData *bwin)
{
  if (MainFrame->currentWindow == bwin)
    return;
  MainFrame->ClearEditor();
  MainFrame->currentWindow = bwin;
}

void BuildApp::DisassociateObjectWithEditor(BuildWindowData *bwin)
{
  if (!MainFrame)
    return;
    
  if (MainFrame->currentWindow != bwin)
    return;

  DeselectAll();
  
  MainFrame->ClearEditor();
  MainFrame->currentWindow = NULL;
}

Bool BuildApp::ShowObjectEditor(BuildWindowData *bwin)
{
  if (!bwin->userWindow)
    bwin->MakeRealWindow();
  if (!bwin->userWindow)
    return FALSE;
  
  if (MainFrame)
  {
    AssociateObjectWithEditor(bwin);
    MainFrame->Show(TRUE);
    EditorPaletteFrame->Show(TRUE);
    bwin->userWindow->Show(TRUE);
    DisplayTree(TRUE, bwin);
  }
  return TRUE;
}

void BuildApp::UpdateWindowList(BuildWindowData *bwin)
{
  MainFrame->buildWindowsItem->Clear();
  wxNode *node = topLevelWindows.First();
  while (node)
  {
    BuildWindowData *win = (BuildWindowData *)node->Data();
    MainFrame->buildWindowsItem->Append(win->name, (char *)win);
    node = node->Next();
  }

  if (bwin)
  {
    int sel = MainFrame->buildWindowsItem->FindString(bwin->name);
    if (sel > -1)
      MainFrame->buildWindowsItem->SetSelection(sel);
  }
#ifdef wx_x
/*
  // wxListBox needs to be resized or it doesn't appear
  // under Motif! Maybe SetSelection contains the bug?
  // See fix in wxListBox::Append which may need to be
  // repeated elsewhere.
  int toolbarHeight = 28;
    
  int listW, listH, listX, listY;
  MainFrame->buildWindowsItem->GetSize(&listW, &listH);
  MainFrame->buildWindowsItem->GetPosition(&listX, &listY);
  int panelW = listW + 5;
  int panelH = listH + listY + 5;

  int frameW, frameH;
  MainFrame->GetClientSize(&frameW, &frameH);
  int canvasH = frameH - panelH - toolbarHeight;

  MainFrame->buildWindowsItem->SetSize(listX, listY, frameW - listX - 5, listH);
//  panel->SetSize(0, toolbarHeight+canvasH, frameW, panelH);
*/
#endif
}

BuildWindowData *BuildApp::FindCurrentWindow(void)
{
  int sel = MainFrame->buildWindowsItem->GetSelection();
  if (sel > -1)
  {
    BuildWindowData *win = (BuildWindowData *)MainFrame->buildWindowsItem->GetClientData(sel);
    return win;
  }
  else return NULL;
}

// Delete an arbitrary window object
Bool BuildApp::DeleteWindow(BuildWindowData *window)
{
  if (window == topLevelFrame)
    topLevelFrame = NULL;

  if (MainFrame && (MainFrame->currentWindow == window))
  {
    MainFrame->canvas->Clear();
  }

  window->DestroyRealWindow();
  topLevelWindows.DeleteObject(window);
  delete window;

  UpdateWindowList();
  MakeModified();

  return TRUE;
}


void BuildApp::CreateObjectMenu(void)
{
  objectMenu = new wxMenu(NULL, (wxFunction)ObjectMenuProc);
  objectMenu->Append(WXBUILD_OBJECT_MENU_EDIT, "Edit attributes");
  objectMenu->Append(WXBUILD_OBJECT_MENU_DELETE, "Delete object");
}

void ObjectMenuProc(wxMenu& menu, wxCommandEvent& event)
{
  BuildWindowData *data = (BuildWindowData *)menu.GetClientData();
  if (!data)
    return;

  switch (event.commandInt)
  {
    case WXBUILD_OBJECT_MENU_EDIT:
    {
      data->EditAttributes();
      data->DestroyRealWindow();
      data->MakeRealWindow();
      break;
    }
    case WXBUILD_OBJECT_MENU_DELETE:
    {
      if (data == MainFrame->currentWindow)
      {
        buildApp.DisassociateObjectWithEditor(MainFrame->currentWindow);
      }
      buildApp.DeleteWindow(data);
      if (MainFrame->currentWindow)
        DisplayTree(TRUE, MainFrame->currentWindow);
      else
        DisplayTree(FALSE, NULL);
      break;
    }
  }
}

