/**************************************************************************

    This file is part of explorer95, a file manager for fvwm95.
    Copyright (C) 1996, 1997 David Barth, Hector Peraza.

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

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

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

**************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <time.h>
#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <xclass/OMimeTypes.h>
#include <xclass/OXClient.h>
#include <xclass/OXWindow.h>
#include <xclass/OXFrame.h>
#include <xclass/OXWidgets.h>
#include <xclass/OXMsgBox.h>
#include <xclass/OString.h>
#include <xclass/OPicture.h>
#include <xclass/utils.h>

#include "OXNewClient.h"
#include "OXNewWidgets.h"
#include "OXOptions.h"

#include "main.h"


extern OXExplorerMainFrame *mainWindow;
extern int DispFullPath;
extern int NewBrowser;
extern int MainMode;

extern struct _default_icon default_icon[];
extern OMimeTypes *MimeTypeList;


//-------------------------------------------------------------------

OXOptionsDialog::OXOptionsDialog(const OXWindow *p, const OXWindow *main,
                                 unsigned long options) :
  OXTransientFrame(p, main, 400, 200, options) {
    OXCompositeFrame *tf;
    int ax, ay, width, height;
    Window wdummy;
    OHotString *str;
    const OPicture *pic;

    //=============== setup elements:

    //======= [1] this frame will contain the "OK Cancel Apply" buttons:
    bframe = new OXHorizontalFrame(this, 60, 20, FIXED_WIDTH);

    //--- create the buttons
    Ok     = new OXTextButton(bframe, new OHotString("OK"), ID_OK);
    Cancel = new OXTextButton(bframe, new OHotString("Cancel"), ID_CANCEL);
    Apply  = new OXTextButton(bframe, new OHotString("&Apply"), ID_APPLY);

    //--- Apply is initially disabled
    Apply->SetState(BUTTON_DISABLED);

    //--- send button messages to this dialog
    Ok->Associate(this);
    Cancel->Associate(this);
    Apply->Associate(this);

    //--- layout for buttons: top align, equally expand horizontally
    bly = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 5, 0, 0, 0);

    //--- layout for the frame: place at bottom, right aligned
    bfly = new OLayoutHints(LHINTS_BOTTOM | LHINTS_RIGHT, 0, 5, 0, 4);

    bframe->AddFrame(Ok, bly);
    bframe->AddFrame(Cancel, bly);
    bframe->AddFrame(Apply, bly);

    width = Ok->GetDefaultWidth();
    width = max(width, Cancel->GetDefaultWidth());
    width = max(width, Apply->GetDefaultWidth());
    bframe->Resize((width + 20) * 3, bframe->GetDefaultHeight());

    AddFrame(bframe, bfly);

    //====== [2] Tab widget

    tab = new OXTab(this, 320, 350);
    //Ltab = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 5, 5, 5, 5);
    Ltab = new OLayoutHints(LHINTS_EXPAND_Y | LHINTS_EXPAND_X, 5, 5, 5, 5);

    if (MainMode == FILE_MGR_MODE) {

      //------ [2a] Tab 1: Folder

      tf = tab->AddTab(new OString("Folder"));

      //--- Tab 1 contents: a single group frame,
      //                    2 radio buttons, 2 labels and 2 icons

      //--- the group frame and its layout
      gf1 = new OXGroupFrame(tf, new OString("Browsing options"));
      Gly = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y,
                             10, 10, 10, 10);

      str  = new OHotString("Browse folders using a separate window "
                            "for each folder.");
      rad1 = new OXRadioButton(gf1, str, 81);

      str  = new OHotString("Browse folders by using a single window "
                            "that changes as you open each folder.");
      rad2 = new OXRadioButton(gf1, str, 82);

      //--- layout for radio buttons and frames hf1, hf2
      Lr = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y, 5, 0, 0, 0);

      //--- layout for labels
      Lly = new OLayoutHints(LHINTS_CENTER_Y | LHINTS_LEFT, 22, 0, 0, 0);

      //--- layout for icons
      Ily = new OLayoutHints(LHINTS_CENTER_Y | LHINTS_LEFT, 15, 0, 0, 0);

      gf1->AddFrame(rad1, Lr);

      //--- horizontal frame holding the first label-icon group
      gf1->AddFrame(hf1 = new OXHorizontalFrame(gf1, 10, 10), Lr);

      //--- label text is owned by the label widget, and will be deleted
      //    on label deletion
      lbl1 = new OXLabel(hf1, new OString("Example:"));
      if ((pic = _client->GetPicture("multiwin.dlg.xpm")) == NULL)
        FatalError("Pixmap not found: multiwin.dlg.xpm");
      icon1 = new OXIcon(hf1, pic, 40, 40);

      hf1->AddFrame(lbl1, Lly);
      hf1->AddFrame(icon1, Ily);

      gf1->AddFrame(rad2, Lr);

      //--- horizontal frame holding the second label-icon group
      gf1->AddFrame(hf2 = new OXHorizontalFrame(gf1, 10, 10), Lr);

      lbl2 = new OXLabel(hf2, new OString("Example:"));
      if ((pic = _client->GetPicture("onewin.dlg.xpm")) == NULL)
        FatalError("Pixmap not found: onewin.dlg.xpm");
      icon2 = new OXIcon(hf2, pic, 40, 40);

      hf2->AddFrame(lbl2, Lly);
      hf2->AddFrame(icon2, Ily);

      tf->AddFrame(gf1, Gly);

      rad1->Associate(this);
      rad2->Associate(this);

      if (NewBrowser)
        rad1->SetState(BUTTON_DOWN);
      else
        rad2->SetState(BUTTON_DOWN);

      _NewBrowser = NewBrowser;
    }

    //------ [2b] Tab 2: View

    tf = tab->AddTab(new OString("View"));

    //--- Tab 2 contents: a group frame with 2 radio buttons and list box,
    //                    and a check button

    gf2 = new OXGroupFrame(tf, new OString("Files"));

    chk1 = new OXCheckButton(gf2, new OHotString("&Show hidden files and folders"), 83);
    chk2 = new OXCheckButton(gf2, new OHotString("Always place &folders first"), 84);

    chk1->Associate(this);
    chk2->Associate(this);
    chk1->SetState(BUTTON_DOWN);

    L3 = new OLayoutHints(LHINTS_LEFT | LHINTS_TOP, 0, 0, 5, 0);
    L4 = new OLayoutHints(LHINTS_LEFT | LHINTS_TOP, 5, 0, 0, 0);

    f3 = new OXVerticalFrame(tf, 60, 20);
    gf2->AddFrame(chk1, L3);
    gf2->AddFrame(chk2, L3);

    chk3 = new OXCheckButton(f3,
               new OHotString("Display the full path in the title bar"), 85);
    chk3->Associate(this);
    chk3->SetState(DispFullPath ? BUTTON_DOWN : BUTTON_UP);
    _DispFullPath = DispFullPath;

    f3->AddFrame(chk3, L4);

    //L6 = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y, 10, 10, 10, 0);
    L6 = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_TOP, 10, 10, 10, 0);
    tf->AddFrame(gf2, L6);
    tf->AddFrame(f3, L6);


    //------ [2c] Tab 3: File Types

    tf = tab->AddTab(new OString("File types"));

    lbly = new OLayoutHints(LHINTS_LEFT | LHINTS_TOP, 10, 10, 10, 0);
    tf->AddFrame(lbl3 = new OXLabel(tf,
                        new OString("Registered file types:")), lbly);

    hf3 = new OXHorizontalFrame(tf, 10, 10);
    lfh = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y, 10, 10, 0, 10);

    gfly = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_EXPAND_Y);
    lgf3 = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_BOTTOM, 0, 0, 2, 0);
    lf = new OXVerticalFrame(hf3, 10, 10);
    lf->AddFrame(lbf = new OXListBox(lf, 801), gfly);
    lf->AddFrame(gf3 = new OXGroupFrame(lf,
                       new OString("File type details")), lgf3);

    shf1 = new OXHorizontalFrame(gf3, 10, 10, FIXED_HEIGHT);
    shf2 = new OXHorizontalFrame(gf3, 10, 10, FIXED_HEIGHT);
    lshf = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 0, 0, 5, 0);

    lfd = new OLayoutHints(LHINTS_LEFT | LHINTS_EXPAND_Y, 0, 5, 2, 2);
    lex1 = new OLayoutHints(LHINTS_LEFT | LHINTS_EXPAND_Y, 10, 5, 2, 2);
    icf = new OXIcon(shf1, default_icon[ICON_APP].icon[ICON_BIG], 32, 32);
    lblex1 = new OXLabel(shf1, new OString("Extension:"));
    lblex2 = new OXLabel(shf1, new OString(""));
    shf1->AddFrame(icf, lfd);
    shf1->AddFrame(lblex1, lex1);
    shf1->AddFrame(lblex2, lfd);

    lblop1 = new OXLabel(shf2, new OString("Opens with:"));
    lblop2 = new OXLabel(shf2, new OString(""));
    shf2->AddFrame(lblop1, lfd);
    shf2->AddFrame(lblop2, lfd);

    shf1->Resize(shf1->GetDefaultWidth(), 38);
    shf2->Resize(shf1->GetDefaultWidth(), lblop1->GetDefaultHeight()+6);

    gf3->AddFrame(shf1, lshf);
    gf3->AddFrame(shf2, lshf);

    hf3->AddFrame(lf, gfly);

    UpdateListBox();

    bf = new OXVerticalFrame(hf3, 10, 10, FIXED_WIDTH);

    nbly = new OLayoutHints(LHINTS_EXPAND_X | LHINTS_TOP, 0, 0, 0, 5);
    nbfly = new OLayoutHints(LHINTS_LEFT | LHINTS_RIGHT, 10, 0, 0, 0);

    New    = new OXTextButton(bf, new OHotString("&New type..."), 801);
    Remove = new OXTextButton(bf, new OHotString("&Remove"), 802);
    Edit   = new OXTextButton(bf, new OHotString("&Edit..."), 803);

    New->Associate(this);
    Remove->Associate(this);
    Edit->Associate(this);

    Remove->SetState(BUTTON_DISABLED);
    Edit->SetState(BUTTON_DISABLED);

    bf->AddFrame(New, nbly);
    bf->AddFrame(Remove, nbly);
    bf->AddFrame(Edit, nbly);

    width = New->GetDefaultWidth();
    width = max(width, Remove->GetDefaultWidth());
    width = max(width, Edit->GetDefaultWidth());
    bf->Resize(width + 10, bf->GetDefaultHeight());

    hf3->AddFrame(bf, nbfly);

    tf->AddFrame(hf3, lfh);

    //-----------------------------

    AddFrame(tab, Ltab);

    MapSubwindows();

    width  = 330; // GetDefaultWidth();
    height = 386; // GetDefaultHeight();
    Resize(width, height);

    //---- position relative to the parent's window (the default was root 0,0!)
 
    XTranslateCoordinates(GetDisplay(),
                          main->GetId(), GetParent()->GetId(),
                          50, 50, &ax, &ay, &wdummy);

    Move(ax, ay);

    //---- make dialog non-resizable

    SetWMSize(width, height);
    SetWMSizeHints(width, height, width, height, 0, 0);

    SetWindowName("Options");
    SetIconName("Options");
    SetClassHints("Explorer", "Explorer");

    SetMWMHints(MWM_DECOR_ALL | MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE |
                                MWM_DECOR_MINIMIZE | MWM_DECOR_MENU,
                MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE | 
                               MWM_FUNC_MINIMIZE,
                MWM_INPUT_MODELESS);

    MapWindow();
    _client->WaitFor(this);
}

OXOptionsDialog::~OXOptionsDialog() {

  delete Ok; delete Cancel; delete Apply;
  delete bframe;
  delete bly; delete bfly;

  if (MainMode == FILE_MGR_MODE) {
    delete gf1;
    delete rad1; delete rad2;
    delete lbl1; delete lbl2;
    delete icon1; delete icon2;
    delete hf1; delete hf2;
    delete Lr; delete Lly; delete Ily; delete Gly;
  }

  delete gf2; delete f3;
  delete chk1; delete chk2; delete chk3;
  delete L3; delete L4; delete L6;

  delete New; delete Remove; delete Edit;
  delete bf; delete lbl3;
  delete lblex1; delete lblex2;
  delete lblop1; delete lblop2;
  delete icf;
  delete shf1; delete shf2;
  delete lshf; delete lfd; delete lex1;
  delete gf3; delete lbf; delete lgf3;
  delete lf;
  delete lfh; delete lbly; delete gfly;
  delete nbly; delete nbfly;
  delete hf3;

  delete tab; delete Ltab;

}

void OXOptionsDialog::CloseWindow() {
  delete this;
}

void OXOptionsDialog::UpdateListBox() {
  OMime *MimeRunner;
  int i;

  // test only...
  //struct { char *ft, *ext; } ftypes[] = { 
  //  { "Documents",            "doc"  },
  //  { "Plain text documents", "txt"  },
  //  { "TEX documents",        "tex"  },
  //  { "HTML files",           "html" },
  //  { "Postcript files",      "ps"   },
  //  { "PDF files",            "pdf"  },
  //  { "GIF images",           "gif"  },
  //  { "TIFF images",          "tiff" },
  //  { "X bitmaps",            "xbm"  },
  //  { "X pixmaps",            "xpm"  },
  //  { "Windows bitmaps",      "bmp"  },
  //  { NULL,                   NULL   } };


  lbf->AddEntry(new OXTreeLBEntry(lbf->GetContainer(),
                      new OString("Application"),
                      default_icon[ICON_APP].icon[ICON_SMALL], 500, NULL),
                new OLayoutHints(LHINTS_LEFT | LHINTS_TOP,
                      3, 0, 0, 0));
  lbf->AddEntry(new OXTreeLBEntry(lbf->GetContainer(),
                      new OString("File folder"),
                      default_icon[ICON_FOLDER].icon[ICON_SMALL], 501, NULL),
                new OLayoutHints(LHINTS_LEFT | LHINTS_TOP,
                      3, 0, 0, 0));

  // for (int i=0; ftypes[i].ft != NULL; ++i) {

  MimeRunner = NULL;
  i = 0;

  while ((MimeRunner = MimeTypeList->NextMime(MimeRunner))) {
    const OPicture *pic;
    char  fname[50];
    OString *descr;

    // sprintf(fname, "x.%s", ftypes[i].ext); 
    // pic = MimeTypeList->GetIcon(fname, True);
    pic = MimeTypeList->GetIcon(MimeRunner, True);
    if (pic == NULL) 
      pic = default_icon[ICON_DOC].icon[ICON_SMALL];

    if (MimeRunner->description) {
      descr = new OString(MimeRunner->description);
    } else {
      char default_descr[1000];
      // generate default description
      sprintf(default_descr, "Files matching %s", MimeRunner->pattern);
      descr = new OString(default_descr);
    }

    // Fake string value /********/
    sprintf(fname, "%ld", (long) MimeRunner);

    lbf->AddEntry(new OXTreeLBEntry(lbf->GetContainer(),
                        // new OString(ftypes[i].ft), 
                        descr, pic, 503+i, 
                        new OString(fname)),
                  new OLayoutHints(LHINTS_LEFT | LHINTS_TOP,
                        3, 0, 0, 0));
    i++;
  }
 
  lbf->Select(500);
  lbf->Associate(this);
}

int OXOptionsDialog::ProcessMessage(long msg, long parm1, long parm2) {
  const OPicture *pic;
  OXTreeLBEntry *e;
  // const char *ext;
  char *p, fname[256], action[256];

  switch(GET_MSG(msg)) {
    case XC_COMMAND:

      switch(GET_SUBMSG(msg)) {
        case CM_BUTTON:
          switch(parm1) {
            case ID_OK:
              NewBrowser = _NewBrowser;
              if (DispFullPath != _DispFullPath) {
                DispFullPath = _DispFullPath;
                mainWindow->SetTitle();
              }
            case ID_CANCEL:
              CloseWindow();
              break;

            case ID_APPLY:
              NewBrowser = _NewBrowser;
              if (DispFullPath != _DispFullPath) {
                DispFullPath = _DispFullPath;
                mainWindow->SetTitle();
              }
              Apply->SetState(BUTTON_DISABLED);
              break;

            case 801:
              new OXEditMimeDialog(_client->GetRoot(), this, NULL, True);
              break;

            case 802:
              break;

            case 803:
              e = (OXTreeLBEntry *) lbf->GetSelectedEntry();
              if (e && (e->ID() > 501)) {
                const char *str;
                OMime *mime;

                str = e->GetPath()->GetString();
                sscanf(str, "%ld", (long *)&(mime)); /********/
                new OXEditMimeDialog(_client->GetRoot(), this, mime, False);
              }
              break;

          }
          break;

        case CM_CHECKBUTTON:
        case CM_RADIOBUTTON:
          switch(parm1) {

            // process the radio buttons
            case 81:
              rad2->SetState(BUTTON_UP);
              _NewBrowser = True;
              break;

            case 82:
              rad1->SetState(BUTTON_UP);
              _NewBrowser = False;
              break;

            case 85:
              _DispFullPath = (chk3->GetState() == BUTTON_DOWN);
              break;

          }
          Apply->SetState(BUTTON_UP);
          break;

        case CM_LISTBOX:
          if (parm1 == 801) {
            if (parm2 == 500) {

              icf->SetPicture(default_icon[ICON_APP].icon[ICON_FOLDER]);
              lblex2->SetText(new OString(""));
              lblop2->SetText(new OString(""));
              Remove->SetState(BUTTON_DISABLED);
              Edit->SetState(BUTTON_DISABLED);

            } else if (parm2 == 501) {

              icf->SetPicture(default_icon[ICON_FOLDER].icon[ICON_FOLDER]);
              lblex2->SetText(new OString(""));
              lblop2->SetText(new OString("explorer"));
              Remove->SetState(BUTTON_DISABLED);
              Edit->SetState(BUTTON_DISABLED);

            } else {

              const char *str;
              OMime *mime;
  
              e = (OXTreeLBEntry *) lbf->GetSelectedEntry();
              // ext = e->GetPath()->GetString();
              str = e->GetPath()->GetString();
              sscanf(str, "%ld", (long *)&(mime)); /********/
              // sprintf(fname, "x.%s", ext);
              // pic = MimeTypeList->GetIcon(fname, False);
              pic = MimeTypeList->GetIcon(mime, False);
              // MimeTypeList->GetAction(fname, action);
              if ((p = strchr(mime->action, ' ')) != NULL) *p = '\0';
              if (!pic) pic = default_icon[ICON_DOC].icon[ICON_BIG];
              icf->SetPicture(pic);
              //lblex2->SetText(new OString(ext));
              //lblop2->SetText(new OString(action));
              lblex2->SetText(new OString(mime->pattern));
              lblop2->SetText(new OString(mime->action));
              Remove->SetState(BUTTON_UP);
              Edit->SetState(BUTTON_UP);

            }
          gf3->Layout();
          }
          break;

        default:
          break;
      }
      break;

    default:
      break;
  }

  return True;
}

//-------------------------------------------------------------------

OXEditMimeDialog::OXEditMimeDialog(const OXWindow *p, const OXWindow *main,
                                   OMime *mime, int add_mode,
                                   unsigned long options) :
  OXTransientFrame(p, main, 400, 200, options) {
    int ax, ay, width;
    Window wdummy;
    const OPicture *pic;
    char name[1024], tmp[1024];

    //--- create the OK / Cancel buttons and button frame:
    bframe = new OXHorizontalFrame(this, 60, 20, FIXED_WIDTH);

    Ok = new OXTextButton(bframe, new OHotString("OK"), ID_OK);
    Cancel = new OXTextButton(bframe, new OHotString("Cancel"), ID_CANCEL);

    Ok->Associate(this);
    Cancel->Associate(this);

    //--- layout for buttons: top align, equally expand horizontally
    bly = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 5, 0, 0, 0);

    //--- layout for the frame: place at bottom, right-aligned
    bfly = new OLayoutHints(LHINTS_BOTTOM | LHINTS_RIGHT, 0, 5, 0, 4);

    bframe->AddFrame(Ok, bly);
    bframe->AddFrame(Cancel, bly);

    width = Ok->GetDefaultWidth();
    width = max(width, Cancel->GetDefaultWidth());
    bframe->Resize((width + 20) * 2, bframe->GetDefaultHeight());

    AddFrame(bframe, bfly);

    //--- icon frame
    Ihf = new OXHorizontalFrame(this, 10, 10, FIXED_WIDTH);

    //sprintf(name, "x.%s", ext);
    //pic = MimeTypeList->GetIcon(name, False);
    EditingMime = mime;
    pic = mime ? MimeTypeList->GetIcon(mime, False) :
                 default_icon[ICON_DOC].icon[ICON_BIG];
    icon1 = new OXIcon(Ihf, pic, 32, 32);
    Ily = new OLayoutHints(LHINTS_LEFT | LHINTS_CENTER_Y, 10, 10, 15, 15);

    SetIcon = new OXTextButton(Ihf, new OHotString("Change &Icon..."), 100);
    SetIcon->Associate(this);
    lyl = new OLayoutHints(LHINTS_LEFT | LHINTS_CENTER_Y);
    lyr = new OLayoutHints(LHINTS_RIGHT | LHINTS_CENTER_Y);

    Ihf->AddFrame(icon1, Ily);
    Ihf->AddFrame(SetIcon, lyr);

    Ihf->Resize(SetIcon->GetDefaultWidth() + icon1->GetDefaultWidth() +40,
                Ihf->GetDefaultHeight());

    //--- separators...

    ln1 = new OXHorizontal3dLine(this);
    ln2 = new OXHorizontal3dLine(this);
    lyln = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 5, 5, 5, 5);

    //--- text entry frames...

    hf1 = new OXHorizontalFrame(this, 10, 10);
    lbl1 = new OXLabel(hf1, new OHotString("&Description of type:"));
    txb1 = new OTextBuffer(256);
    txb1->AddText(0, "");
    txt1 = new OXTextEntry(hf1, txb1, 101);
    txt1->Resize(180, txt1->GetDefaultHeight());
    hf1->AddFrame(lbl1, lyl);
    hf1->AddFrame(txt1, lyr);

    hf2 = new OXHorizontalFrame(this, 10, 10);
    lbl2 = new OXLabel(hf2, new OHotString("Content &Type (MIME):"));
    txb2 = new OTextBuffer(256);
    MimeTypeList->GetType(name, tmp);
    txb2->AddText(0, tmp);
    txt2 = new OXTextEntry(hf2, txb2, 103);
    txt2->Resize(180, txt2->GetDefaultHeight());
    hf2->AddFrame(lbl2, lyl);
    hf2->AddFrame(txt2, lyr);

    hf3 = new OXHorizontalFrame(this, 10, 10);
    lbl3 = new OXLabel(hf3, new OHotString("Matching &Pattern:"));
    txb3 = new OTextBuffer(256);
    // txb3->AddText(0, ext);
    txb3->AddText(0, (mime) ? mime->pattern : "");

    txt3 = new OXTextEntry(hf3, txb3, 102);
    txt3->Resize(180, txt3->GetDefaultHeight());
    hf3->AddFrame(lbl3, lyl);
    hf3->AddFrame(txt3, lyr);

    hf4 = new OXHorizontalFrame(this, 10, 10);
    lbl4 = new OXLabel(hf4, new OHotString("&Handle by:"));
    txb4 = new OTextBuffer(256);
    MimeTypeList->GetAction(name, tmp);
    txb4->AddText(0, tmp);
    txt4 = new OXTextEntry(hf4, txb4, 104);
    txt4->Resize(250, txt4->GetDefaultHeight());
    hf4->AddFrame(lbl4, lyl);
    hf4->AddFrame(txt4, lyr);

    lv = new OLayoutHints(LHINTS_TOP | LHINTS_EXPAND_X, 5, 5, 2, 2);
    llv = new OLayoutHints(LHINTS_TOP | LHINTS_LEFT, 5, 5, 2, 0);

    AddFrame(Ihf, llv);
    AddFrame(ln1, lyln);
    AddFrame(hf1, lv);
    AddFrame(hf2, lv);
    AddFrame(hf3, lv);
    AddFrame(hf4, lv);
    AddFrame(ln2, lyln);

    MapSubwindows();
    ODimension size = GetDefaultSize();
    size.w += 10;
    size.h += 15;
    Resize(size);

    //---- position relative to the parent's window (the default was root 0,0!)
 
    XTranslateCoordinates(GetDisplay(),
                          main->GetId(), GetParent()->GetId(),
                          50, 50, &ax, &ay, &wdummy);

    Move(ax, ay);

    //---- make dialog non-resizable

    SetWMSize(size.w, size.h);
    SetWMSizeHints(size.w, size.h, size.w, size.h, 0, 0);

    sprintf(name, "%s File Type", add_mode ? "Add New" : "Edit");
    SetWindowName(name);
    SetIconName(name);
    SetClassHints("Explorer", "Explorer");

    SetMWMHints(MWM_DECOR_ALL | MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE |
                                MWM_DECOR_MINIMIZE | MWM_DECOR_MENU,
                MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE | 
                               MWM_FUNC_MINIMIZE,
                MWM_INPUT_MODELESS);

    MapWindow();
    _client->WaitFor(this);
}

OXEditMimeDialog::~OXEditMimeDialog() {

  delete Ok; delete Cancel;
  delete bframe;
  delete bly; delete bfly;

  delete SetIcon;
  delete icon1; delete Ily;

  delete ln1; delete lyln;

  delete lbl1; delete txt1; delete hf1;
  delete lbl2; delete txt2; delete hf2;
  delete lbl3; delete txt3; delete hf3;
  delete lbl4; delete txt4; delete hf4;

  delete lyl; delete lyr;
  delete lv; delete llv;

}

void OXEditMimeDialog::CloseWindow() {
  delete this;
}

int OXEditMimeDialog::ProcessMessage(long msg, long parm1, long parm2) {
  switch(GET_MSG(msg)) {
    case XC_COMMAND:

      switch(GET_SUBMSG(msg)) {
        case CM_BUTTON:
          switch(parm1) {
            case ID_OK:
              // get values
              { char *descr, *type, *pattern, *action;

              // description
              descr   = (char *) txb1->GetString();
              type    = (char *) txb2->GetString();
              pattern = (char *) txb3->GetString();
              action  = (char *) txb4->GetString();
              if (EditingMime) {
                // modify 
                MimeTypeList->Modify(EditingMime,
                      (descr[0] != '\0') ? strdup(descr) : (char *) NULL,
                      type, pattern, NULL, action);
              } else {
                // update 
                MimeTypeList->AddType( 
                      (descr[0] != '\0') ? strdup(descr) : (char *) NULL,
                      type, pattern, NULL, action);
              }
              }
            case ID_CANCEL:
              CloseWindow();
              break;

          }
          break;

        default:
          break;
      }
      break;

    default:
      break;
  }

  return True;
}
