



// YACL text editor: a simple program to demonstrate the use of the
// TextEditor class
//
// Author: M. A. Sridhar
// Date:   April 8, 1996


#include <fstream.h>

#include "base/version.h"

#include "ui/applic.h"
#include "ui/composit.h"
#include "ui/textedit.h"
#include "ui/menu.h"
#include "ui/stddlg.h"
#include "ui/cntroler.h"


// -------------------- AppWindow class ---------------------------------

class AppWindow: public UI_CompositeVObject {

public:
    AppWindow ();

    bool DoOpen ();

    bool DoSave ();

    bool DoQuit ();

    bool DoCut ();

    bool DoCopy ();

    bool DoPaste ();
    
    bool DoAbout ();
    
protected:
    bool Reconfigure (const UI_Rectangle& r);
    
    CL_String       _fileName;
    CL_String       _cutBuffer;
    fstream         _stream;
    UI_TextEditor*  _editor;
    UI_MenuBar*     _bar;
};


enum {
    ID_EDITOR       = 101,
    
    ID_MENU_FILE    = 201,
    ID_MENU_OPEN,
    ID_MENU_SAVE,
    ID_MENU_QUIT,

    ID_MENU_EDIT    = 220,
    ID_MENU_CUT,
    ID_MENU_COPY,
    ID_MENU_PASTE,

    ID_MENU_HELP    = 230,
    ID_MENU_ABOUT
};



typedef UI_EventBinding0<AppWindow> AppBind;

#if defined(__GNUC__)
template class UI_EventBinding0<AppWindow>;
#endif


AppWindow::AppWindow ()
    : UI_CompositeVObject (NULL, UI_Rectangle (70, 70, 400, 300))
{
    _editor = new UI_TextEditor (this, UI_Rectangle (0, 0, 400, 300));
    _bar    = new UI_MenuBar (this);
    UI_ViewID rootID = _bar->RootID();
    _bar->Add (ID_MENU_FILE, "&File", rootID);
    _bar->Add (ID_MENU_OPEN, "&Open...",    ID_MENU_FILE);
    _bar->Add (ID_MENU_SAVE, "&Save",       ID_MENU_FILE);
    _bar->AddSeparator (ID_MENU_FILE);
    _bar->Add (ID_MENU_QUIT, "&Quit", ID_MENU_FILE);

    _bar->Add (ID_MENU_EDIT,    "&Edit",  rootID);
    _bar->Add (ID_MENU_CUT,     "&Cut",   ID_MENU_EDIT);
    _bar->Add (ID_MENU_COPY,    "C&opy",  ID_MENU_EDIT);
    _bar->Add (ID_MENU_PASTE,   "&Paste", ID_MENU_EDIT);

    _bar->Add (ID_MENU_HELP,    "&Help",  rootID);
    _bar->Add (ID_MENU_ABOUT,   "&About TextEditor",   ID_MENU_HELP);
     
    (*_bar)[ID_MENU_OPEN]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoOpen));
    (*_bar)[ID_MENU_SAVE]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoSave));
    (*_bar)[ID_MENU_QUIT]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoQuit));
    
    (*_bar)[ID_MENU_CUT]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoCut));
    (*_bar)[ID_MENU_COPY]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoCopy));
    (*_bar)[ID_MENU_PASTE]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoPaste));

    (*_bar)[ID_MENU_ABOUT]->AddEventDependent
        (Event_Select, AppBind (this, &AppWindow::DoAbout));
}


bool AppWindow::DoOpen ()
{
    CL_String s = UI_FileSelectDialog (this);
    if (!s.Size())
        return TRUE;
#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__) || defined(__OS2__)
    _stream.open (s.AsPtr(), ios::in | ios::out | ios::binary);
#else
    _stream.open (s.AsPtr(), ios::in | ios::out);
#endif
    if (!_stream.good()) {
        UI_StandardDialog (CL_String ("File ") + s + " not found.",
                           "Open failure", this);
        return TRUE;
    }
    CL_String& model = (CL_String&) _editor->Model();
    if (! model.ReadStream (_stream))
        UI_StandardDialog ("File too big.", "Warning", this);
    _stream.close ();
#if defined(__OS2__)
    // The OS/2 TextEditor cannot handle more than 4k
    if (model.Size() >= 4096)
        UI_StandardDialog ("File too big.", "Warning", this);
#endif
    _fileName = s;

    Title() = "YACL Text Editor: " + s;
    _Controller->GiveFocusTo (_editor);
    return TRUE;
};


bool AppWindow::DoSave ()
{
#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__) || defined(__OS2__)
    _stream.open (_fileName.AsPtr(), ios::in | ios::out | ios::binary);
#else
    _stream.open (_fileName.AsPtr(), ios::in | ios::out);
#endif
    _Controller->BeginWait();
    _stream.seekg (ios::beg);
    CL_String& data = (CL_String&) _editor->Model();
    _stream.write (data.AsPtr(), data.Size());
    _stream.close();
    _Controller->EndWait ();
    return TRUE;
}


bool AppWindow::DoQuit ()
{
    _Application->Destroy (this);
    return TRUE;
}

    
bool AppWindow::DoCut ()
{
    CL_Interval sel = _editor->Selection();
    CL_String& model = (CL_String&) _editor->Model();
    _cutBuffer = model (sel.Low(), sel.Length());
//     CL_Error::Warning ("Selection: %s: '%s'", sel.AsString().AsPtr(),
//                        _cutBuffer.AsPtr());//DEBUG
    model (sel.Low(), sel.Length()) = "";
    return TRUE;
}


bool AppWindow::DoCopy ()
{
    CL_Interval sel = _editor->Selection();
    CL_String& model = (CL_String&) _editor->Model();
    _cutBuffer = model (sel.Low(), sel.Length());
//     CL_ByteArray b ((uchar*) _cutBuffer.AsPtr(), _cutBuffer.Size());
//     CL_Error::Warning ("Selection: %s: '%s'", sel.AsString().AsPtr(),
//                        b.AsString().AsPtr());//DEBUG
    return TRUE;
}


bool AppWindow::DoPaste ()
{
    CL_Interval sel = _editor->Selection();
    CL_String& model = (CL_String&) _editor->Model();
//     CL_Error::Warning ("Before: '%s' cutBuf '%s'\n",
//                        model.AsPtr(), _cutBuffer.AsPtr()); // DEBUG
    model.Insert (_cutBuffer, sel.Low()-1);
//     CL_Error::Warning ("After: '%s'\n", model.AsPtr()); // DEBUG
    return TRUE;
}

#if defined(__UNIX__) || defined(__OS2__)
#define END_OF_LINE "\n"
#else
#define END_OF_LINE "\r\n"
#endif

bool AppWindow::DoAbout ()
{
    CL_String msg = "Minimal TextEditor Version 0.2" END_OF_LINE END_OF_LINE;
    UI_StandardDialog (CL_String (msg) + "YACL version " + YACLVersion(),
                       "About TextEditor", this, UIS_Ok, UIS_Information);
    return TRUE;
}


bool AppWindow::Reconfigure (const UI_Rectangle& r)
{
    _editor->Shape() = UI_Rectangle (0, 0, r.Width(), r.Height());
    return TRUE;
}
        
    


// -------------------------- Main program ----------------------------


int UI_Application::Main (int, char* [])
{
    UI_CompositeVObject* root = new AppWindow;
    root->Title() = "YACL Text Editor";
    MakeTopWindow (root);
    Run();
    return 0;
}

