
/**  
  
   Categories
   ----------
  
   v0.10.1i (ENTWICKLUNGS-VERSION)

   Werkzeug zur Anzeige und Bearbeitung von Und/Oder-Baeumen

   Oeffentliche Applet-Klasse AOT ("And/Or Tree")
   
   Copyright (c)1997 Matthias Nickles, Ludwig-Maximilians-Universitaet Muenchen

   All Rights Reserved

   Erstellt im Maerz/April 1997 im Rahmen eines FoPras an der LMU Muenchen 
   am Lehrstuhl von Prof. Dr. F. Bry (Institut fuer Informatik).

   Programmautor: Matthias Nickles (Matthias_Nickles@msn.com
                                    und nicklesm@usa.net)
  
   Aufgabenstellung/Betreuung: Dr. Heribert Schuetz (Heribert.Schuetz@informatik.uni-muenchen.de)
    
   Entwickelt mit MS Visual J++ (Professional Edition mit Compiler v1.01.7022) 
   und Sun JDK (1.0.2)
   unter Windows 95, Linux (Kernel 2.0) und HP-UX 10
   sowie mit dem Parser-Generator JavaCC (v0.6(Beta2)) von Sun.

   Die vorliegende Version von Categories setzt Java 1.0.2 voraus;
   Java 1.1 und hoeher wird nicht unterstuetzt.

   Dokumentation: cats_doc.html, readme

   This program is published WITHOUT ANY WARRANTY; without 
   even the implied warranty of MERCHANTABILITY or FITNESS FOR 
   A PARTICULAR PURPOSE.

   JavaBrowser GNU(c) 1996 by Alexey Goloshubin <s667@ii.uib.no> and Jeremy Cook <jeremy@ii.uib.no>
               GNU(c) 1997 by Matthias Nickles <Matthias_Nickles@msn.com> 
 
   HTTPClient GNU(c)1996, 1997 Ronald Tschalaer 

*/


//package AOT; // dazu muss das uebergeordnete Verzeichnis von AOT im CLASSPATH enthalten sein!


import java.applet.*;

import java.awt.*;

import java.io.*;

import java.net.*;

import java.util.*;

import Document; 

import jb;  // HTML Viewer-Frame

import HTTPClient.*;  // Basisklassen fuer HTTP-Verbindungen


public class AOT extends Applet {

/* *** der Zugriffsmodifizierer "private protected" ist unter J++ 1.0
  leider nicht verfuegbar. Er sollte fast ueberall statt private eingesetzt werden! */

 public static /*final=>Absturz*/ String APPLET_NAME_ABBREVIATION = "Categories";
 
 public static /*final=>Absturz*/ String APPLET_NAME = APPLET_NAME_ABBREVIATION;

 public static final String COPYRIGHT = 
  "(c)1997 University of Munich (LMU)\nInstitute of Computer Science (Heribert.Schuetz@informatik.uni-muenchen.de)";

 public static final String DEVELOPER = 
  "Matthias Nickles (Matthias_Nickles@msn.com)";

 public static final String VERSION = "0.10.1i";


 /** Dateiendung "Baum" */
 public static final String CATEGORIES_FILE_TYPE = "cat"; 
 
 /** Dateiendung "Selektion" */
 public static final String SELECTION_FILE_TYPE = "sel";  


 /** horiz. Ausdehnung des Applets in der HTML-Seite (Aenderungen sind auch in deren Quelltext vorzunehmen) */
 private static int initial_width = 350; 

 /** vert. Ausdehnung des Applets in der HTML-Seite (Aenderungen sind auch in deren Quelltext vorzunehmen) */
 private static int initial_height = 450; 

 /** Parameter-Schluessel: */

 private static final String PARAM_Param1 = "Tree";  
 
 private static final String PARAM_Param2 = "Selection"; 
 
 private static final String PARAM_Param3 = "Access";
 
 private static final String PARAM_Param4 = "Frame";

 private static final String PARAM_Param5 = "User"; 

 private static final String PARAM_Param6 = "Form"; 

 private static final String PARAM_Param7 = "Port"; 

 private static final String PARAM_Param8 = "Host"; 

 private static final String PARAM_Param9 = "Force_cntrl_swap"; 

 private static final String PARAM_Param10 = "Force_config";  // nur zur internen Verwendung


 /** access_mode-Schluessel "Abfrage" (Endanwender) */
 public static final int USER = 0; 

 /** access_mode-Schluessel "voller Zugriff" */
 public static final int SUPERUSER = 1; 


 /** Operationstypen fuer Funktion user_file_operation() */
 public static final int user_file_operation_LOAD_CAT = 0; 

 public static final int user_file_operation_SAVE_CAT = 1; 

 public static final int user_file_operation_LOAD_SEL = 2; 

 public static final int user_file_operation_SAVE_SEL = 3; 

 public static final String[] user_file_operation_MESSAGE = { 
  "Load categories",
  "Save categories",
  "Load selection",
  "Save selection"
 };

 public static final String MODIFY_MESSAGE = "Document may have been changed.\nSave now?";

 public static final String SELECTION_MODIFY_MESSAGE = "Activation state may have been changed.\nSave selection?";


 static String online_documentation = "cats_doc.html"; /* muss sich im aktuellen Verzeichnis befinden, kein Pfad erlaubt! */

 /** HTML-Viewer als externen Prozess oder per class jb (immer fuer Java 1.0.2!) */
 static boolean external_html_viewer = false; 

 /** (relevant wenn external_html_viewer=true)
  HTML-Viewer (z.B. Web-Browser) zur Anzeige der Dokumentation.
  Fuer %s wird ueberall die URL der anzuzeigenden Seite eingesetzt: */
 static String[] html_viewers = {  

  "netscape -remote openURL(%s)",

  "netscape %s",

  "explorer.bat %s"  /* (= Aufrufbatch fuer Microsoft Internet Explorer)*/

 }; /* Achtung: aus technischen Gruenden wird unter Unix immer versucht, ALLE aufgezaehlten
       Programme zu starten!*/
	 

 private static String title;


 static URL doc_file = null;

 private static Process html_proc = null;

 /** interner HTML-Viewer-Kontext (nur falls external_html_viewer=false) */
 static jb current_browser = null;  

 /** Port beim Host zur Kommunikation via communicate_with_host() */
 private static int host_port; // vgl. Parameter 7 (Port=)

 /** URL des Hosts. Wenn nicht im Applet-Modus, wird die Vorgabe hier verwendet */
 private static String host; // vgl. Parameter 8 (Host=)

 
 /** folgende Werte sind leider sehr wichtig in einigen Situationen: */

 public static boolean java_102 = false;
  
 public static boolean GUI_Windows = false;  

 public static boolean BROWSER_Navigator = false;  

 public static boolean INTERPRETER_Jview = false;
 
 public static boolean force_cntrl_swap = false; // *** wenn true, wird auch unter Motif
												 // angenommen, dass kleine Controls grosse verdecken

 public static int config = 0; // Binaerkombination Manipulation von Kommandozeilen-Switches 

 public boolean m_fStandAlone = false;

 public boolean BUFFERED_PAINTING = false;

 /* Parameter/-Vorgabewerte aus HTML-Seite (Applet) oder (indirekt) Kommandozeile (Standalone) uebernehmen
     (werden per Kommandozeile ggf. ueberschrieben): */


 /** Baumtext-Datei, falls diese nicht in der Kommandozeile angegeben wurde */
 private String m_param1 = "demo."+CATEGORIES_FILE_TYPE; 
  
 /** Selektionstext-Datei, falls diese nicht in der Kommandozeile angegeben wurde */
 private String m_param2 = "minimal."+SELECTION_FILE_TYPE; // "minimal.sel": keine Selektion laden
 
 /** Steuerung der Zugriffsbeschraenkung, falls Parameter nicht in der Kommandozeile angegeben wurde */
 private int m_param3 = 0;

 /** Aufrufmodus (als Fenster(yes) oder in HTML-Seite(no)), falls Parameter nicht in der Kommandozeile angegeben wurde */
 private String m_param4 = "no";
  
 /** Datei mit Endanwender-Selektion */
 private String m_param5 = "user."+SELECTION_FILE_TYPE;
  
 /** Formularmodus (als Fenster(yes) oder in HTML-Seite(no)), falls Parameter nicht in der Kommandozeile angegeben wurde */
 private String m_param6 = "no";

 /** Host-Port */
 private int m_param7 = 9002;

 /** URL von Pseudo-Host (wird nur gebraucht, wenn Cats sich nicht im Applet-Modus befindet) */
 private String m_param8 = "";

 /** Erzwingt einen Windows-aehnlichen Darstellungsmodus unter Motif (noetig bei neueren Java-Builds) */
 private String m_param9 = "auto";

 private String m_param10 = "iiiiiiiii";  // i=ignorieren, y=ein, n=aus


 /** Zugriffs-Modus (siehe Applet-Parameter 3 "Access") */
 int access_mode; 

 /** Darstellungs-Modus (siehe Applet-Parameter 4 "Frame") */
 boolean frame_mode; 

 /** Schalter: Formular-Modus (siehe Applet-Parameter 6 "Form") */
 boolean form_mode; 

 /** Datei fuer Endanwender-Selektionen (Parameter 5) */
 String user_selection_file; 

 static String current_directory = null;

 /** Baum (Modell und Darstellung)*/
 Document document = null;  

 /** Zwischenablage (ein Extra-Baum)*/
 Document clipboard = null;  

 /** "Bitte warten" Dialog fuer Startup-Phase */
 public InfoDialog wait = null;

 private Vector history_list = null;

 private int history_list_pos = -1;

 /* Fenster-Komponenten im Applet:*/

 /** optionales Frame zur "anwendungsartigen" Darstellung des Applets (resizeable, Pulldown-Menue usw.)*/
 public ApplicationFrame application = null;  

 /** Fenster, in dem optional das Clipboard dargestellt wird*/
 ClipboardFrame clipboard_frame = null;  

 /** Frame "simuliert" im Standalone-Modus den Browser */
 AOTFrame aotframe = null; 

 /** schaltet zwischen Embedded- und Application-Modus um
    im Embedded-Modus ist das Haupt-Dokument in die HTML-Seite eingebettet, andernfalls ins application-Frame */
 private Button toggle_insertion = null;  

 /** es gibt immer genau ein Applet*/
 static public AOT Aot = null; 

 /** einige AWT-Methoden benoetigen unter Motif immer 
    irgendein first-level Fenster als Bezug*/
 static Frame dummy; 

 /** Sicherheitsmodus: wenn true, unterbleiben einige sicherheitsrelevanten Aktionen. */
 static boolean secure = true; 

  /** dieser Konstruktor oeffnet noch kein Dokumenten-Fenster.
 Dies muss mit init() bewerkstelligt werden */
 public AOT() { 
 
  title = new String(APPLET_NAME);

  Aot = this; /* (es kann nur eines geben)*/

  setBackground(Color.white);

  dummy = new Frame();  /* *** (siehe Status-Bereich)*/

 }


 /** Laed neues Anwender-Dokument, fordert ggf. vorher zur Datensicherung auf. 
 (= Document.open() plus Sicherheitsabfrage) */
 public static void open(Document document, String filename/*null: erfragen*/, boolean any_input) {

  OpenDocumentDialog alert;

  alert = new OpenDocumentDialog(AOT.APPLET_NAME+" Warning", AOT.MODIFY_MESSAGE, InfoDialog.YES|InfoDialog.NO|InfoDialog.CANCEL, document, filename, any_input);

  if(!document.closeable()&&AOT.Aot.access_mode!=AOT.USER&&!document.current_URL(filename)) {

   alert.center(); // Dokument wurde veraendert, daher ggf. sichern

   document.warn_about_empty_or_node(true);

  } else
   alert.open();

 }

 
 /** Liefert aktuelles Hauptdokument */
 public Document get_document() {

  return document;

 }


 public void load_selection(String filename) {

  document.load_selection(filename, true, true);

 } 

 
 /** Eintrag der Parameter, die in der HTML-Seite oder der Kommandozeile (Standalone-Variante) stehen*/
 String GetParameter(String strName, String args[]) {  /* nur fuer Standalone-Version, vgl. getParameter()*/
 
  if(args==null)
   return getParameter(strName); /* Parameter aus HTML-Seite lesen*/

  int i;

  String strArg = strName + "=";
  
  String strValue = null;

  for(i = 0; i<args.length; i++)  { /* Suche nach Argumenten der Form "Arg=Value"*/

   int arglen = strArg.length()<args[i].length()?strArg.length():args[i].length();

   if(strArg.equalsIgnoreCase(args[i].substring(0, arglen))) {

	strValue = args[i].substring(arglen);

 	if(strValue.startsWith("\"")) {

	 strValue = strValue.substring(1);

	 if(strValue.endsWith("\""))
      strValue = strValue.substring(0, strValue.length()-1);

	}

   }

  }
		
  return strValue;

 }


 void GetParameters(String args[]) {  

  String param;

  param = GetParameter(PARAM_Param1, args);

  if(param!=null)
   if(param.trim().length()>0)
    m_param1 = param;

  param = GetParameter(PARAM_Param2, args);

  if(param!=null)
   if(param.trim().length()>0)
    m_param2 = param;

  param = GetParameter(PARAM_Param3, args);

  if(param!=null)
   m_param3 = Integer.parseInt(param);

  param = GetParameter(PARAM_Param4, args);

  if(param!=null)
   m_param4 = param;

  param = GetParameter(PARAM_Param5, args);

  if(param!=null)
   m_param5 = param;

  param = GetParameter(PARAM_Param6, args);

  if(param!=null)
   m_param6 = param;

  param = GetParameter(PARAM_Param7, args);

  if(param!=null)
   m_param7 = Integer.parseInt(param);

  param = GetParameter(PARAM_Param8, args);

  if(param!=null)
   m_param8 = param;

  param = GetParameter(PARAM_Param9, args);

  if(param!=null)
   m_param9 = param;

  param = GetParameter(PARAM_Param10, args);

  if(param!=null)
   m_param10 = param;

 }


 static void print_info(boolean sysinfo, boolean m_fStandAlone) {

  System.out.println("\n"+APPLET_NAME+" v"+VERSION+"\n\nDeveloped by "+DEVELOPER+" for\n\n"+COPYRIGHT+"\n");  

  System.out.println("Java version: "+java_version());

  if(sysinfo)
    System.out.println(
      "System properties:"
     +"\n Java-vendor-specific string: "+System.getProperty("java.vendor")
     +"\n Java vendor URL: "+System.getProperty("java.vendor.url")
     +"\n Java installation directory: "+(!m_fStandAlone?"(unknown for security reasons)":System.getProperty("java.home"))
     +"\n Java class format version number: "+System.getProperty("java.class.version")
     +"\n Java classpath: "+(!m_fStandAlone?"(unknown for security reasons)":System.getProperty("java.class.path"))		
     +"\n Operating system name: "+System.getProperty("os.name")
     +"\n Operating system architecture: "+System.getProperty("os.arch")			
     +"\n Operating system version: "+System.getProperty("os.version")
     +"\n User account name: "+(!m_fStandAlone?"(unknown for security reasons)":System.getProperty("user.name"))			
     +"\n User home directory: "+(!m_fStandAlone?"(unknown for security reasons)":System.getProperty("user.home"))
     +"\n User's current working directory: "+(!m_fStandAlone?"(unknown for security reasons)":System.getProperty("user.dir"))+"\n\n");
 
 }

 
 /** nur relevant fuer Standalone-Version (sonst init())*/
 public static void main(String args[]) { 

  AOT applet_AOT = new AOT();

  applet_AOT.secure = false;

  applet_AOT.m_fStandAlone = true;

  boolean sysinfo = false;

  for(int i = 0; i<args.length; i++)
   if(args[i].equalsIgnoreCase("-sysinfo")) {

    sysinfo = true;

	break;

   }

  print_info(sysinfo, applet_AOT.m_fStandAlone);

  applet_AOT.aotframe = new AOTFrame(AOT.APPLET_NAME);
  
  applet_AOT.GetParameters(args);

  applet_AOT.aotframe.resize(applet_AOT.aotframe.insets().left+applet_AOT.aotframe.insets().right+AOT.initial_width,
                             applet_AOT.aotframe.insets().top+applet_AOT.aotframe.insets().bottom+AOT.initial_height);

  applet_AOT.aotframe.add("Center", applet_AOT);

  applet_AOT.init();

  applet_AOT.start();

  if(applet_AOT.frame_mode)
   applet_AOT.aotframe.resize(160, applet_AOT.aotframe.minimumSize().height);

 }


 static boolean is_java_102() {

  return java_version().startsWith("1.0");
 
 }


 static String java_version() {

  String raw = System.getProperty("java.version")+"                                  ";

  if(raw.startsWith("chapman"))
   return "1.0.2 ("+raw+")";
  else if(raw.startsWith("sbb"))
   return (((Integer.parseInt(raw.substring(4, 6))<5&&Integer.parseInt(raw.substring(10, 12))==97)||Integer.parseInt(raw.substring(10, 12))<97)?"1.0.2":"1.1.1")+" ("+raw+")";
  else if(raw.startsWith("1"))
   return raw;
  else
   return "1.0 or higher (unknown release)";

 }

 /** wird vom AWT und ggf. von main() beim ersten Aufruf des Applets aufgerufen.
 init() erzeugt ein Dokumentenfenster aus einer Datei mit der Textdarstellung
 eines Und-/Oder-Baums. Vorher muss das Applet natuerlich mit dem Konstruktor
 AOT() eingerichtet werden. Exemplarisch ist die Verwendung von init()
 in main() zu sehen.*/
 public void init() {

  wait = new InfoDialog("Loading...", 
	   AOT.APPLET_NAME+" "+AOT.VERSION+"\n"+AOT.COPYRIGHT+"\nDeveloper: "+AOT.DEVELOPER+"\nAll rights reserved. This software comes without any warranty!"
       , 0, null);  // nicht zu viele Zeilen, da Linux sonst vom Anwender Positionierung verlangt!

  wait.center();

  if(!m_fStandAlone) {

   print_info(true, false);

   System.out.println("Applet code base: "+getCodeBase()+"\n");

   System.out.println("Document base: "+getDocumentBase()+"\n");

  }

  java_102 = is_java_102();

  BROWSER_Navigator = System.getProperty("java.vendor").indexOf("Netscape")>=0;

  GUI_Windows = System.getProperty("os.name").startsWith("Windows");

  INTERPRETER_Jview = System.getProperty("java.vendor").indexOf("Microsoft")>=0;

  resize(initial_width, initial_height);
	  
  if(!m_fStandAlone) 
   GetParameters(null);  /* Parameter aus HTML-Seite lesen */

  access_mode = m_param3;

  frame_mode = m_param4.equalsIgnoreCase("yes");

  form_mode = m_param6.equalsIgnoreCase("yes");

  host_port = m_param7;

  if(m_param8.length()>0||m_fStandAlone)
   host = m_param8;
  else
   host = new String(getCodeBase().getHost());

  BUFFERED_PAINTING = false; //!form_mode; *** fkt. z.Zt. nicht (warum?)

  // Force_config; ueberschreibt ggfs. fast alles:

  if(m_param10.charAt(0)=='y') //Java 1.0?
   java_102 = true;
  else if(m_param10.charAt(0)=='n') 
   java_102 = false;
  else
   m_param10 = (java_102?'y':'n')+m_param10.substring(1);

  if(m_param10.charAt(1)=='y') //Navigator?
   BROWSER_Navigator = true;
  else if(m_param10.charAt(1)=='n') 
   BROWSER_Navigator = false;
  else
   m_param10 = m_param10.substring(0, 1)+(BROWSER_Navigator?'y':'n')+m_param10.substring(2);

  if(m_param10.charAt(2)=='y') //Jview?
   INTERPRETER_Jview = true;
  else if(m_param10.charAt(2)=='n') 
   INTERPRETER_Jview = false;
  else
   m_param10 = m_param10.substring(0, 2)+(INTERPRETER_Jview?'y':'n')+m_param10.substring(3);
    
  if(m_param10.charAt(3)=='y') //Windows?
   GUI_Windows = true;
  else if(m_param10.charAt(3)=='n') 
   GUI_Windows = false;
  else
   m_param10 = m_param10.substring(0, 3)+(GUI_Windows?'y':'n')+m_param10.substring(4);

  if(m_param10.charAt(4)=='y') //Hintergrundspeicher fuer Graphikdarstellung?
   BUFFERED_PAINTING = true;
  else if(m_param10.charAt(4)=='n') 
   BUFFERED_PAINTING = false;
  else
   m_param10 = m_param10.substring(0, 4)+(BUFFERED_PAINTING?'y':'n')+m_param10.substring(5);

  if(m_param9.equalsIgnoreCase("auto")) { 
  // Notwendigkeit, Controls in InplaceLayout umzudrehen, automatisch feststellen:

   if((GUI_Windows||!java_102)&&BROWSER_Navigator)  //*** folgende Pruefung basiert auf Erfahrungswerten; eine echte autom. Erkennungsmgl. ist nicht bekannt
    force_cntrl_swap = false;
   else if(INTERPRETER_Jview||!java_102||GUI_Windows&&java_102)
    force_cntrl_swap = true;
   else
    force_cntrl_swap = false;
   
  } else
   force_cntrl_swap = m_param9.equalsIgnoreCase("yes");

  if(m_param10.charAt(5)=='y') //Inplace-Controls umgekehrt in Container setzen?
   force_cntrl_swap = true;
  else if(m_param10.charAt(5)=='n') 
   force_cntrl_swap = false;
  else
   m_param10 = m_param10.substring(0, 5)+(force_cntrl_swap?'y':'n')+m_param10.substring(6);

  View.allow_inplace = form_mode;

  if(!BUFFERED_PAINTING) { 

   View.buffered_painting = false;

   View.scrollable = false;

  }

  if(!java_102)
   System.out.println("\nWarning: Incompatible Java version\n");

  if(APPLET_NAME.indexOf(" viewer")<0&&APPLET_NAME.indexOf(" editor")<0)
   APPLET_NAME += access_mode<SUPERUSER?" viewer":" "/* " editor"*/;

  System.out.println("\nSystem configuration string: "+m_param10);

  System.out.println("                             ||||||__Controls swap");
  System.out.println("                             |||||___Buffered painting");
  System.out.println("                             ||||____found Windows");
  System.out.println("                             |||_____found Jview");
  System.out.println("                             ||______found Navigator");
  System.out.println("                             |_______found Java 1.0\n");
   
  System.out.println("Access mode: "+(access_mode==SUPERUSER?"Superuser":"Customer")+"\n");  
  
  System.out.println("View mode: "+(form_mode?"Form":"Simple")+" "+(frame_mode?"frame":"")+"\n");  

  document = new Document(m_param1);  /* Baum aus .cat-Datei lesen und parsen*/

  set_title(m_param1);

  toggle_insertion = new Button("Frame..."); /* schaltet Applet zw. HTML- und Anwendungsmodus um*/

  insert_document(frame_mode); /* Dokument document ins Applet-Panel (d.h. in die HTML-Seite) integrieren */

  clipboard = new Document("clipboard."+CATEGORIES_FILE_TYPE);

  if(frame_mode) {

   /* Darstellung in eigenem First-Order-Fenster ("Anwendungs"-modus)*/

   detach_document();

  }

  if(m_param2.length()>0&&!m_param2.startsWith("minimal."))
   document.load_selection(m_param2, false, false); /* Default-Aktivierungszustand festlegen (optional)*/

  user_selection_file = m_param5;

  if(!INTERPRETER_Jview/*GUI_Windows*/&&form_mode) { // *** aus unbekanntem Grund braucht's das:

   document.view.reshaped();

   try {

    document.view.canvas.just_paint();

   } catch(Exception e) {}

  }

  if(application!=null) {

   application.resize(application.bounds().width+1, application.bounds().height+1);

   application.layout();

  }

  if(wait!=null) {

   wait.dispose();  

   wait = null;

  }

 }


 /** diese Infos koennen nicht alle Browser lesen: */
 public String getAppletInfo() { 

  return "Name: "+APPLET_NAME+"\r\n"+
         "Author: "+DEVELOPER+"\r\n"+
		 "Copyright: "+COPYRIGHT+"\r\n"+
         "Version: "+VERSION+"\r\n";
 }


 /** diese Tabelle kann nicht jeder Browser lesen: */
 public String[][] getParameterInfo() { 

  String[][] info = {
			{ PARAM_Param1, "String", "Categories file (."+CATEGORIES_FILE_TYPE+")" },
			{ PARAM_Param2, "String", "Selection file (."+SELECTION_FILE_TYPE+")" },
			{ PARAM_Param3, "int",    "Access Mode (key)" },
			{ PARAM_Param4, "String", "Open diagram in frame (no/yes)" },
			{ PARAM_Param5, "String", "User selection backup file (."+SELECTION_FILE_TYPE+")" },
			{ PARAM_Param6, "String", "Form mode (no/yes)" },
			{ PARAM_Param7, "int",    "CATTP port number" },
			{ PARAM_Param8, "String", "Host URL" },
			{ PARAM_Param9, "String", "Force controls swap (no/yes)" },
			{ PARAM_Param10,"String", "Force configuration ((i|y|n)+)" }

  };

  return info;		

 }

 /** Anwender nach Dateinamen fragen und Datei speichern/laden */
 static void user_file_operation(int type/*=user_file_operation_LOAD_CAT/SEL,SAVE_CAT/SEL*/, String defname, Document document, boolean flag1/*jenachdem...*/, boolean flag2) {

  user_file_operation(type, defname, document, flag1, flag2, false);

 }

 /** Anwender nach Dateinamen fragen und Datei speichern/laden */
 static void user_file_operation(int type/*=user_file_operation_LOAD_CAT/SEL,SAVE_CAT/SEL*/, String defname, Document document, boolean flag1/*jenachdem...*/, boolean flag2, boolean any_input) {

  if(AOT.Aot.m_fStandAlone&&!any_input) {

   String filename = inquire_filename(user_file_operation_MESSAGE[type], defname, type==user_file_operation_SAVE_SEL||type==user_file_operation_SAVE_CAT?FileDialog.SAVE:FileDialog.LOAD);

   if(filename!=null) {

    if(type==user_file_operation_SAVE_CAT)
 	 document.save(filename); 
    else if(type==user_file_operation_SAVE_SEL)
     document.save_selection(filename);
    else if(type==user_file_operation_LOAD_CAT)
     document.open(filename, true);
    else if(type==user_file_operation_LOAD_SEL)
     document.load_selection(filename, flag1, flag2);

   } else {
 
    /* keine Fehlermeldung, da dieser Zustand auch Folge von <Cancel> sein kann:
    System.out.println("Improper filename");

    InfoDialog.info(APPLET_NAME+" Error", "Improper filename", InfoDialog.OK, null);
	*/

   }

  } else { // spartanische Variante fuer Applets:

   GetFileNameDialog dialog = new GetFileNameDialog(user_file_operation_MESSAGE[type], defname, type, AOT.Aot.aotframe!=null?AOT.Aot.aotframe:AOT.Aot.application!=null?AOT.Aot.application:AOT.dummy, document, flag1, flag2);

  }

 }

 /** Dateiauswahlbox anzeigen */
 static String inquire_filename(String message, String type, int operation) {

  return inquire_filename(message, type, operation, AOT.Aot.aotframe!=null?AOT.Aot.aotframe:AOT.Aot.application!=null?AOT.Aot.application:AOT.dummy);

 }

 
 static String inquire_filename(String message, String type, int operation, Frame parent) {
 
  return inquire_filename(message, type, operation, parent, System.getProperty("user.dir"));

 }


 /** type ist die Dateiendung der zu erfragenden Datei (z.B. "*.cat")
     oder ein vollstaendiger, vorzugebender Dateinamen.
     operation ist FileDialog.SAVE oder FileDialog.LOAD */
 static String inquire_filename(String message, String type, int operation, Frame parent, String directory) {
  /* *** unter Motif/X-Window fkt. der Dateiauswahl-Dialog nicht richtig (warum??)*/

  if(AOT.Aot.m_fStandAlone) {

   FileDialog file_dialog = new FileDialog(parent, message, operation);

   if(type.indexOf("*")>=0)
    file_dialog.setFilenameFilter(new Filter(type)); // *** wird von Motif ignoriert!

   if(File.separator.equals("/")) // *** Motif zeigt keine brauchbaren Wildcards
    file_dialog.setDirectory(directory); //...+File.separator+type+File.separator
   else
    file_dialog.setDirectory(directory);

   file_dialog.setFile(type); // *** wird von Motif ebenfalls ignoriert!

		file_dialog.pack();
		file_dialog.resize(file_dialog.preferredSize().width*2,file_dialog.preferredSize().height);

   file_dialog.setResizable(true);  // *** hat bei den meisten GUIs keinen Effekt

   file_dialog.resize(file_dialog.preferredSize().width*2,file_dialog.preferredSize().height);
  
 	  file_dialog.pack();
	  file_dialog.resize(file_dialog.preferredSize().width*2,file_dialog.preferredSize().height);

   file_dialog.show();

   if(file_dialog.getFile()!=null&&file_dialog.getDirectory()!=null) {

    String fn = file_dialog.getDirectory();

    if(fn.endsWith("/")||fn.endsWith("\\"))
     fn = fn.substring(0, fn.length()-1);

    File file = new File(fn, file_dialog.getFile());

    fn = file.getAbsolutePath(); // Ergebnis kann sich laut Java-Doku. von DialogDirectory+File unterscheiden!

    if(fn.endsWith("*.*"))
     fn = fn.substring(0, fn.length()-4); // *** wg. Fehler im Windows-AWT (???)

    return fn;

   } else
    return null;

  } else {  // für Applets nicht erlaubt!

   System.out.println("Cannot open file dialog within applet");

   InfoDialog.info(APPLET_NAME+" Error", "Cannot open file dialog within applet", InfoDialog.OK, null);

   return null;

  }

 }


 /** wechselt in das Verzeichnis der Datei filename*/
 static void set_dir(String filename) {
 /* (*** Methode "Pfad-Praefix", denn das Wechseln des Systemverzeichnisses fkt. in Java 1.0 nicht)*/

  File file = new File(filename);

  if(!file.isAbsolute())
   file = new File(current_directory, filename);

  if(file!=null)
   current_directory = file.getParent();

 }


 /** Datei zu Datei oder URL in Stringform (lokal bzw. auf Host) oeffnen. */
 static URL get_URL(String filename) { 

  return get_URL(filename, false, false);

 }


 /** Datei zu Datei oder URL in Stringform (lokal bzw. auf Host) oeffnen.
  just_try=true: keine Fehlermeldungen anzeigen, wenn die Datei nicht gefunden wurde*/
 static URL get_URL(String filename, boolean just_try, boolean print_info) { 

  URL url;

  try {

   if(filename.length()>=5&&!filename.substring(0,5).equals("file:")
	  &&!filename.substring(0,5).equals("http:")) {  
	// normaler Dateiname -> URL ;
    // das Praefix file:// ist fuer manche Java-Implementation noetig,
    // damit das URL-Protokoll "Plain Text" erkannt werden kann (z.B. MS-J, aber nicht Sun)

	if(AOT.Aot.m_fStandAlone) {
	
     File file = new File(filename);

     if(!file.isAbsolute()) {

      if(print_info)
	   System.out.println("(directory "+(current_directory==null?(secure?"unknown":System.getProperty("user.dir")):current_directory)+")");

	  file = new File(current_directory, filename);

	 }

     filename = file.getAbsolutePath();

	 if(!java_102&&GUI_Windows)  // Korrektur des DOS-Laufwerksbuchstabens
	  if(filename.charAt(1)==':')
	   filename = "/"+filename.charAt(0)+":"+filename.substring(2);

	 filename = "file://"+filename.replace('\\', '/'); // auch unter DOS!

     url = new URL(filename);  

	} else 
	 url = new URL(AOT.Aot.getDocumentBase(), filename); // Zugriff somit nur ueber Host erlaubt!!

   } else
    url = new URL(filename);  // Applet: filename-Host muss sich von lokalem Host unterscheiden (auch wenn Applet von lokaler Maschine gestartet wurde!)

   if(print_info)
    System.out.println("URL is "+url.toString());
   
  } catch(MalformedURLException url_xcpt) {

   if(!just_try) {

    System.out.println(url_xcpt);

    InfoDialog.info(APPLET_NAME+" Error", "Cannot access URL " + filename +" ("+url_xcpt+")", InfoDialog.OK, null);

   }

   return null;

  }

  return url;

 }


 /** Liest Datei/URL-Inhalt (MIME: plain text) in einen Zwischenpuffer
  Relative Dateipfade beziehen sich auf current_directory.
  Es wird nur ASCII-Zeichencode unterstuetzt, kein Unicode. 
  change_dir=true: in das Verzeichnis von filename wird gewechselt (nur per_URL)*/
 static String read(String filename, boolean per_URL) {
		 
  System.out.println("Reading from "+filename+"..."); 

  InputStream in;

  if(per_URL) {  /* (obligatorisch)*/

   URL url = get_URL(filename, false, false);

   try {

    in = url.openStream();

   } catch(IOException io_xcpt) { /* Datei konnte nicht gelesen werden*/

	System.out.println(io_xcpt.toString());

	if(filename.indexOf("clipboard")<0)
     InfoDialog.info(APPLET_NAME+" Error", "Cannot open " + filename, InfoDialog.OK, null);

    return null;

   }

  } else {  /* (folgender direkter Dateizugriff ist obsolet, nur noch zu Debugging-Zwecken enthalten)*/

   try {
 
    in = new FileInputStream(filename); 
	       
   } catch(IOException io_xcpt) { /* Datei konnte nicht gelesen werden*/

    System.out.println(io_xcpt.toString()); 

	if(filename.indexOf("clipboard")<0)
     InfoDialog.info(APPLET_NAME+" Error", "Cannot open " + filename, InfoDialog.OK, null);

    return null;

   }

  }

  try {
	 
   StringBuffer text = new StringBuffer();

   int b;

    do {

     if((b = in.read())>=0)
      text.append((char)b);

    } while(b>=0);
	 
    System.out.println("Finished"); 

    return text.toString();

  } catch(IOException io_xcpt) { /* Datei konnte nicht gelesen werden*/

    System.out.println(io_xcpt.toString()); 

    InfoDialog.info(APPLET_NAME+" Error", "Cannot read from " + filename, InfoDialog.OK, null);

    return null;

   }
 }

 
 /** Speichert einen String content als Datei.
  Relative Dateipfade beziehen sich auf current_directory.
  Es wird z.Zt. nur ASCII-Zeichencode unterstuetzt, kein Unicode.
  change_dir=true: in das Verzeichnis von filename wird gewechselt*/
 static void save(String filename, String content, boolean per_URL) {
		 
  System.out.println("Writing to " + filename +"..."); 

  OutputStream out;

  if(per_URL&&!AOT.Aot.m_fStandAlone) {  

   URL url = get_URL(filename, false, false);

   try {

/* *** wird von Java z.Zt. (1.0/1.1) noch nicht unterstuetzt:

	URLConnection url_con = url.openConnection();

	url_con.setDoOutput(true);

    out = url_con.getOutputStream();
*/

	System.out.println("Connecting via HTTP to \""+url.getHost()+"\"...");

    HTTPConnection con = new HTTPConnection(url);

    //con.setRawMode(true); //(=Default)

    HTTPResponse rsp = con.Put(url.getFile(), content);

    if(rsp.getStatusCode()>=300) {

	 System.out.println("HTTP connection: received error: "+rsp.getReasonLine());

	 System.out.println(new String(rsp.getData(), 0));

    } else
     System.out.println("Finished"); 

	return;

   } catch(Exception xcpt) { /* Datei konnte nicht ueber HTTP geschrieben werden*/

	System.out.println(xcpt.toString());

    if(filename.indexOf("clipboard")<0)
     InfoDialog.info(APPLET_NAME+" Error", "Cannot open HTTP connection for writing: " + filename, InfoDialog.OK, null);

   /* try { *** ueblicherweise nicht erlaubt:
	 
	 // CGI-Skript aufrufen:

     String script = "http://cgi.cip.informatik.uni-muenchen.de/cgi-bin/user/nickles/nhp-CGIput.cgi";

     HTTPConnection con = new HTTPConnection(script);

     con.Post("nhp-CGIput.cgi", "");
	 
	} catch(Exception io_xcpt) { 

	 System.out.println(io_xcpt.toString());

	 if(filename.indexOf("clipboard")<0)
	  InfoDialog.info(APPLET_NAME+" Error", "Cannot open URL connection for writing: " + filename, InfoDialog.OK, null);

	}
 */

    return;

   }

  } else {

   try {

    File file = new File(filename);

    if(!file.isAbsolute()) {

     System.out.println("(directory "+(current_directory==null?(secure?"unknown":System.getProperty("user.dir")):current_directory)+")");

     file = new File(current_directory, filename);

    }

    out = new FileOutputStream(file);

   } catch(IOException io_xcpt) { /* Datei konnte nicht geschrieben werden*/

    System.out.println(io_xcpt.toString()); 

    InfoDialog.info(APPLET_NAME+" Error", "Cannot access " + filename, InfoDialog.OK, null);

    return;
   
   }

  }

  try {

   for(int i = 0; i<content.length(); i++)
    out.write((int)content.charAt(i));

  } catch(IOException io_xcpt) { /* Datei konnte nicht geschrieben werden*/

   System.out.println(io_xcpt.toString()); 

   InfoDialog.info(APPLET_NAME+" Error", "Cannot write to "+filename, InfoDialog.OK, null);

   return;
   
  }
  
  System.out.println("Finished"); 

 }


 /** Internet Client-Server-Verbindung zum Applet-Host aufbauen und Daten uebertragen.
 Protokoll: CATTP 1.0  (siehe Quellcode-Dokumentation cats_doc.html) */

 String communicate_with_host(String[] process) { //(natuerlich nur im Applet-Modus mgl.)
 // *** Verbesserungsmgl.: Bei folgendem Algo. sollte noch ein Zeitlimit fuer die Server-Antworten gesetzt werden

  boolean error = false;

  String error_msg = null;

  byte[] data = null;

  System.out.println("Connecting to host \""+host+"\", port "+host_port+"...");

  Socket socket = null;

  DataOutputStream out = null;

  DataInputStream in = null;

  try {

   socket = new Socket(host, host_port);

   out = new DataOutputStream(socket.getOutputStream());

   in = new DataInputStream(socket.getInputStream());
   
   if((socket==null||out==null||in==null)) {

	error = true;

    error_msg = "Cannot connect to "+host; 

   } else {

    System.out.println("Connected.");

    for(int i = 0; i<process.length; i++) {

 	 String message;

	 boolean pull = false;  // Datenempfangsmodus

	 if(process[i].startsWith("#")) {  // Token

	  message = process[i].substring(1)+"\n";

      if(message.startsWith("RESET")) { // nur fuer Notfaelle (Server reagiert nicht)

       try {

        System.out.println("Transmitting token: \"CLOSE_CONNECTION\\n\"...");

	    out.writeChars("CLOSE_CONNECTION\n");

 	    out.close();

        in.close();

        socket.close();
 
 	    System.out.println("Connection closed.");

       } catch(Exception xcpt) { 

	    System.out.println("Reset fail. Please try again.");

       }

       return new String("(unknown)");

      }

	  System.out.println("Transmitting token: \""+AOTParse.escapeString(message)+"\"...");

	  out.writeChars(message);

	 } else if(process[i].startsWith("*")) {  // interner Befehl

	  System.out.println("Changing state to: \""+process[i]+"\"...");

	  pull = process[i].equals("*PULL"); // im naechsten Schritt Daten vom Server holen

	  //...

	 } else { // Daten vom Client zum Server senden

	  message = process[i];

	  System.out.println("Transmitting data: \""+AOTParse.escapeString(message.substring(0, Math.min(20,message.length())))+"[...]\" (size: "+message.length()+" bytes)...");

      out.writeInt(message.length()); 

	  out.writeBytes(message);

	 }
     
	 String answer;

     if(pull) {  // Daten empfangen (als Bytefeld)

	  pull = false;

      System.out.println("Downloading data... Please wait.");

      int len = in.readInt();  // Anzahl der nun folgenden Bytes

	  if(len<=0) {

	   error = true;

	   error_msg = "Downloading fail.";

	   out.writeChars("ERROR\nWrong byte count\n");

	  } else {

	   System.out.println("(size: "+len+" bytes)");

       data = new byte[len];

	   in.readFully(data);

	   //(hier fehlt noch der Test, ob data was sinnvolles enthaelt)

	   out.writeChars("OK\n");

	   System.out.println("Downloading complete.");

	  }

	 } else {  // Token empfangen (als String)

 	  System.out.println("Waiting for response...");

      answer = in.readLine(); // Token muss also immer mit \n enden 
 	                          // (dies gilt nicht fuer Daten!)

      if(answer==null) {

	   error = true;

	   error_msg = "Server doesn't respond";

      } else { 
	  
       System.out.println("Response: \""+AOTParse.escapeString(answer)+"\\n\"");

	   if(answer.equals("ERROR")) {

		error = true;

        error_msg = "server: "+in.readLine();

       }
	  
      }

	 }

	 if(error)
	  break;

    }

   }

  } catch(Exception xcpt) {

   error = true;

   error_msg = new String(xcpt.toString());

  }

  if(socket!=null) {

   try {

    System.out.println("Disconnecting...");
	
    if(out!=null) {

     System.out.println("Transmitting token: \"CLOSE_CONNECTION\\n\"...");

	 out.writeChars("CLOSE_CONNECTION\n");

 	 out.close();

	}

	if(in!=null)
     in.close();

    socket.close();

	System.out.println("Connection closed.");

   } catch(Exception xcpt) {

	error = true;
   
	error_msg = new String(xcpt.toString());
   
   }

  }

  System.out.println("Transmission to/from \""+host+"\" \n"+(error?("fail.\nError message: "+error_msg):"was successful.")); 

  InfoDialog.info(APPLET_NAME+" host transfer","Transmission to/from \""+host+"\" \n"+(error?("fail.\nError message: "+error_msg):"was successful."), InfoDialog.OK, null);

  if(error||data==null)
   return new String("(unknown)");
  else
   return new String(data, 0);

 }


 void set_title(String filename) {

  title = AOT.APPLET_NAME;

 }

 
 /* Ereignishandler:*/

 /** falls warn=true, prueft on_quit(), ob das Dokument gesichert werden muss
  andernfalls erfolgte diese Pruefung schon in class QuitDialog*/
 void on_quit(boolean warn) {
  
  if(clipboard!=null)
   if(clipboard.has_been_modified())
    clipboard.save_flat(); 

  if(document!=null) {

   if(warn&&document.has_been_modified()) {

    /* *** so nicht, da mit AWT 1.0 sonst der Thread nicht angehalten wird:
	 QuitDocumentDialog alert = new QuitDocumentDialog(APPLET_NAME+" Warning", MODIFY_MESSAGE, InfoDialog.YES|InfoDialog.NO, this);

     alert.show();
    */

	document.warn_about_empty_or_node(false);

    user_file_operation(user_file_operation_SAVE_CAT, File.separator.equals("\\")?"*."+CATEGORIES_FILE_TYPE:document.name(), document, false, false);

   }

   if(document.selection_has_been_modified()) {
   /* nur im Endanwender-Modus */

    user_file_operation(user_file_operation_SAVE_SEL, user_selection_file, document, false, false);
	
   }

  }

  System.out.println("\nClosing applet...");  

 }


 /** liefert die Textdarstellung ("Quellcode") des Baums im Hauptdokument */
 public String get_tree() {

  return document.source.text;
 
 }

 /** Uebersetzung eines Und-/Oder-Baums (zeigt im Dokumentenfenster einen neuen Und-/Oder-Baum an) */
 public void load_tree(String text) {

  document.source.parse(text);
 
 }
 
 /** wird nach stop() vom Browser aufgerufen*/
 public void destroy() {  } 


 public void paint(Graphics g)	{

  if(application==null)
   g.drawString("Could not display categories tree yet...", 10, 130);
  else
   g.drawString("Push <Catch> to integrate the tree into this page", 10, 60);
  
 }


 /** Aufruf wenn HTML-Seite mit Applet (erneut) sichtbar wird;
  zeitgleich startet auch der einzige Thread; vgl. stop()*/
 public void start() {  
 
  if(!m_fStandAlone)
   showStatus(APPLET_NAME);

 }
	
	
 /** Webseite mit Aot wird geschlossen*/
 public void stop() {  

  on_quit(true);
 
 }


 public boolean action(Event e, Object arg) {
   
  if(e.id==Event.ACTION_EVENT&&e.target==toggle_insertion) {  /* Button "Frame"/"Catch" angeklickt:*/
    
   if(application==null) {  /* Dokument aus dem Applet herausloesen*/
						    /* und in einem eigenen "Anwendungs-"fenster anzeigen*/

	detach_document();

   } else { /* (retour)*/

    document = application.document;

    application.dispose();

    application = null;

	if(clipboard_frame!=null) {

	 clipboard_frame.dispose();

     clipboard_frame = null;

	}

    insert_document(false);

   }

   return true;

  } else
   return false;

 }


 /** (re-)integriert Haupt-document in die HTML-Seite*/
 void insert_document(boolean detached) { 
 
  removeAll(); /* (*** da der Layout-Manager evtl. fehlerhaft arbeitet, muessen alle Components neu eingesetzt werden)*/
   
  Panel north_row = new Panel();  /* Hilfspanel zur rechtbuendigen Anordnung des Buttons*/

  north_row.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));

  setLayout(new BorderLayout(10, 10));

  toggle_insertion.setLabel("Frame...");

  north_row.add(toggle_insertion);

  add("North", north_row);

  if(!detached)
   add("Center", document.view);

  getParent().hide(); /* *** zwecks Anpassung des documents an die originale Applet-Groesse scheint dies noetig zu sein (pack()=gelegentlicher Absturz)*/

  getParent().show(); 
 
 }
 

 /** Umkehrung zu insert_document()*/
 void detach_document() {

  remove(document.view);

  application = new ApplicationFrame(document);

  toggle_insertion.setLabel("Catch");

 }


static void online_help(String page/* null: Viewer nur in Vordergrund holen*/) {

 online_help(page, null);

}

/** Dokumentation anzeigen bzw. Seite anzeigen (content!=null: statt Datei/URL page den String content anzeigen) */
static void online_help(String page, String content/* null: URL page*/) {

 if(!external_html_viewer||java_102||content!=null) {  // internen HTML-Browser aufrufen

  if(AOT.current_browser==null) {

   System.out.println("Spawning HTML-browser (c96 A. Goloshubin, J. Cook, c97 M. Nickles) \non "+page+"...");
      
   AOT.current_browser = new jb(page, content);

  }

  AOT.current_browser.toFront();

  AOT.current_browser.requestFocus();

  AOT.current_browser.browser.panel1.requestFocus();

  AOT.current_browser.goto_URL(page);

 } else { // externen HTML-Viewer starten:

  /* *** folgendes Verfahren fkt. unter Unix+JDK 1.0 nicht (Fremdprozess laesst sich nicht korrekt starten): */

  int i;  // so nicht wg. fehlerh. AppletStub?: if(AOT.Aot.getAppletContext()!=null) AOT.Aot.getAppletContext().showDocument(AOT.doc_file = AOT.get_URL(urls, false), "_blank"); 

  AOT.doc_file = AOT.get_URL(page==null?AOT.online_documentation:page, false, false);

  String abs_filename = AOT.doc_file.toString();

  if(/*java_102&&*/GUI_Windows)
   if(abs_filename.startsWith("file://"))
    if(abs_filename.indexOf("/",8)==8) /// *** Hack, um DOS-Laufwerksbuchstaben in abs_filename zu korrigieren
     if(abs_filename.charAt(7)>='A'&&abs_filename.charAt(7)<='Z') 
      abs_filename = abs_filename.substring(0,7+1)+":"+abs_filename.substring(8);

  System.out.println("Invoking HTML viewer on "+abs_filename+"..."); 

  for(i = 0; i<AOT.html_viewers.length; i++) {

   String call = new String(AOT.html_viewers[i]);

   for(;;) {

    int j = call.indexOf("%s");

	if(j>=0) 
	 call = call.substring(0, j) + abs_filename + call.substring(j+2);
	else 
	 break;

   }

   try {

	System.out.println("Invoking "+call); 
  
    /*System.out.println("Exit value: "+
		               (*/AOT.html_proc = Runtime.getRuntime().exec(call)/*).exitValue())*/; 

   } catch(IOException io_xcpt) { 

    System.out.println(io_xcpt);

    if(i+1<AOT.html_viewers.length)
	 System.out.println("Trying next..."); 

	continue;
 
   }

   //if(GUI_Windows)
	break;

  }

  }

 }

}


/** Simuliert eine Web-Seite, die das Applet-Panel integriert.
    Wenn gilt AOT.Aot.frame_mode=true, so wird AOTFrame allerdings
    vor dem Anwender versteckt.*/
class AOTFrame extends Frame {

 public AOTFrame(String str) {

  super (str);
 
 }

 public boolean handleEvent(Event evt) {

  switch (evt.id) {
		
   case Event.WINDOW_DESTROY:  /* Shutdown durch Schliessen des Frames*/

    AOT.Aot.on_quit(true);

	dispose();

	System.exit(0);

	return true;

   default:

	return super.handleEvent(evt);

  }			 

 }

}


/** Frame mit Menue, simuliert eine "Anwendung" (mit Pulldownmenue usw.) ausserhalb des Applets*/
class ApplicationFrame extends Frame {

 final static int WIDTH = 640, HEIGTH = 720;  /* initiale Groesse */
	
 final static String LABEL_PATTERN = "                    "; 
 /* auf diese Laenge werden unter Motif die Teilstrings bis zum Tab-Zeichen*/
 /* in Menue-Labels getrimmt.*/

 Document document;

 MenuBar menubar;

 Menu file, selection, edit, edit_paste_at, new_as, edit_move, viewm, help, bookmarks;

 MenuItem new_cat, open_cat, open_url_cat, /*goto_cat,*/ save_cat, saveas_cat, close, print_cat,
		  undo, undo_all, cut, copy, paste, paste_as_first, paste_as_last, 
		  paste_behind, paste_before, replace,
		  clear, delete, move_up, move_down, sort, find,
		  new_branch, new_as_first, new_as_last, 
		  new_behind, new_before, new_alternative,
		  add_bookmark, commentary,
		  props,
          open_clipboard, open_source, open_selsource, collapse, collapse_all, expand, expand_all, activated_only, 
	      load_sel, merge_sel, save_sel, send_sel, del_sel, complete_sel, reset_server, open, enter_text, toggle_activation, reset_activation, constraints,
		  about, online_doc, decision_help;

 /** Button-Leiste oben */
 private Panel north_panel; 

 /** Sub-Panels innerhalb von north_panel */
 private Panel north_left_panel, north_middle_panel, north_right_panel;

 /** Shortcut-Buttons */
 private Button new_file_button, open_button, open_url_button, save_button, reload_button,
  cut_button, copy_button, paste_button, new_button;

 /** Popdown-Comboboxen */ 
 private Choice bookmarks_choice = null, goto_choice = null;

 PopUpWindow popup = null;

 private boolean has_focus; 

 final static String activated_only_label = "Hide inactivated objects"; //(wird mehrfach gebraucht)


 ApplicationFrame() { /*(?)*/ }


 ApplicationFrame(Document document) {

  this.document = document;

  setBackground(Color.white);

  menubar = new MenuBar();

  setMenuBar(menubar);

  /* Im folgenden duerfen Menu-Labels nicht mit Shortcuts ausgestattet
     werden (z.B. &<.> unter Windows), da dies nicht systemuebergreifend fkt.!*/

  file = new Menu("File");

  if(AOT.Aot.access_mode==AOT.SUPERUSER)
   file.add(new_cat = new MenuItem(win2motif_men("New")));

  file.add(open_cat = new MenuItem(win2motif_men("Open...")));

  file.add(open_url_cat = new MenuItem(win2motif_men("Open URL...")));

  file.add(new MenuItem("-"));

  if(AOT.Aot.access_mode==AOT.SUPERUSER) {

   file.add(save_cat = new MenuItem(win2motif_men("Save\tCtrl+S")));

   file.add(saveas_cat = new MenuItem(win2motif_men("Save as...")));
  
   file.add(new MenuItem("-"));

  }

  file.add(print_cat = new MenuItem(win2motif_men("Print")));

  file.add(new MenuItem("-"));

  file.add(close = new MenuItem(win2motif_men("Close")));

  menubar.add(file);

  if(true) {

   edit = new Menu("Edit");

   edit.add(undo = new MenuItem(win2motif_men("Undo")));

   undo.disable();

   edit.add(undo_all = new MenuItem(win2motif_men("Undo all")));

   edit.add(new MenuItem("-"));

   if(AOT.Aot.access_mode==AOT.SUPERUSER) {

    edit.add(cut = new MenuItem(win2motif_men("Cut\tCtrl+X")));

    edit.add(copy = new MenuItem(win2motif_men("Copy\tCtrl+C")));
   
    edit.add(paste = new MenuItem(win2motif_men("Paste\tCtrl+V")));

    edit_paste_at = new Menu("Paste as");

    edit_paste_at.add(paste_as_first = new MenuItem(win2motif_men("...first child")));

    edit_paste_at.add(paste_as_last = new MenuItem(win2motif_men("...last child\tCtrl+V")));

    edit_paste_at.add(paste_before = new MenuItem(win2motif_men("...upper neighbour")));

    edit_paste_at.add(paste_behind = new MenuItem(win2motif_men("...lower neighbour")));
   
    edit.add(edit_paste_at);

    edit.add(delete = new MenuItem(win2motif_men("Delete\tCtrl+D")));

    edit.add(replace = new MenuItem(win2motif_men("Replace\tCtrl+H")));

    edit_move = new Menu("Move");

    edit_move.add(move_up = new MenuItem(win2motif_men("Upward\tCtrl+Up")));

    edit_move.add(move_down = new MenuItem(win2motif_men("Downward\tCtrl+Down")));

    edit.add(edit_move);

    edit.add(sort = new MenuItem(win2motif_men("Sort")));

    edit.add(new MenuItem("-"));

    edit.add(new_branch = new MenuItem(win2motif_men("New...\tCtrl+N")));

    new_as = new Menu("New");

    new_as.add(new_as_first = new MenuItem(win2motif_men("...first child")));

    new_as.add(new_as_last = new MenuItem(win2motif_men("...last child\tCtrl+N")));

    new_as.add(new_before = new MenuItem(win2motif_men("...upper neighbour")));

    new_as.add(new_behind = new MenuItem(win2motif_men("...lower neighbour\tCtrl+L")));
   
    edit.add(new_as);

   }

   edit.add(new_alternative = new MenuItem(win2motif_men("New alternative...")));
   
   if(AOT.Aot.access_mode==AOT.SUPERUSER) {
   
    edit.add(new MenuItem("-"));

    edit.add(props = new MenuItem(win2motif_men("Properties...\tCtrl+Enter")));

    edit.add(open = new MenuItem(win2motif_men("Open..."))); // (dasselbe wie Enter - Edit leaf)
  
   }
											 
   menubar.add(edit);

  }

  viewm = new Menu("View");

  viewm.add(collapse = new MenuItem(win2motif_men("Collapse branch")));

  viewm.add(collapse_all = new MenuItem(win2motif_men("Collapse all")));

  viewm.add(expand = new MenuItem(win2motif_men("Expand branch")));

  viewm.add(expand_all = new MenuItem(win2motif_men("Expand all")));

  viewm.add(activated_only = new MenuItem(win2motif_men(AOT.BROWSER_Navigator?"Toggle visibility of inactivated objects":activated_only_label)));

  viewm.add(new MenuItem("-"));

  viewm.add(find = new MenuItem(win2motif_men("Find\tCtrl+F")));

  if(AOT.Aot.access_mode==AOT.SUPERUSER) {

   viewm.add(new MenuItem("-"));

   viewm.add(open_clipboard = new MenuItem(win2motif_men("Clipboard")));

   viewm.add(open_source = new MenuItem(win2motif_men("Categories text...")));

  }

  viewm.add(open_selsource = new MenuItem(win2motif_men("Selection text...")));

  viewm.add(new MenuItem("-"));

  viewm.add(decision_help = new MenuItem(win2motif_men("Object notes...")));

  menubar.add(viewm);

  selection = new Menu("Selection");

  if(AOT.Aot.access_mode!=AOT.SUPERUSER) {

   selection.add(undo = new MenuItem(win2motif_men("Undo")));

   undo.disable();

   selection.add(new MenuItem("-"));

  }

  selection.add(enter_text = new MenuItem(win2motif_men("Edit leaf..."+(AOT.Aot.access_mode!=AOT.SUPERUSER?"\tCtrl+Enter":"")))); 
   // (^ dasselbe wie Edit - Open)

  selection.add(new MenuItem("-"));

  selection.add(toggle_activation = new MenuItem(win2motif_men("Toggle activation\tEnter")));

  selection.add(reset_activation = new MenuItem(win2motif_men("Reset activations")));

  if(AOT.Aot.access_mode==AOT.SUPERUSER)
   selection.add(constraints = new MenuItem(win2motif_men("Constraints...")));

  selection.add(commentary = new MenuItem(win2motif_men("Enter commentary...\tCtrl+K")));

  selection.add(new MenuItem("-"));

  selection.add(load_sel = new MenuItem(win2motif_men("Load...")));

  selection.add(merge_sel = new MenuItem(win2motif_men("Merge...")));

  bookmarks = new Menu("Bookmarks");

  bookmarks.add(add_bookmark = new MenuItem(win2motif_men("Add current selection")));
 
  bookmarks.add(new MenuItem(win2motif_men("-"))); // zaehlt nicht als "Eintrag"!

  bookmarks.add(new MenuItem("0. Empty selection")); // nicht aendern!! *** mind. zwei Eintraege, sonst Probleme unter Windows

  selection.add(bookmarks);

  selection.add(new MenuItem("-"));

  selection.add(save_sel = new MenuItem(win2motif_men("Save as...")));

  selection.add(send_sel = new MenuItem(win2motif_men("Store at host")));

  selection.add(del_sel = new MenuItem(win2motif_men("Delete at host")));

  selection.add(new MenuItem("-"));

  selection.add(complete_sel = new MenuItem(win2motif_men("Request completion...")));

  selection.add(reset_server = new MenuItem(win2motif_men("Reset server")));

  menubar.add(selection);

  help = new Menu("Help");

  help.add(online_doc = new MenuItem(win2motif_men("Documentation\tF1")));

  help.add(new MenuItem("-"));

  help.add(about = new MenuItem(win2motif_men("About...")));

  menubar.add(help);

  menubar.setHelpMenu(help);

  display(document);

  document.add_bookmarks(this);

 }


 void clear_bookmarks() {

  if(bookmarks!=null)
   for(int i = bookmarks.countItems()-1; i>=3; i--)
    bookmarks.remove(i);

  if(document.view!=null)
   if(bookmarks_choice!=null) 
    if(bookmarks_choice.countItems()>=3) { // (es gibt im AWT 1.0 leider keinen Befehl zum Entfernen eines Eintrags)
    
     Choice prev = bookmarks_choice;

     String first_item = new String(prev.getItem(0)), second_item = new String(prev.getItem(1));

     Container parent = prev.getParent();

     parent.remove(prev);

     bookmarks_choice = new Choice();

     bookmarks_choice.addItem(first_item);

     bookmarks_choice.addItem(second_item);

     parent.add(bookmarks_choice);

     parent.layout();

  //bookmarks_choice.move(bookmarks_choice.bounds().x, bookmarks_choice.bounds().y+2);

   } 

 }  


 void add_bookmark(Bookmark bookmark) {

  String item = bookmarks.countItems()-2+". "+bookmark.name;
  //					    (^ die Zahl dient auch intern als Erkennungsmerkmal!!)

  bookmarks.add(new MenuItem(win2motif_men(item)));

  if(document.view!=null)
   if(bookmarks_choice!=null)
    bookmarks_choice.addItem(item);

 }

 /** Setzt ein fuer Windows gedachtes Menu-Label nach Motif um;
  fkt. nur, wenn unter Motif die Menue-Schriftart nicht proportional ist!*/
 static String win2motif_men(String label) {

  if(!AOT.INTERPRETER_Jview) {  

   StringBuffer result = new StringBuffer(label);

   for(int i = 0; i<result.length(); i++)
    if(result.charAt(i)=='\t') {

     result.setCharAt(i, ' ');

	 result.insert(i, LABEL_PATTERN.substring(0, Math.max(0, LABEL_PATTERN.length()-i)));

    }

   return result.toString();

  } else
   return label;

 }


 /** Haupt-document in "Anwendungs-"fenster integrieren */
 void display(Document document) { 

  add("Center", document.view);

  if(true) {

   north_panel = new Panel();

   north_panel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 3));

   north_panel.setBackground(Color.lightGray);

   north_left_panel = new Panel();

   north_left_panel.setLayout(new FlowLayout(FlowLayout.LEFT, 4, 3));

   north_left_panel.setBackground(Color.lightGray);

   north_middle_panel = new Panel();

   north_middle_panel.setLayout(new FlowLayout(FlowLayout.LEFT, 4, 3));

   north_middle_panel.setBackground(Color.lightGray);

   north_right_panel = new Panel();

   north_right_panel.setLayout(new FlowLayout(FlowLayout.RIGHT, 4, 3));

   north_right_panel.setBackground(Color.lightGray);

   if(AOT.Aot.access_mode==AOT.SUPERUSER&&document!=AOT.Aot.clipboard) {

    new_file_button = new Button(" New ");

    north_left_panel.add(new_file_button);

   }

   if(document!=AOT.Aot.clipboard) {

    open_button = new Button("Open");

    north_left_panel.add(open_button);

    open_url_button = new Button(" URL ");

    north_left_panel.add(open_url_button);

   }

   if(AOT.Aot.access_mode==AOT.SUPERUSER) {

    save_button = new Button("Save");

    north_left_panel.add(save_button);

    if(document!=AOT.Aot.clipboard) {

     cut_button = new Button(" Cut ");

     north_middle_panel.add(cut_button);

     copy_button = new Button("Copy");

     north_middle_panel.add(copy_button);

     paste_button = new Button("Paste");

     north_middle_panel.add(paste_button);

     new_button = new Button(" New ");

     north_middle_panel.add(new_button);

    } else {

     reload_button = new Button("Reload");
 
     north_left_panel.add(reload_button);

    }

   }

   if(document!=AOT.Aot.clipboard) {

    bookmarks_choice = new Choice();

    bookmarks_choice.addItem("Add selection");

    bookmarks_choice.addItem("0. Empty selection"); // *** mind. zwei Eintraege, sonst Probleme unter Windows

    bookmarks_choice.setBackground(Color.lightGray); // *** keine Wirkung unter Windows

    north_right_panel.add(bookmarks_choice);

   }

   north_panel.add(north_left_panel);

   north_panel.add(north_middle_panel);

   north_right_panel.layout();

   north_panel.add(north_right_panel);

   north_panel.layout();

   add("North", north_panel);

  }

  setTitle(AOT.APPLET_NAME+" ["+document.name()+"]");

  pack();

  hide(); /**** (warum noetig?)*/

  resize(640/*WIDTH geht nicht(!!!)*/+1, 720/*HEIGHT*/+1);  /* nach pack(), vor show()!*/

  show();

  document.view.mark_root();

  document.view.canvas.requestFocus();

  validate();


			  resize(641/*WIDTH geht nicht(!!!)*/+1, 721/*HEIGHT*/+1);  /* nach pack(), vor show()!*/


 }

 
 void quit_dialog() {

  QuitDialog alert = new QuitDialog(AOT.APPLET_NAME+" Warning", AOT.Aot.access_mode==AOT.SUPERUSER?AOT.MODIFY_MESSAGE:AOT.SELECTION_MODIFY_MESSAGE, InfoDialog.YES|InfoDialog.NO|InfoDialog.CANCEL, this);

  if(document.has_been_modified()&&document!=AOT.Aot.clipboard)
   alert.center();
  else
   alert._quit();

 }


 void undo_setLabel(String new_label) {

   if(!AOT.BROWSER_Navigator)
	undo.setLabel(new_label);  // *** obskurer Fehler im Netscape Navigator 3.02

 }
	 

 public boolean handleEvent(Event evt) {

  switch(evt.id) {
		
   case Event.WINDOW_DESTROY:  /* nach Schliessen des Anwendungs-Frames */
							   /* Baumdiagramm in HTML-Seite zuruecksetzen*/

    if(evt.target==this) {

	 if(document.has_been_modified()&&document!=AOT.Aot.clipboard) 
   	  document.warn_about_empty_or_node(true); /* ***vor dem Konstruktor-Aufruf!!*/

	 quit_dialog();

	 return true;

	}

	return false;

   case Event.KEY_ACTION:  /* nicht-ASCII Tasten:*/

    evt.arg = "";

	switch(evt.key) {

     case Event.F1:

      evt.id = Event.ACTION_EVENT;

	  evt.target = online_doc;

	  evt.key = 0;

      return handleEvent(evt);      

     case Event.DOWN:

	  if(evt.controlDown()/* Ctrl.. nicht immer mgl.||evt.shiftDown()*/) {

	   evt.id = Event.ACTION_EVENT;

	   evt.target = move_down;

 	   evt.key = 0;

       return handleEvent(evt);      

      }

     case Event.UP:

	  if(evt.controlDown()/* Ctrl.. nicht immer mgl.||evt.shiftDown()*/) {

	   evt.id = Event.ACTION_EVENT;

	   evt.target = move_up;

	   evt.key = 0;

       return handleEvent(evt);      

      }

	 default:

      return super.handleEvent(evt);

	}

   case Event.GOT_FOCUS:

    has_focus = true;

    return super.handleEvent(evt);

   case Event.LOST_FOCUS:

    has_focus = false;

    return super.handleEvent(evt);

   /* Shortcuts:*/

   case Event.KEY_PRESS:  /* ASCII Tasten:*/
 
    evt.arg = "";

	switch(evt.key) {

	 case 0: /* Dummy, um Default-Behandlung von KEY_ACTIONs zu verhindern*/

	  break;

     case '\n':  /* Enter (eine vereinfachte Version davon gibt's im*/
	 /* Eventhandler von class View (fuer den Applet-Frameless-Modus, der ja*/
	 /* kein ApplicationFrame kennt)*/

	  if(evt.controlDown()) {
 
       evt.id = Event.ACTION_EVENT;

	   if(AOT.Aot.access_mode==AOT.SUPERUSER) 
 	    evt.target = props;
	   else
	    evt.target = enter_text;

	  } else {

	   if(has_focus) /* ***wg. eines AWT-Fehlers im Zusammenhang mit Child-Fenstern*/
        document.toggle_activation();
	   else
	    return false;

	  }

	  break;
    
     /*case 127: // Delete (fuehrt zu Problemen mit Textbereichen) */
	 case 'D': case 'd': case 4: if(evt.controlDown()) { // Ctrl-D
     
      evt.id = Event.ACTION_EVENT;

	  evt.target = delete;

	  break;

     } case 'X': case 'x': case 24: if(evt.controlDown()) {  /* Ctrl-X (usw.:)*/
		 
      evt.id = Event.ACTION_EVENT;

	  evt.target = cut;

	  break;

	 } case 'C': case 'c': case 3: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = copy;

	  break;

	 } case 'V': case 'v': case 22: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = paste;

	  break;

	 } case 'H': case 'h': case 8/*(BS)*/: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = replace;

	  break;

	 } case 'N': case 'n': case 14: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = new_branch;

	  break;

	 } case 'L': case 'l': case 12: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = new_behind;

	  break;

	 } case 'F': case 'f': case 6: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = find;

	  break;

	 } case 'S': case 's': case 19: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = save_cat;

	  break;

	 } case 'K': case 'k': case 11: if(evt.controlDown()) {

      evt.id = Event.ACTION_EVENT;

	  evt.target = commentary;

	  break;

	 }

	 default:

      return super.handleEvent(evt);

	}

   case Event.ACTION_EVENT:

	if(evt.target instanceof MenuItem||evt.arg instanceof String||evt.arg instanceof Button) {

     if(undo!=null) {

      undo_setLabel("Undo");  

      undo.disable();

	 }

     if(evt.target==close) {

	  if(document.has_been_modified()&&document!=AOT.Aot.clipboard) 
   	   document.warn_about_empty_or_node(true); /* ***vor dem Konstruktor-Aufruf!!*/

	  quit_dialog();

	 } else if(evt.target==new_cat||evt.target==new_file_button) { 
      /* neues Dokument (.cat) erzeugen*/

 	  NewDocumentDialog alert = new NewDocumentDialog(AOT.APPLET_NAME+" Warning", AOT.MODIFY_MESSAGE, InfoDialog.YES|InfoDialog.NO|InfoDialog.CANCEL, this);

      if(!document.closeable()) {

	   alert.center(); /* Dokument wurde veraendert, daher ggf. sichern*/

	   document.warn_about_empty_or_node(true);

	  } else
	   alert._new();

	 } else if(evt.target==open_cat||((String)(evt.arg)).startsWith("Goto")||evt.target==open_button) { 
      /* anderes Dokument (.cat) oeffnen. ("Goto"...-Syntax ist veraltet)*/

	  AOT.open(document, ((String)(evt.arg)).startsWith("Goto")?((String)(evt.arg)).substring(4):null, false);

	 } else if(evt.target==undo_all||evt.target==reload_button) { /* Dokument (.cat) nochmals oeffnen, um Aenderungen rueckgaengig zu machen*/

   	  AOT.open(document, document.name(), false);

	 } else if(evt.target==open_url_cat||evt.target==open_url_button) { 
      // wie open_cat, aber beliebige Eingabe (z.B. demo.cat#edge_x oder eine URL)

	  AOT.open(document, null, true);

     } else if(evt.target==save_cat||evt.target==save_button) { 
      /* Dokument als Datei speichern*/

      document.save();
	 
	 } else if(evt.target==saveas_cat) { /* Dokument unter einem anderem Dateinamen speichern*/

      AOT.user_file_operation(AOT.user_file_operation_SAVE_CAT, "*."+AOT.CATEGORIES_FILE_TYPE, document, false, false);

     } else if(evt.target==load_sel) { /* Selektion (.sel) laden*/

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Load selection]");
   
	  AOT.user_file_operation(AOT.user_file_operation_LOAD_SEL, "*."+AOT.SELECTION_FILE_TYPE, document, true, true);

	 } else if(evt.target==merge_sel) { /* Selektion (.sel) ueber bestehenden Aktiv.zustand laden, ohne diesen vorher zu loeschen */

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Merge selection]");

 	  AOT.user_file_operation(AOT.user_file_operation_LOAD_SEL, "*."+AOT.SELECTION_FILE_TYPE, document, false, true);

	 } else if(evt.target==save_sel) { /* Selektion (.sel) speichern*/

   	  AOT.user_file_operation(AOT.user_file_operation_SAVE_SEL, "*."+AOT.SELECTION_FILE_TYPE, document, false, false);
 
	 } else if(evt.target==send_sel) { /* Selektion (.sel) zum Applet-Host schicken */

	  document.send_selection(/*null*/);

	 } else if(evt.target==del_sel) { /* Selektion (.sel) auf Applet-Host loeschen */

	  document.delete_selection(/*null*/);

	 } else if(evt.target==complete_sel) { /* Unvollstaendige Selektion (.sel) zum Applet-Host schicken zwecks Ergaenzung */

	  document.complete_selection(/*null*/);

	 } else if(evt.target==reset_server) { // nur zum internen Gebrauch

	  document.reset_server();

	 } else if(evt.target==open_selsource) { /* Aktivierungszustand als Selektionstext anzeigen*/

      document.display_selection(false);

	 } else if(evt.target==enter_text||evt.target==open||evt.arg.equals(PopUpWindow.encode(open/*(das "Node-Open")*/==null?null:open.getLabel()))) { 
      /* Inhalt oeffnen (d.h.: Blatt-Text eingeben oder HTML-Seite anschauen) */

	  document.edit_leaf_text();

	 } else if(evt.target==reset_activation) { /* minimalen Aktivierungszustand herstellen*/

      document.reset_activation();

     } else if(evt.target==open_clipboard) {

      if(AOT.Aot.clipboard_frame==null) {  /* Clipboard in einem eigenen "Anwendungs-"fenster anzeigen*/

       AOT.Aot.clipboard_frame = new ClipboardFrame(AOT.Aot.clipboard);

	  } else {

	   AOT.Aot.clipboard_frame.show();

	   AOT.Aot.clipboard_frame.requestFocus();

	  }

     } else if(evt.target==copy||evt.arg.equals(PopUpWindow.encode(copy==null?null:copy.getLabel()))||evt.target==copy_button)
      AOT.Aot.clipboard.paste(document);
	 
     else if(evt.target==paste||evt.target==paste_as_last||evt.arg.equals(PopUpWindow.encode(paste==null?null:paste.getLabel()))||evt.target==paste_button) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Paste]");

      document.paste(AOT.Aot.clipboard);

     } else if(evt.target==paste_as_first||evt.arg.equals(PopUpWindow.encode(paste_as_first==null?null:paste_as_first.getLabel()))) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Paste as first]");

      document.paste_as_first(AOT.Aot.clipboard);

     } else if(evt.target==paste_before||evt.arg.equals(PopUpWindow.encode(paste_before==null?null:paste_before.getLabel()))) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Paste before]");

      document.paste_before(AOT.Aot.clipboard);

     } else if(evt.target==paste_behind||evt.arg.equals(PopUpWindow.encode(paste_behind==null?null:paste_behind.getLabel()))) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Paste behind]");

      document.paste_behind(AOT.Aot.clipboard);

     } else if(evt.target==new_branch||evt.target==new_as_last||evt.arg.equals(PopUpWindow.encode(new_branch==null?null:new_branch.getLabel()))||evt.target==new_button)
      document.new_branch(false, null);
      
     else if(evt.target==new_as_first) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [New first child]");

      document.new_as_first();

     } else if(evt.target==new_before) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [New neighbour]");

      document.new_before();

     } else if(evt.target==new_behind) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [New neighbour]");

      document.new_behind();

     } else if(evt.target==new_alternative||evt.arg.equals(PopUpWindow.encode(new_alternative==null?null:new_alternative.getLabel()))) {  
     // Durch Endanwender Nachfolger zu "other" hinzufuegen

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [New alternative]");

      document.new_alternative();

     } else if(evt.target==commentary) { 

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Enter commentary]");

      document.commentary();

	 } else if(evt.target==move_up||evt.arg.equals(PopUpWindow.encode(move_up==null?null:move_up.getLabel())))
      document.move(AOT.Aot.clipboard, true);

	 else if(evt.target==move_down||evt.arg.equals(PopUpWindow.encode(move_down==null?null:move_down.getLabel())))
      document.move(AOT.Aot.clipboard, false);

	 else if(evt.target==delete||evt.arg.equals(PopUpWindow.encode(delete==null?null:delete.getLabel()))) {

      if(undo!=null)
       document.prepare_undo();

      document.delete();

      if(undo!=null) {

       undo.enable();

       undo_setLabel("Undo [Delete]");

	  }

	 } else if(evt.target==replace||evt.arg.equals(PopUpWindow.encode(replace==null?null:replace.getLabel()))) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Replace]");

      document.replace(AOT.Aot.clipboard);

	 } else if(evt.target==sort||evt.arg.equals(PopUpWindow.encode(sort==null?null:sort.getLabel()))) { 

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Sort]");

      document.sort();

	 } else if(evt.target==find)
      document.find();

	 else if(evt.target==collapse)
      document.collapse();

	 else if(evt.target==expand)
      document.expand();

	 else if(evt.target==collapse_all)
      document.collapse_all();

	 else if(evt.target==expand_all)
      document.expand_all();

	 else if(evt.target==activated_only) {

	  boolean activated_only_flag = document.toggle_activated_only();

	  if(!AOT.BROWSER_Navigator) // *** wg. groteskem Fehler im Borland Java
	   activated_only.setLabel(activated_only_flag?"Show inactivated objects":activated_only_label);
	  
	 } else if(evt.target==clear) {

      document.clear(); /*(kann nur im Clipboard aufgerufen werden, daher kein Undo)*/

	 } else if(evt.target==cut||evt.arg.equals(PopUpWindow.encode(cut==null?null:cut.getLabel()))||evt.target==cut_button) {

      document.prepare_undo();

      undo.enable();

      undo_setLabel("Undo [Cut]");

      AOT.Aot.clipboard.paste(document);

      document.delete();

	 } else if(evt.target==undo||evt.arg.equals(PopUpWindow.encode(undo==null?null:undo.getLabel())))
      document.undo();

     else if(evt.target==open_source) /* Baum in Textform anzeigen */
      document.display_source();

	 else if(evt.target==toggle_activation) 
	  document.toggle_activation();

	 else if(evt.target==constraints) 
	  document.constraints();

     else if(evt.target==add_bookmark||evt.arg.equals(bookmarks_choice.getItem(0).toString()))
	  document.add_bookmark();

     else if(evt.target==print_cat) 
	  document.print();  /* *** Drucken ist nicht moeglich unter Java 1.0 (mit Java 1.1 sollte es *im Prinzip* klappen)*/

	 else if(evt.target==about) 
	  InfoDialog.info("About", 
	   AOT.APPLET_NAME+" "+AOT.VERSION+"\nDeveloper:  "+AOT.DEVELOPER+"\n"+AOT.COPYRIGHT
       +"\nAll rights reserved.\nUnauthorized reproduction or distribution of this software or any portion of it will be prosecuted.\nDisclaimer: Categories comes without any warranty!"
       +"\nHTML browser: (c)1996 A. Goloshubin, J. Cook, (c)1997 M. Nickles (GNU)\nHTTPClient: (c)1996, 1997 R. Tschalaer (GNU)"
       , InfoDialog.OK, "cats_int.html");

	 else if(evt.target==decision_help) {

      document.decision_help = new DecisionHelpDialog(document);
   
      document.display_decision_help(null);

     }

	 else if(evt.target==props||evt.arg.equals(PopUpWindow.encode(props==null?null:props.getLabel()))) {
     /* Eigenschaften einer Kante bzw. des nachfolgenden Knotens aendern*/

	  document.properties();

	 } else if(evt.target==online_doc)
	  AOT.online_help(AOT.online_documentation);

	 else if(evt.arg.toString().length()>=1) { // immer als letzten Fall

      if(((evt.arg.toString())).charAt(0)>='0'&&((evt.arg.toString())).charAt(0)<='9') // Bookmark
       document.activate_bookmark(((evt.arg.toString().substring(evt.arg.toString().indexOf(" ")+1))));

     }

	 return true;

	}

  }			 

  return super.handleEvent(evt);

 }


 /** wird aufgerufen, wenn das Ereignis nicht vom Dokument(-canvas) verarbeitet wurde*/
 public boolean mouseDown(Event evt, int x, int y) {  

  if(popup!=null) {

   if(!AOT.java_102) {
   
    popup.dispose();

    popup = null; 

   }

  }

  if((evt.modifiers&Event.META_MASK)!=0) { /* rechte Maustaste gedrueckt:*/
  /* Anzeige eines Kontextmenues, hergestellt aus dem Edit-Menue.*/
  /* Folgender Code hat experimentellen Charakter;*/

  /* Kontextmenue per class List, da classes Menu und Choice hierfuer in Java nicht taugen*/

   if(AOT.Aot.access_mode==AOT.SUPERUSER) {

    if(popup!=null) {

     popup.dispose();

     popup = null;

    }

    popup = new PopUpWindow(this/*Modal-Bezug, kein Container*/, edit, x, y);

   }

   return true;

  }

  return false;

 }
 

 synchronized void on_destroy() {

  AOT.Aot.document = document;

  if(AOT.Aot.frame_mode&&AOT.Aot.aotframe!=null) { 
  /* schnelles Beenden ohne Umweg ueber aotframe:*/

   AOT.Aot.on_quit(false);

   System.exit(0);

  } else {

   if(AOT.Aot.clipboard_frame!=null) {

    AOT.Aot.clipboard_frame.dispose();
 
    AOT.Aot.clipboard_frame = null;

   }

   AOT.Aot.insert_document(false);
    /* (...denn zusaetzlich zum Schliessen des Frames soll das Dokument*/
    /* auch wieder in die Web-Seite integriert werden)*/
  
   dispose();

   AOT.Aot.application = null;

  }

 }

}


/** Emulation eines Popup-Menues unter Java 1.0 */
class PopUpWindow extends Dialog /* experimentell!, 
									*** fkt. nicht unter Motif: Window*/ {
/* *** PopUpWindow emuliert nicht besonders gut, besser waere ein*/
/* Custom-Control, dass Painting und Event-Handling komplett uebernimmt.*/
/* Unter Java 1.1 koennte diese Klasse durch ein echtes Menue ersetzt werden.*/

 ApplicationFrame parent; /* (nicht der Container, sondern der Bezug der Modalitaet)*/


 PopUpWindow(ApplicationFrame parent, Menu menu, int x, int y) {

  super(parent, "Edit tools", false);

  this.parent = parent;

  setLayout(new BorderLayout(1, 1));

  Panel panel = new Panel();

  panel.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 0));

  PopUpList popup_menu = new PopUpList(this, 12/*(!)*/);

  for(int i = 0; i<menu.countItems(); i++)
   if(!((String)menu.getItem(i).getLabel()).equals("-")&&  /* Trennzeilen auslassen*/
      !(menu.getItem(i) instanceof Menu)&&  /* Sub-PopUps weglassen*/
	  menu.getItem(i)!=parent.undo&&
	  menu.getItem(i)!=parent.undo_all)
    popup_menu.addItem(encode((String)menu.getItem(i).getLabel()));

  setBackground(Color.lightGray); /**** hierzu sollte es System.properties geben!?*/

  popup_menu.setBackground(Color.lightGray);

  popup_menu.setForeground(Color.black);

  panel.add(popup_menu);

  add("Center", panel);

  pack(); /**** ohne pack() stuerzt das Programm manchmal ab, mit pack() verschiebt sich der Inhalt...*/

  move(x+parent.location().x, y+parent.location().y);

  toFront();

  show();

  move(x+parent.location().x, y+parent.location().y); /* *** siehe Bemerkung in InputDialog.center()*/

 }


 /** Markierung zu menulabel hinzufuegen, um Verwechslungen mit echten Menuelabels auszuschliessen:*/
 static String encode(String menulabel) {

  if(menulabel==null)
   return "";

  String popuplabel = new String(" ");

  for(int i = 0; i<menulabel.length(); i++) 
   if(menulabel.charAt(i)=='\t')
	break;
   else if(menulabel.charAt(i)!='&')
    popuplabel += menulabel.charAt(i);

  return popuplabel;

 }


 public boolean handleEvent(Event evt) {

  if(evt.id==Event.WINDOW_DESTROY||evt.id==Event.ACTION_EVENT||evt.id==Event.KEY_PRESS&&evt.key==27) {

   parent.popup = null;

   dispose();

   return true;

  } 

  return super.handleEvent(evt);

 }

}


/** (Component von PopUpWindow)*/
class PopUpList extends List {

 PopUpWindow parent;


 PopUpList(PopUpWindow parent, int items) {

  super(items, false);

  this.parent = parent;

 }


 public boolean handleEvent(Event evt) {

  if(evt.id==Event.LIST_SELECT) {

   parent.parent.postEvent(new Event(evt.target/*nicht null!*/, 
						   Event.ACTION_EVENT, new String(getSelectedItem())));

   parent.hide();

   parent.dispose();

  } 

  return super.handleEvent(evt);

 }

}


class ClipboardFrame extends ApplicationFrame {

 ClipboardFrame(Document document) {

  this.document = document;

  setBackground(Color.white);

  menubar = new MenuBar();

  setMenuBar(menubar);

  file = new Menu("File");

  file.add(undo_all = new MenuItem(win2motif_men("Reload"))); // zwecks Datenaustausch mit anderen Categories-Programmen

  file.add(new MenuItem("-"));

  file.add(save_cat = new MenuItem(win2motif_men("Save\tCtrl+S")));  // zwecks Datenaustausch mit anderen Categories-Programmen

  // geht nicht: file.add(saveas_cat = new MenuItem(win2motif_men("Save as...")));
  
  file.add(new MenuItem("-"));

  file.add(close = new MenuItem("Close"));

  menubar.add(file);

  edit = new Menu("Edit");

  edit.add(delete = new MenuItem("Delete"));

  edit.add(clear = new MenuItem("Clear"));

  menubar.add(edit);

  display(document);

 }

 void on_destroy() {

  dispose();

  AOT.Aot.clipboard_frame = null;

 }
 
 public boolean mouseDown(Event evt, int x, int y) {  

  return false; /* damit im Clipboard kein Kontextmenue zur Verfuegung stehen soll*/

 }
	 
}


/** Neues Anwender-Dokument oeffnen (d.h.: Datei in Dokument austauschen).
Dieser Dialog muss ggf. konstruiert werden, auch wenn er nicht dargestellt wird (zur Sicherung der Selektion) */
class OpenDocumentDialog extends InfoDialog {

 Document document;

 String filename; // null: erfragen

 boolean any_input;  // Beliebiges Ziel erlauben (wie z.B. x.cat#edge_x oder URL)


 OpenDocumentDialog(String title, String message, int mode, Document document, String filename, boolean any_input) {

  super(title, message, mode, "cats_fit.html#source");

  this.document = document;

  this.filename = filename==null?null:filename.trim();

  this.any_input = any_input;

  if(document.selection_has_been_modified()&&(filename==null||filename.charAt(0)!='#')) 
   AOT.user_file_operation(AOT.user_file_operation_SAVE_SEL, AOT.Aot.user_selection_file, document, false, false);
  
 }


 /** altes Dokument sichern, neues oeffnen*/
 void yes_action() { 

  hide();
  
  document.save();

  open();

  dispose();
  
 }
 

 /** altes Dokument nicht sichern, gleich neues oeffnen*/
 void no_action() { 
 
  hide();

  open();

  dispose();
  
 }


 /** Abbruch*/
 void cancel_action() { 
 
  dispose();
  
 }


 /** Baum aus Datei lesen*/
 void open() {  

  if(document==null) { // kommt das jemals hier vor?
/*
   if(filename==null)
    filename = AOT.Aot.inquire_filename("Load Categories-tree", "*."+AOT.CATEGORIES_FILE_TYPE, FileDialog.LOAD);

   if(filename!=null) {

    if(AOT.Aot.application!=null) {

     AOT.Aot.application.remove(AOT.Aot.application.document.view);

     AOT.Aot.application.document = new Document(filename);

     AOT.Aot.application.display(AOT.Aot.application.document);
    }

   }
*/ System.out.println("Internal error: Missing document object\nPlease report to developer!");

  } else {

   if(filename==null)
    AOT.user_file_operation(AOT.user_file_operation_LOAD_CAT, "*."+AOT.CATEGORIES_FILE_TYPE, document, false, false, any_input);
   else
    document.open(filename, true);

  }

 }

}


/** .cat-Datei statt dem markierten Knoten in den Baum einfuegen (aehnlich wie bei einem Include-Knoten)*/
class OpenIncludeDialog extends InfoDialog {

 String filename;

 String short_name; /* damit nicht der absolute Dateipfad als Subroot-Name verwendet werden muss*/

 Document document; 


 OpenIncludeDialog(String title, String message, int mode, String filename, String short_name, Document document) {

  super(title, message, mode, "cats_fit.html#source");

  this.filename = filename;

  this.short_name = short_name;

  this.document = document;

 }


 void yes_action() { 

  hide();

  Document temp_doc = new Document(filename);

  Node subroot = document.replace(temp_doc);

  subroot.set_name(short_name);

  document.view.canvas.update(); /* sonst wuerde der von .replace() angezeigte absolute Pad erscheinen*/
  
  dispose();

 }
 
 
 void no_action() { 

  hide();

  dispose();

 }

}


/** Aehnlich OpenDocumentDialog, aber kein neues Dokument oeffnen;*/
class QuitDialog extends InfoDialog {

 ApplicationFrame parent_app;


 QuitDialog(String title, String message, int mode, ApplicationFrame  parent_app) {

  super(title, message, mode, null);

  this.parent_app = parent_app;

 }


 /** altes Dokument sichern*/
 void yes_action() { 
 
  hide();

  parent_app.document.save();

  _quit();
  
 }
 
 
 /** altes Dokument verwerfen*/
 void no_action() { 
 
  _quit();

 }

 void cancel_action() {
 
 
 }

 void _quit() {

  parent_app.on_destroy();

 }

}


/** Aehnlich OpenDocumentDialog, aber neues, leeres Dokument erzeugen;*/
class NewDocumentDialog extends InfoDialog {

 ApplicationFrame parent_app;


 NewDocumentDialog(String title, String message, int mode, ApplicationFrame parent_app) {

  super(title, message, mode, "cats_fit.html#document");

  this.parent_app = parent_app;

 }


 /** altes Dokument sichern*/
 void yes_action() { 
 
  hide();

  parent_app.document.save();

  _new();
  
 }
 

 /** altes Dokument verwerfen*/
 void no_action() { 

  hide();

  _new();

 }


 void cancel_action() {  }


 /** neues, leeres Dokument oeffnen */
 void _new() {  

  parent_app.document.clear();

  parent_app.document.set_name("noname."+AOT.CATEGORIES_FILE_TYPE);

 }

}


/** einfache Nachrichtenbox (modal, aber asynchron zum Thread!!)*/
class InfoDialog extends Dialog {

 final static int OK = 1;

 final static int YES = 2;
 
 final static int NO = 4;
 
 final static int CANCEL = 8;

 final static int POS_X = 400, POS_Y = 200, indent = 60;

 static int offset_x = 0, offset_y = 0;

 final static Color bk_color = (true||AOT.GUI_Windows)?Color.lightGray:Color.gray, 
	          warn_color = Color.white/* *** keine Wirkung unter Windows/Java 1.0*/, error_color = Color.red;

 static Frame dummy; /* (*** wenn Motif kein Frame-Parent findet => Exception!)*/

 Button ok_button = null, yes_button = null, no_button = null, cancel_button = null, help_button = null;

 int mode; 

 Component postmortem; /* (siehe Konstruktor) */

 /** URL des Hilfeeintrags zur Dialogbox (optional)*/
 String help = null;  


 void ok_action() { }
 
 void yes_action() { }
 
 void no_action() { }
 
 void cancel_action() { }

 void help_action() { 
 
  AOT.online_help(help);
 
 }

 InfoDialog(String title, String message, int mode, String help) {
 
  this(title, message, mode, AOT.Aot.application!=null?AOT.Aot.application:AOT.Aot.aotframe!=null?AOT.Aot.aotframe:(dummy = new Frame()), help);

 }

 InfoDialog(Component postmortem, String title, String message, int mode, String help) {
 
  this(title, message, mode, help);

  this.postmortem = postmortem; /* Komponente, die nach Beendigung aktiviert werden soll*/
  /* (normalerweise ist dies parent, dies fkt. aber nicht mit class Window/Dialog)*/

 }

 InfoDialog(String title, String message, int mode, Frame parent, String help) {
  
  super(parent, title, false /* *** true (modal) waere richtig, dann aber Absturz unter Motif mgl.*/);

  this.help = help;
   
  postmortem = null;

  setBackground(bk_color);

  int rows = 2;

  for(int i = 0; i<message.length(); i++)
   if(message.charAt(i)=='\n')
    ++rows;
    
  setLayout(new GridLayout(rows, 1, 0, -5));

  String subm = new String(message+"\n");

  while(subm.indexOf("\n")>=0) {

   Label label = new Label(subm.substring(0, subm.indexOf("\n"))+"   ", Label.CENTER);

   add(label);

   if(title.indexOf("Error")>=0)  /**** Farbaenderung fkt. mit Motif, aber nicht mit Windows 95*/
    label.setForeground(error_color);
   else if(title.indexOf("Warning")>=0)
    label.setForeground(warn_color);
   else
    label.setForeground(Color.black);

   try {

    subm = subm.substring(subm.indexOf("\n")+1);

   } catch(StringIndexOutOfBoundsException xcpt) {

    break;

   }

  }

  Panel p = new Panel();

  p.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));

  if((mode&OK)!=0) {

   ok_button = new Button("     Ok     ");

   p.add(ok_button);

  }

  if((mode&YES)!=0) {

   yes_button = new Button("      Yes      ");

   p.add(yes_button);

  }

  if((mode&NO)!=0) {

   no_button = new Button("   No   ");

   p.add(no_button);

  }

  if((mode&CANCEL)!=0) {

   cancel_button = new Button(" Cancel ");

   p.add(cancel_button);

  }

  if(help!=null) {

   help_button = new Button(" Help ");

   p.add(help_button);

  }

  add(p);

  pack();

  setResizable(false);

 }


 /** siehe Konstruktor*/
 static void info(String title, String text, int mode, String help) { /* zeigt Information-/Warn-/Fehlermeldung an*/
 
  InfoDialog info = new InfoDialog(title, text, mode, help);

  info.center();

 }


 /** siehe Konstruktor*/
 static void info(String title, String text, int mode, Frame parent, String help) { /* zeigt Information-/Warn-/Fehlermeldung an*/
 
  InfoDialog info = new InfoDialog(title, text, mode, parent, help);

  info.center();

 }

 
 /** siehe Konstruktor*/
 static void info(Component postmortem, String title, String text, int mode, String help) { /* zeigt Information-/Warn-/Fehlermeldung an*/

  InfoDialog info = new InfoDialog(postmortem, title, text, mode, help);

  info.center();

 }


 void center() {  // (man kann in Java zwar per AWT-Toolkit die Screen-Ausmasse feststellen, dies ist aber evtl. fuer Applets nicht erlaubt)

  if(offset_x>indent*3)
   offset_x = offset_y = 0;

  offset_x += indent;
  
  offset_y += indent;

  /* *** folgendes ist kein Witz, sondern bittere Notwendigkeit, zumindest unter Java 1.0+JView: */

resize(bounds().width, bounds().height+30); //** sonst oft Buttons verdeckt wg. "Sicherheitswarnungs-"Zeile unten
  move(POS_X+offset_x, POS_Y+offset_y);

  show();

  validate();

 }


 public boolean handleEvent(Event e) {

   if(e.id==Event.WINDOW_DESTROY||e.id==Event.KEY_PRESS&&e.key==27) { /*Esc wird leider vom GUI abgefangen*/

	quit();

	return true;
 
   } else if(e.id==Event.ACTION_EVENT) {

   if(e.target==ok_button) {

    ok_action();

    quit();

    return true;

   } else if(e.target==yes_button) {

    yes_action();

	quit();

    return true;

   } else if(e.target==no_button) {

    no_action();

	quit();

    return true;

   } else if(e.target==cancel_button) {

    cancel_action();

	quit();

    return true;

   } else if(e.target==help_button) {

    help_action();

    return true;

   }

  }

   return super.handleEvent(e);

 }


 void quit() {

  offset_x -= indent;
	
  offset_y -= indent;

  hide();

  dispose();

  if(postmortem!=null) {

   postmortem.show();

   postmortem.requestFocus();

  }

 }

}


class Filter implements FilenameFilter {

 String[] xtn; /* erlaubte Dateiendungen (z.B. { ".cat", ".sel" })*/


 Filter(String[] xtn) {

  this.xtn = xtn;

 }


 Filter(String xtn) {
  
  this.xtn = new String[1];

  this.xtn[0] = xtn;

 }


 public boolean accept(File dir, String name) {

  for(int i = 0; i<xtn.length; i++)
   if(name.toLowerCase().endsWith(xtn[i]))
    return true;

  return false;

 }

}


/** /* Sicherheitsabfrage + Properties-Refresh
Vgl. InfoDialog */
class RefreshPropsDialog extends InfoDialog { 
/* *** diese Klasse gehoert eigentlich nach Node.java, dann stuerzt aber*/
/* manchmal der Interpreter ab(!)*/

 PropertiesDialog parent_app;


 RefreshPropsDialog(String title, String message, int mode, PropertiesDialog parent_app) {

  super(title, message, mode, parent_app, "cats_pro.html");

  this.parent_app = parent_app;

 }


 /** Inhalte der Properties-Box aktivieren, dann neues editable-object lesen*/
 void yes_action() { 

  hide();

  dispose();

  Node temp = parent_app.node;

  parent_app.node = parent_app.previous_node;

  boolean success = parent_app.activate_changes();

  parent_app.modified = false;

  if(success)
   parent_app.node = temp;

  parent_app.doc.view.mark_edge(parent_app.doc.view.find_neuro(parent_app.node), true);

  if(success)
   parent_app.read_properties();
  
  parent_app.alert = null;

 }
 

 /** Inhalte der Properties-Box verwerfen, gleich neues editable-object lesen*/
 void no_action() { 
 
  hide();

  dispose();

  parent_app.read_properties();

  parent_app.alert = null;

  parent_app.modified = false;

 }

}



/** Primitive Dateiauswahlbox (fuer Applets, z.Zt. noch ohne Verzeichnisliste) */
class GetFileNameDialog extends Dialog {

 /** anfaengliche Position*/
 final static int POS_X = 410, POS_Y = 210, LEN = 50;

 int type; /* siehe AOT.user_file_operation() */

 boolean flag1, flag2; // fuer type=LOAD_SEL 

 Document document;

 String filename;

 TextComponent textarea;

 Button ok_button, cancel_button, help_button;


 GetFileNameDialog(String message, String defname, int type/*Operationsart*/, Frame parent, Document document, boolean flag1, boolean flag2) {

  super(parent, message, false/*unbedingt modeless, da mehrere dieser Dialoge zugleich offen sein koennen!*/);

  filename = new String(defname);

  this.document = document;

  this.flag1 = flag1;

  this.flag2 = flag2;

  this.type = type;

  textarea = new TextArea(defname, 1, LEN);

  textarea.setFont(new Font("Courier", Font.PLAIN, 12));

  add("Center", textarea);

  Panel p = new Panel();

  p.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));

  ok_button = new Button("     Ok     ");

  p.add(ok_button);

  cancel_button = new Button(" Cancel ");

  p.add(cancel_button);

  help_button = new Button(" Help ");

  p.add(help_button);

  p.setBackground(Color.white);

  add("South", p);

  pack(); 

resize(bounds().width, bounds().height+30); //** sonst oft Buttons verdeckt wg. "Sicherheitswarnungs-"Zeile unten

  move(POS_X+((type==AOT.user_file_operation_SAVE_SEL)?40:0),POS_Y-((type==AOT.user_file_operation_SAVE_SEL)?40:0));

  show();

  move(POS_X+((type==AOT.user_file_operation_SAVE_SEL)?40:0),POS_Y-((type==AOT.user_file_operation_SAVE_SEL)?40:0));
   // *** sonst klappt Positionierung evtl. nicht (!)

 }


 public boolean handleEvent(Event e) {

  if(e.id==Event.KEY_PRESS&&e.key==27||e.id==Event.WINDOW_DESTROY) { //Esc/Close

   hide();

   dispose();

   AOT.Aot.document.view.canvas.requestFocus();

   return true;

  }

  if(e.id==Event.ACTION_EVENT) {

   if(e.target==ok_button) {

    filename = new String(textarea.getText());

	if(!filename.startsWith("*")) {

	 hide();

     dispose();

     if(type==AOT.user_file_operation_SAVE_CAT)
 	  document.save(filename); 
     else if(type==AOT.user_file_operation_SAVE_SEL)
      document.save_selection(filename);
     else if(type==AOT.user_file_operation_LOAD_CAT)
      document.open(filename, true);
     else if(type==AOT.user_file_operation_LOAD_SEL)
      document.load_selection(filename, flag1, flag2);

     AOT.Aot.document.view.canvas.requestFocus();

	} else {

	 System.out.println("Improper filename");

     InfoDialog.info(AOT.APPLET_NAME+" Error", "Improper filename", InfoDialog.OK, null);

	}

    return true;

   } else if(e.target==cancel_button) {

    hide();

    dispose();

    AOT.Aot.document.view.canvas.requestFocus();

    return true;
  
   } else if(e.target==help_button) {

	AOT.online_help(type==AOT.user_file_operation_SAVE_SEL||type==AOT.user_file_operation_LOAD_SEL?"cats_sel.html":"cats_fit.html#source");
      
    return true;

   }

  }

  return super.handleEvent(e);

 }

}

