/***************************************************************************
* $Id$
**
* Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
**
* This file is part of an example program for Qt.  This example
* program may be used, distributed and modified without limitation.
**
****************************************************************************/

import org.kde.qt.*;
import java.util.ArrayList;

class Editor extends QWidget
{
private   QMenuBar 	   m;
private   QMultiLineEdit e;
private   QPrinter        printer = new QPrinter();
private   QPopupMenu	   save_as;
private   QPopupMenu	   open_as;
private   boolean changed;


private   boolean no_writing = false;

static ArrayList codecList = null;

static final int Uni = 0;
static final int MBug = 1;
static final int Lat1 = 2;
static final int Local = 3;
static final int Guess = 4;
static final int Codec = 5;


Editor( )
{
	this(null, null);
}

Editor( QWidget  parent , String  name )
{
    super( parent, name, WDestructiveClose );
    m = new QMenuBar( this, "menu" );

    QPopupMenu  file = new QPopupMenu(this);
    m.insertItem( "&File", file );

    file.insertItem( "&New",   this, SLOT("newDoc()"),   new QKeySequence(ALT+Key_N) );
    file.insertItem( "&Open...",  this, SLOT("load()"),     new QKeySequence(ALT+Key_O) );
    file.insertItem( "&Save...",  this, SLOT("save()"),     new QKeySequence(ALT+Key_S) );
    file.insertSeparator();
    open_as = new QPopupMenu(file);
    file.insertItem( "Open &As",  open_as );
    save_as = new QPopupMenu(file);
    file.insertItem( "Sa&ve As",  save_as );
    file.insertItem( "Add &Encoding", this, SLOT("addEncoding()") );    
    file.insertSeparator();
    file.insertItem( "&Print...", this, SLOT("print()"),    new QKeySequence(ALT+Key_P) );
    file.insertSeparator();
    file.insertItem( "&Close", this, SLOT("close()"),new QKeySequence(ALT+Key_W) );
    file.insertItem( "&Quit",  qApp(), SLOT("closeAllWindows()"),     new QKeySequence(ALT+Key_Q) );

    connect( save_as, SIGNAL("activated(int)"), this, SLOT("saveAsEncoding(int)") );
    connect( open_as, SIGNAL("activated(int)"), this, SLOT("openAsEncoding(int)") );
    rebuildCodecList();

    QPopupMenu  edit = new QPopupMenu(m);
    m.insertItem( "&Edit", edit );

    edit.insertItem( "To &Uppercase",   this, SLOT("toUpper()"),   new QKeySequence(ALT+Key_U) );
    edit.insertItem( "To &Lowercase",   this, SLOT("toLower()"),   new QKeySequence(ALT+Key_L) );
    edit.insertSeparator();
    edit.insertItem( "&Select Font" ,	 this, SLOT("getFont()"),     new QKeySequence(ALT+Key_F) );
    changed = false;
    e = new QMultiLineEdit( this, "editor" );
    connect( e, SIGNAL(" textChanged()"), this, SLOT(" textChanged()") );

    // We use Unifont - if you have it installed you'll see all
    // Unicode character glyphs.
    //
    // Unifont only comes in one pixel size, so we cannot let
    // it change pixel size as the display DPI changes.
    //
    QFont unifont = new QFont("unifont",16,50); unifont.setPixelSize(16);
    e.setFont( unifont );

    e.setFocus();
}


public void getFont()
{
    boolean[] ok = { true };
    QFont f = QFontDialog.getFont( ok, e.font() );
    if ( ok[0] ) {
        e.setFont( f );
    }
}



void rebuildCodecList()
{
    codecList = new ArrayList();
    QTextCodec codec = null;
    int i;
    for (i = 0; (codec = QTextCodec.codecForIndex(i)) != null; i++)
	codecList.add( codec );
    int n = codecList.size();
    for (int pm=0; pm<2; pm++) {
	QPopupMenu menu = pm != 0 ? open_as : save_as;
	menu.clear();
	String local = "Local (";
	local += QTextCodec.codecForLocale().name();
	local += ")";
	menu.insertItem( local, Local );
	menu.insertItem( "Unicode", Uni );
	menu.insertItem( "Latin1", Lat1 );
	menu.insertItem( "Microsoft Unicode", MBug );
	if ( pm != 0 )
	    menu.insertItem( "[guess]", Guess );
	for ( i = 0; i < n; i++ )
	    menu.insertItem( ((QTextCodec) codecList.get(i)).name(), Codec + i );
    }
}

void newDoc()
{
    Editor ed = new Editor();
    if ( qApp().desktop().size().width() < 450
	 || qApp().desktop().size().height() < 450 ) {
	ed.showMaximized();
    } else {
	ed.resize( 400, 400 );
	ed.show();
    }
}


void load()
{
    String fn = QFileDialog.getOpenFileName( "", "", this );
    if ( fn != null )
	load( fn, -1 );
}

void load( String fileName )
{
	load(fileName, -1);
}

void load( String fileName, int code )
{
    QFile f = new QFile( fileName );
    if ( !f.open( QIODevice.IO_ReadOnly ) )
	return;

    e.setAutoUpdate( false );

    QTextStream t = new QTextStream(f);
    if ( code >= Codec )
	t.setCodec( (QTextCodec) codecList.get(code-Codec) );
    else if ( code == Uni )
	t.setEncoding( QTextStream.Unicode );
    else if ( code == MBug )
	t.setEncoding( QTextStream.UnicodeReverse );
    else if ( code == Lat1 )
	t.setEncoding( QTextStream.Latin1 );
    else if ( code == Guess ) {
	f = new QFile(fileName);
	f.open(QIODevice.IO_ReadOnly);
	StringBuffer buffer = new StringBuffer();
	int l = 256;
	l=(int)f.readBlock(buffer,l);
	QTextCodec codec = QTextCodec.codecForContent(buffer.toString(), l);
	if ( codec != null ) {
	    QMessageBox.information(this,"Encoding","Codec: "+codec.name());
	    t.setCodec( codec );
	}
    }
    e.setText( t.read() );
    f.close();

    e.setAutoUpdate( true );
    e.repaint();
    setCaption( fileName );

    changed = false;
}

void openAsEncoding( int code )
{
    //storing filename (proper save) is left as an exercise...
    String fn = QFileDialog.getOpenFileName( "", "", this );
    if ( !fn.equals("") )
	load( fn, code );
}

boolean save()
{
    //storing filename (proper save) is left as an exercise...
    String fn = QFileDialog.getSaveFileName( "", "", this );
    if ( !fn.equals("") )
	return saveAs( fn );
    return false;
}

void saveAsEncoding( int code )
{
    //storing filename (proper save) is left as an exercise...
    String fn = QFileDialog.getSaveFileName( "", "", this );
    if ( !fn.equals("") )
	saveAs( fn, code );
}

void addEncoding()
{
    String fn = QFileDialog.getOpenFileName( "", "*.map", this );
    if ( !fn.equals("") ) {
	QFile f = new QFile(fn);
	if (f.open(QIODevice.IO_ReadOnly)) {
	    if (QTextCodec.loadCharmap(f) != null) {
		rebuildCodecList();
	    } else {
		QMessageBox.warning(null,"Charmap error",
		    "The file did not contain a valid charmap.\n\n"
		    + "A charmap file should look like this:\n"
		       + "  <code_set_name> thename\n"
		       + "  <escape_char> /\n"
		       + "  % alias thealias\n"
		       + "  CHARMAP\n"
		       + "  <tokenname> /x12 <U3456>\n"
		       + "  <tokenname> /xAB/x12 <U0023>\n"
		       + "  ...\n"
		       + "  END CHARMAP\n"
		);
	    }
	}
    }
}


boolean saveAs( String fileName )
{
	return saveAs(fileName, -1);
}

boolean saveAs( String fileName, int code )
{
    QFile f = new QFile( fileName );
    if ( no_writing || !f.open( QIODevice.IO_WriteOnly ) ) {
	QMessageBox.warning(this,"I/O Error",
		    "The file could not be opened.\n\n"
			+fileName);
	return false;
    }
    QTextStream t = new QTextStream(f);
    if ( code >= Codec )
	t.setCodec( (QTextCodec) codecList.get(code-Codec) );
    else if ( code == Uni )
	t.setEncoding( QTextStream.Unicode );
    else if ( code == MBug )
	t.setEncoding( QTextStream.UnicodeReverse );
    else if ( code == Lat1 )
	t.setEncoding( QTextStream.Latin1 );
	t.writeRawBytes(e.text(), e.text().length());
    f.close();
    setCaption( fileName );
    changed = false;
    return true;
}

void print()
{
    if ( printer.setup(this) ) {		// opens printer dialog
	printer.setFullPage(true);		// we'll set our own margins
	QPainter p = new QPainter();
	p.begin( printer );			// paint on printer
	p.setFont( e.font() );
	QFontMetrics fm = p.fontMetrics();
	QPaintDeviceMetrics metrics = new QPaintDeviceMetrics( printer ); // need width/height
						 // of printer surface
	int MARGIN = metrics.logicalDpiX() / 2; // half-inch margin
	int yPos        = MARGIN;		// y position for each line

	for( int i = 0 ; i < e.numLines() ; i++ ) {
	    if ( printer.aborted() )
		break;
	    if ( yPos + fm.lineSpacing() > metrics.height() - MARGIN ) {
		// no more room on this page
		if ( !printer.newPage() )          // start new page
		    break;                           // some error
		yPos = MARGIN;			 // back to top of page
	    }
	    p.drawText( MARGIN, yPos, metrics.width() - 2*MARGIN,
			fm.lineSpacing(), ExpandTabs, e.textLine( i ) );
	    yPos += fm.lineSpacing();
	}
	p.end();				// send job to printer
    }
}

protected void resizeEvent( QResizeEvent event )
{
    if ( e != null && m != null )
	e.setGeometry( 0, m.height(), width(), height() - m.height() );
}

protected void closeEvent( QCloseEvent event )
{
    event.accept();

    if ( changed ) { // the text has been changed
	switch ( QMessageBox.warning( this, "Qwerty",
					"Save changes to Document?",
					tr("&Yes"),
					tr("&No"),
					tr("Cancel"),
					0, 2) ) {
	case 0: // yes
	    if ( save() )
		event.accept();
	    else
		event.ignore();
	    break;
	case 1: // no
	    event.accept();
	    break;
	default: // cancel
	    event.ignore();
	    break;
	}
    }
}

void toUpper()
{
    e.setText(e.text().toUpperCase());
}

void toLower()
{
    e.setText(e.text().toLowerCase());
}

void textChanged()
{
    changed = true;
}
}
