// Editor Window Routines
//
// written by Michael Riedel <Michael.Riedel@gmx.de>
//
     
#include <qpopmenu.h>
#include <qmlined.h>
#include <qfiledlg.h> 
#include <qmsgbox.h>
#include <qaccel.h>
#include <qlistbox.h>

#include <kfontdialog.h>
#include <klocale.h>
#include <kmsgbox.h>
#include <kapp.h>
#include <kstdaccel.h>
#include <kiconloader.h>

#include "Maker.h"
#include "Editor.h"
#include "Editor.moc"
#include "Dlgs/EditorSettingsDlg.h"
#include "Dlgs/ColorSet.h"



#define ID_LINE    		100
#define ID_GENERAL 		101
#define ID_MODE    		102
#define ID_DIRTY   		103
#define LINE_STR_MAX 	"Line: 000000 Col: 000"
#define LINE_STR     	"Line: %d Col: %d"



/////////////////////////////////////////////////////
//
//	 Global Variables -> later in config file
//
//	The name of the section in the cofig file that is used to
//	store information concerning the editor:
QString EditorSectionName = "Editor";
//
//	The (relative) path below kapp->kde_datadir(), in which the 
//	editor searches the for configuration files:
QString RulesDir 		  = "/KColorEditor/Keywords/";
//
//	Contains the index of the initially used mode; this index is
//  used to access the modesDir array:
int StartupModeIndex  = 0;
//
/////////////////////////////////////////////////////



/////////////////////////////////////////////////////
//
// con-/destructor(s)
//

/////////////////////////////////////////////////////
Editor::Editor(QWidget *parent, const char *name, const char* file)
	: KTopLevelWidget(name)
{
	warning("Editor::Editor()\n");
    resize(800, 600);

		// Loads the mode Names
	setupModes();

		// setup the text editing widget:
	setupView();

		// set up add. widgets:
	setupToolBar();
	setupMenuBar();
	setupStatusBar();

		// configure keys:
	setupKeystrokes();

  
	if(file)
	{
		if(!load(QString(file)))
			editbuffer->clear();
	}
	else
	{
		changeFileState("");
	}
	
        // add widget to list of editor windows (so other widgets can determine 
        // if there is already an Editor with the desired filename):
    Editors.append(this);
}
/////////////////////////////////////////////////////



/////////////////////////////////////////////////////
Editor::~Editor()
{
	warning("Editor::~Editor()\n");

	delete editbuffer;
	delete label;
	delete mainMenu;
	
    Editors.remove(this);
	if(Editors.count() == 0)
		kapp->exit();
}
/////////////////////////////////////////////////////



/////////////////////////////////////////////////////
QList<Editor> Editor::Editors;
/////////////////////////////////////////////////////



/////////////////////////////////////////////////////
//
// events
//

void Editor::resizeEvent(QResizeEvent* ev)
{
    KTopLevelWidget::resizeEvent(ev);
}

void Editor::closeEvent(QCloseEvent* ev)
{
		// accept the close event if user didn't select 'Cancel'
	if(!doSavingIfNeeded())
	{
	    ev->accept();
	    delete this;
	}
}



/////////////////////////////////////////////////////
//
// slots
//

void Editor::newFileSlot()
{
	if(!doSavingIfNeeded())
	{
		editbuffer->clear();
		changeFileState("");
	}
}

void Editor::openFileSlot()
{
	QFileDialog fd(".", "*.C", this , "", true);
	fd.setCaption(i18n("Select File To Load"));

	int result = fd.exec();
	QString fname = fd.selectedFile();

	if(result == QFileDialog::Accepted)
	{
		if(!doSavingIfNeeded())
			load(fname);
	}
}

void Editor::saveFileSlot()
{
	save();
}

void Editor::saveAsFileSlot()
{
	save(true);
}

void Editor::closeWindowSlot()
{
	close();
}

void Editor::saveFileAndCloseWindowSlot()
{
	save();		// save if dirty without asking user
	close();    // close window
}

void Editor::selectFontSlot()
{
	bool accepted;
	QStrList l; 
	QFont font = editbuffer->font();     // local copy of Editor font

		// This is a little bit too slow; is there any 
		// other possibility to retrieve information on
		// the installed fixed pitch fonts?	
	if(kapp->getKDEFonts(&l))
	{
		QStrList l2;
		const char* family = l.first();
		while(family)
		{
			QFont f(family);
			if(QFontInfo(f).fixedPitch())
				l2.append(family);
			family = l.next();
		}
		KFontDialog kfd(this, 0, true, &l2);
		kfd.setFont(font);
		accepted = kfd.exec();
		font = kfd.font();
	}
	else
		accepted = KFontDialog::getFont(font) == QDialog::Accepted;
	
    if(accepted)
	{
		editbuffer->settings().setFont(font);
		editbuffer->updateFromSettings();
	}
}

void Editor::searchAgainSlot()
{
}

void Editor::replaceAgainSlot()
{
}

void Editor::makeSlot()
{
	int index = fileName.findRev('/');
	QString path;
	if(index)
		path = fileName.left(index);
	else
		path = ".";
	Maker* m = new Maker(0, 0, path);
	m->show();
	m->startMake();
}

void Editor::optionsColorsSlot()
{
	ColorSet cs(*editbuffer->getColorizer(), editbuffer->settings().font(), this);
	connect(&cs, SIGNAL(applied()), this, SLOT(colorsAppliedSlot()));

	if(cs.exec() == QDialog::Accepted)
		editbuffer->repaint();

	// disconnect is done with destructor of QObject!
}

void Editor::colorsAppliedSlot()
{
	editbuffer->repaint();
}

void Editor::optionsConfigureKeysSlot()
{
	KKeyConfig* conf = KStdAccel::getKKeyConfig();
	conf->configureKeys(this);
}

void Editor::optionsSelectModeSlot(int id)
{
	modeMenu->setItemChecked(modeIndex + firstModeID, false);
	if(id >= firstModeID && id <= lastModeID)
	{
		modeIndex = id - firstModeID;	// save index of mode for later use!
		QString modeFile = modeFiles[modeIndex];
		if(!modeFile.isEmpty())
		{
				// change editor appearance:
			editbuffer->setNewMode(kapp->kde_datadir() + RulesDir + modeFile);
			modeMenu->setItemChecked(id, true);
		}
	}
	else
		debug("optionsSelectModeSlot() with invalid id.");
}

static EditorSettingsDlg* esd = 0;
void Editor::optionsSettingsSlot()
{
	EditorSettings es = editbuffer->settings();
	esd = new EditorSettingsDlg(es, this);
	connect(esd, SIGNAL(applied()), this, SLOT(editorSettingsApplied()));

	if(esd->exec() == QDialog::Accepted)
	{
		editbuffer->setSettings(esd->settings());
		editbuffer->updateFromSettings();
	}
		
	delete esd;
	esd = 0;
}

void Editor::editorSettingsApplied()
{
	if(esd)
	{
		editbuffer->setSettings(esd->settings());
		editbuffer->updateFromSettings();
	}
}

void Editor::helpIndexSlot()
{
	warning("function not implemented\n");
}

void Editor::helpAboutSlot()
{
    KMsgBox::message(0, "About KColorEditor", 
		  "KColorEditor Version 0.0.3\n"
		  "Programmed by Michael Riedel <Michael.Riedel@gmx.de>\n"
		  "Partially based on KEdit.\n\n"
		  "This program uses KDE and Qt and is covered under the GPL.\n"
		  "See \"LICENSE\" for more information.\n\n"
		  "THIS PROGRAM COMES WITH NO WARRANTY!",
		  KMsgBox::INFORMATION, "Ok");
}

void Editor::helpAboutQtSlot()
{
    KMsgBox::message(0, "About QT",
		"This program was developed with Qt, a cross-platform GUI library.\n\n"
		"Qt is a product of Troll Tech AS (http://www.troll.no).\n"
		"The free edition of Qt may be used freely to develop free software\n"
		"on the X Window System.\n\n"
		"If you develop non-free software or want to use Qt to develop\n"
		"software for Microsoft Windows, you need the professional edition.\n\n"
		"Please contact sales@troll.no for information and pricing.", KMsgBox::INFORMATION, "Ok");
}



/////////////////////////////////////////////////////
//
// slots connected to editbuffer sigs:
//

void Editor::updateDirtyFlagSlot()
{
	char* s = editbuffer->dirty() ? "*" : " ";    
   	label->changeItem(s, ID_DIRTY);
}

void Editor::insModeChangedSlot()
{
    if(editbuffer->isOverwriteMode())
	    label->changeItem(i18n("OVR"), ID_MODE);
	else
	    label->changeItem(i18n("INS"), ID_MODE);
}

void Editor::cursorPosChangedSlot()
{	
	int row, col;
	editbuffer->getCursorPosition(&row, &col);

	char s[50];
	sprintf(s, LINE_STR, row + 1, col + 1);
    label->changeItem(s, ID_LINE);
}

//#include <kwm.h>
void Editor::test()
{
	editbuffer->debugOutUL();

/* just a test...
	KWM kwm;
	static bool on = false;
	if(!on)
		kwm.darkenScreen();
	else
		kwm.refreshScreen();
	on = !on;
*/
}



/////////////////////////////////////////////////////
//
// slots connected to dropZone sigs:
//

void Editor::filesDroppedSlot(KDNDDropZone* dz)
{
	QStrList& list = dz->getURLList();
	
	char* s;
	for(s = list.first(); s != 0; s = list.next())
	{
			// This code does not work with URLs; only 
			// local files are loaded!
	
			// if there is a protocol part preceeding the file name,
			// eliminate it:
		QString f(s);
		int index = f.find(':');
		if(index >= 0)
		{
			if(f.left(index).lower() != "file")
			{
				warning("not a local file!");
				QMessageBox::information(this, 
										 "File Error", 
										 "Not a local file. It can't be loaded");
				return;
			}
			else
				f = f.right(f.length() - index - 1);
		}
		// else
			// no protocol part; file assumed to be on a local disk
			
		warning("file dropped <%s>\n", f.data());
/*
		
		Editor *e = new Editor(0, "editor", f.data());
		e->show();
*/
			// creating a new Editor widget leads to the deletion of all accelerator 
			// bindings; this is a quick hack to make the desired number of 
			// Editors run simultanously:
			// It is no permanent solution because the findEditorWidget() method does
			// not work any longer :-(
		if(fork() == 0)
		{
			QString name = kapp->kde_bindir() + "/kcoloreditor";
			warning("executing %s %s", name.data(), f.data());
			execl(name, name, f.data(), 0);
		}
	}
}



/////////////////////////////////////////////////////
//
// helper functions
//

void Editor::setTitle(const QString& name)
{
	QString s;
	if(name.isEmpty())
		s = "New File";
	else
	{
			// extract the file name only:
		int ix = name.findRev('/');
		if(ix != -1)
		{
			QString path = name.left(ix);
			QString n	 = name.right(name.length() - ix - 1);
			
			s = n;
			s += " in ";
			s += path;
		}
		else
    		s += name;
	}
    setCaption(s);
}

bool Editor::gotoLine(int line)
{
	int numL = editbuffer->numLines();
	int numV = editbuffer->numVisibleLines();
	int lastV = line + (numV >> 1) - 2;
	 
		// bring the desired line into the middle of the window (if possible)
	editbuffer->setCursorPosition(numL < lastV ? numL : lastV, 0);
	editbuffer->setCursorPosition(line, 0);
	return true;	
}



bool Editor::save(bool force)
{
	int result = false;
	
    if(isDirty() || force)
    {
		debug("buffer is dirty; will be saved!");
		if(fileName.isEmpty())
		{
			debug("filename is empty; will be asked!");
			QFileDialog fd(".", "*.*", this, 0, true);
			fd.setCaption(i18n("Select Filename To Save"));
			result = fd.exec();
			QString fname = fd.selectedFile();

			if(result == QFileDialog::Accepted)
			{
				result = editbuffer->saveTo(fname);
				changeFileState(fname);
			}
			else
				result = false;		
		}
		else
		{
			result = editbuffer->saveTo(fileName);
			changeFileState(fileName);
		}


/* show info in status line:
		QString msg = "File '";
		msg += fn; 
		msg += "' exists; renaming it to '" + backFile;
		msg += "'.";
   		warning(msg);
		label->changeItem(msg, ID_GENERAL);
*/		
    }
    else 
    {
		debug("buffer is not dirty; nothing to be saved!");
		result = true;
	}

    return result;
}



bool Editor::load(const QString& fname)
{
    disconnect(editbuffer, SIGNAL(dirtyChanged()), this, SLOT(updateDirtyFlagSlot()));
	bool retval = editbuffer->loadFile(fname);
    connect(editbuffer, SIGNAL(dirtyChanged()), this, SLOT(updateDirtyFlagSlot()));
	changeFileState(fname);
    return retval;
}


 
bool Editor::doSavingIfNeeded()
{
	bool cancelled = false;

    if(isDirty())
    {
		debug("buffer is dirty!");
	    label->changeItem(i18n("Changes saved."), ID_GENERAL);

		QString msg;
		if(!fileName.isEmpty())
		{
			msg = "Do you want to write the changes to file\n<";
			msg += fileName;
			msg += "> ?";
		}
		else
			msg = "Do you want to write the changes to a new file?";
			

		switch(QMessageBox::information(this, "File is dirty", msg, 
									 	"Save", "Don't Save",
										"Cancel", 0, 2))
		{
			case 0: 
					// set cancelled to true to indicate failed saving; editor will not close
				if(!save(true))
				{
					msg = "Couldn't save to file\n<";
					msg += fileName;
					msg += ">";
					if(QMessageBox::information(this, "Error", msg, "Doesn't matter", "Cancel", "", 1, 0) == 1)
						cancelled = true;		// could not be saved -> cancel op if user selecet cancel!
				}
				else
					changeFileState(fileName);					
				break;

			case 1: 
				break;
			case 2: 
				cancelled = true;
				break;
		}
    }
    else 
    {
		debug("buffer is not dirty!");
	    label->changeItem(i18n("No changes made. Nothing to be saved."), ID_GENERAL);
	}

	return cancelled;
}



void Editor::setupView()
{
    editbuffer = new KSyntaxMultiLineEdit(kapp->kde_datadir() + RulesDir + modeFiles[modeIndex],
    									  this, "EditBuffer");
	editbuffer->setFocus();
	
	dropZone = new KDNDDropZone(editbuffer, DndURL);

    connect(editbuffer, SIGNAL(dirtyChanged()), this, SLOT(updateDirtyFlagSlot()));
    connect(editbuffer, SIGNAL(cursorPosChanged()), this, SLOT(cursorPosChangedSlot()));
    connect(editbuffer, SIGNAL(insModeChanged()), this, SLOT(insModeChangedSlot()));
    connect(dropZone, SIGNAL(dropAction(KDNDDropZone*)), this, SLOT(filesDroppedSlot(KDNDDropZone*)));

		// make editbuffer my view:
	setView(editbuffer);
}



void Editor::setupMenuBar()
{
	QString strg = QString("\t") + i18n("Ctrl") + QString("+"),
			alt  = QString("\t") + i18n("Alt") + QString("+");

	
		// set up the menu bar:
    mainMenu = new KMenuBar(this, "MenuBar");

		// file menu:
    QPopupMenu* file = new QPopupMenu;
    file->insertItem(i18n("&New"), this, SLOT(newFileSlot()));
    file->insertItem(i18n("&Open..."), this, SLOT(openFileSlot()));
    file->insertItem(i18n("&Save") + strg + "S", this, SLOT(saveFileSlot()));
    file->insertItem(i18n("Save &As..."), this, SLOT(saveAsFileSlot()));
    file->insertSeparator();
    file->insertItem(i18n("&Close") + strg + "Q", this, SLOT(closeWindowSlot()));
    file->insertItem(i18n("Sa&ve And Close") + strg + "W", this, SLOT(saveFileAndCloseWindowSlot()));

		// the edit menu:
	int index;
	QPopupMenu* edit = new QPopupMenu;
	edit->insertItem(i18n("&Undo"));
	edit->insertItem(i18n("Do &Again"));
	edit->insertSeparator();	
	edit->insertItem(i18n("&Cut"));
	edit->insertItem(i18n("C&opy"));
	edit->insertItem(i18n("&Paste"));
	edit->insertSeparator();	
	edit->insertItem(i18n("&Search..."), editbuffer, SLOT(Search()));
	index = edit->insertItem(i18n("&Search %s Again"), this, SLOT(searchAgainSlot()));
	edit->setItemEnabled(index, false);
	edit->insertItem(i18n("&Replace..."), editbuffer, SLOT(Replace()));
	index = edit->insertItem(i18n("&Replace %s with %s Again"), this, SLOT(replaceAgainSlot()));
	edit->setItemEnabled(index, false);
	edit->insertSeparator();	
	edit->insertItem(i18n("&Goto Line..."), editbuffer, SLOT(GotoLine()));

	QPopupMenu* options = new QPopupMenu;
	index = options->insertItem(i18n("&Colors..."), this, SLOT(optionsColorsSlot()));
	edit->setItemEnabled(index, false);
	options->insertItem(i18n("&Settings..."), this, SLOT(optionsSettingsSlot()));
	options->insertItem(i18n("Select &Font...") + strg + "F", this, SLOT(selectFontSlot()));
	options->insertItem(i18n("Keys...") + strg + "K", this, SLOT(optionsConfigureKeysSlot()));

		// append mode names to the options menu:
/*	modeMenu = new QPopupMenu; 				// setup member variable 
	options->insertItem(i18n("Select Mode..."), modeMenu);
	modeMenu->setCheckable(true);			// make menu show checkmarks
	modeFiles.setPath(kapp->kde_datadir() + RulesDir);
	modeFiles.setNameFilter("*.rules");
	firstModeID = lastModeID = -1;
	for(unsigned int i = 0; i < modeFiles.count(); i++)
	{
		QString r(modeFiles[i]);
		QString mode(r.left(r.find('.')));	// r always contains '.'!
		int id = modeMenu->insertItem(i18n(mode));
		if(firstModeID == -1)
			firstModeID = id;
		lastModeID = id;
	}		
*/
		// modeMenu was (hopefully) created earlier:
	options->insertItem(i18n("Select Mode..."), modeMenu);
	connect(mainMenu, SIGNAL(activated(int)), this, SLOT(optionsSelectModeSlot(int)));
	
	
		// make menu:
	QPopupMenu* make = new QPopupMenu;
	make->insertItem("(&Make...)", this, SLOT(makeSlot()));
	make->insertItem("(Show Undo Entries)", this, SLOT(test()));

		// the help menu:
	QPopupMenu* help = new QPopupMenu;
	help->insertItem(i18n("&Index..."), this, SLOT(helpIndexSlot()));
    help->insertSeparator();
	help->insertItem(i18n("&About..."), this, SLOT(helpAboutSlot()));
	help->insertItem(i18n("About &Qt..."), this, SLOT(helpAboutQtSlot()));
	
    mainMenu->insertItem(i18n("&File"), file);
    mainMenu->insertItem(i18n("&Edit"), edit);
    mainMenu->insertItem(i18n("(&Make)"), make);
    mainMenu->insertItem(i18n("&Options"), options);
    mainMenu->insertSeparator();
    mainMenu->insertItem(i18n("&Help"), help);

    setMenu(mainMenu);
}
 


void Editor::setupStatusBar()
{
    label = new KStatusBar( this );

		// Create items with max sizes:
    label->insertItem(LINE_STR_MAX, ID_LINE);
    label->insertItem("XXX", ID_MODE);
    label->insertItem("*", ID_DIRTY);
    label->insertItem("", ID_GENERAL);

		// set initial text in items:
	char s[50];
	sprintf(s, LINE_STR, 1, 1);
    label->changeItem(s, ID_LINE);
    label->changeItem("INS", ID_MODE);
    label->changeItem("", ID_DIRTY);
    label->changeItem("", ID_GENERAL);

    label->setInsertOrder(KStatusBar::RightToLeft);
    label->setAlignment(ID_MODE, AlignCenter);

    setStatusBar(label);
}



void Editor::setupToolBar()
{
  toolbar = new KToolBar(this);

  KIconLoader *loader = kapp->getIconLoader();

  QPixmap pixmap;

  pixmap = loader->loadIcon("filenew2.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), this,
		      SLOT(newFileSlot()), TRUE, i18n("New File"));


  pixmap = loader->loadIcon("fileopen.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), this,
		      SLOT(openFileSlot()), TRUE, i18n("Open File"));

  pixmap = loader->loadIcon("filefloppy.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), this,
		      SLOT(saveFileSlot()), TRUE, i18n("Save Current File"));

  toolbar->insertSeparator();
  toolbar->insertSeparator();

  pixmap = loader->loadIcon("editcopy.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), editbuffer,
		      SLOT(copyText()), TRUE, i18n("Copy"));

  pixmap = loader->loadIcon("editpaste.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), editbuffer,
		      SLOT(paste()), TRUE, i18n("Paste"));

  pixmap = loader->loadIcon("editcut.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), editbuffer,
		      SLOT(cut()), TRUE, i18n("Cut"));


/*
  pixmap = loader->loadIcon("fileprint.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), this,
		      SLOT(print()), TRUE, i18n("Print Document"));
*/

  toolbar->insertSeparator();
  toolbar->insertSeparator();

  pixmap = loader->loadIcon("help.xpm");
  toolbar->insertButton(pixmap, 0,
		      SIGNAL(clicked()), this,
		      SLOT(helpIndexSlot()), TRUE, i18n("Help"));

  addToolBar(toolbar);
}



void Editor::setupKeystrokes()
{
	const char* sEditor = "Editor";
	const char* sEditBuffer = "EditBuffer";

		// Init KeyConfig:
	KStdAccel* conf = (KStdAccel*)KStdAccel::getKKeyConfig();
	conf->registerWidget(sEditBuffer, editbuffer);
	conf->registerWidget(sEditor, this);


		// Cursor movement actions:
	conf->addKey("Start Of Doc", CTRL + Key_Home);
	conf->addKey("End Of Doc", CTRL + Key_End);
	conf->addKey("Start Of Line", conf->home());
	conf->addKey("End Of Line", conf->end());
	conf->addKey("Cursor Left", Key_Left);
	conf->addKey("Cursor Right", Key_Right);
	conf->addKey("Cursor Up", Key_Up);
	conf->addKey("Cursor Down", Key_Down);
	conf->addKey("Word Left", CTRL + Key_Left);
	conf->addKey("Word Right", CTRL + Key_Right);
	conf->addKey("Page Up", conf->prior());
	conf->addKey("Page Down", conf->next());
	
		// Cursor movement actions with marking!
	conf->addKey("Start Of Doc (Mark)", SHIFT + CTRL + Key_Home);
	conf->addKey("End Of Doc (Mark)", SHIFT + CTRL + Key_End);
	conf->addKey("Start Of Line (Mark)", SHIFT + conf->home());
	conf->addKey("End Of Line (Mark)", SHIFT + conf->end());
	conf->addKey("Cursor Left (Mark)", SHIFT + Key_Left);
	conf->addKey("Cursor Right (Mark)", SHIFT + Key_Right);
	conf->addKey("Cursor Up (Mark)", SHIFT + Key_Up);
	conf->addKey("Cursor Down (Mark)", SHIFT + Key_Down);
	conf->addKey("Word Left (Mark)", SHIFT + CTRL + Key_Left);
	conf->addKey("Word Right (Mark)", SHIFT + CTRL + Key_Right);
	conf->addKey("Page Up (Mark)", SHIFT + conf->prior());
	conf->addKey("Page Down (Mark)", SHIFT + conf->next());

		// Editing actions:
	conf->addKey("Cut", conf->cut());
	conf->addKey("Copy", conf->copy());
	conf->addKey("Paste", conf->paste());
	conf->addKey("Kill Line", CTRL + Key_K);
	conf->addKey("New Line", Key_Return);
	conf->addKey("Delete", Key_Delete);
	conf->addKey("Backspace", Key_Backspace);
	conf->addKey("Undo", conf->undo());
	conf->addKey("Redo", CTRL + Key_R);
	conf->addKey("Toggle Mode", Key_Insert);

		// Additional actions:
	conf->addKey("Select Font", CTRL + Key_F);
	conf->addKey("New File", conf->openNew());
	conf->addKey("Open File", conf->open());
	conf->addKey("Save File", conf->save());
	conf->addKey("Close", conf->quit());
	conf->addKey("Save And Close", CTRL + Key_E);
	

		// Connect cursor movement actions:
	conf->connectFunction(sEditBuffer, "Start Of Doc", editbuffer, SLOT(UFStartOfText()));
	conf->connectFunction(sEditBuffer, "End Of Doc", editbuffer, SLOT(UFEndOfText()));
	conf->connectFunction(sEditBuffer, "Start Of Line", editbuffer, SLOT(UFStartOfLine()));
	conf->connectFunction(sEditBuffer, "End Of Line", editbuffer, SLOT(UFEndOfLine()));
	conf->connectFunction(sEditBuffer, "Cursor Left", editbuffer, SLOT(UFCursorLeft()));
	conf->connectFunction(sEditBuffer, "Cursor Right", editbuffer, SLOT(UFCursorRight()));
	conf->connectFunction(sEditBuffer, "Cursor Up", editbuffer, SLOT(UFCursorUp()));
	conf->connectFunction(sEditBuffer, "Cursor Down", editbuffer, SLOT(UFCursorDown()));
	conf->connectFunction(sEditBuffer, "Word Left", editbuffer, SLOT(UFWordLeft()));
	conf->connectFunction(sEditBuffer, "Word Right", editbuffer, SLOT(UFWordRight()));
	conf->connectFunction(sEditBuffer, "Page Up", editbuffer, SLOT(UFPageUp()));
	conf->connectFunction(sEditBuffer, "Page Down", editbuffer, SLOT(UFPageDown()));

		// Connect cursor movement actions  with marking:
	conf->connectFunction(sEditBuffer, "Start Of Doc (Mark)", editbuffer, SLOT(UFStartOfTextM()));
	conf->connectFunction(sEditBuffer, "End Of Doc (Mark)", editbuffer, SLOT(UFEndOfTextM()));
	conf->connectFunction(sEditBuffer, "Start Of Line (Mark)", editbuffer, SLOT(UFStartOfLineM()));
	conf->connectFunction(sEditBuffer, "End Of Line (Mark)", editbuffer, SLOT(UFEndOfLineM()));
	conf->connectFunction(sEditBuffer, "Cursor Left (Mark)", editbuffer, SLOT(UFCursorLeftM()));
	conf->connectFunction(sEditBuffer, "Cursor Right (Mark)", editbuffer, SLOT(UFCursorRightM()));
	conf->connectFunction(sEditBuffer, "Cursor Up (Mark)", editbuffer, SLOT(UFCursorUpM()));
	conf->connectFunction(sEditBuffer, "Cursor Down (Mark)", editbuffer, SLOT(UFCursorDownM()));
	conf->connectFunction(sEditBuffer, "Word Left (Mark)", editbuffer, SLOT(UFWordLeftM()));
	conf->connectFunction(sEditBuffer, "Word Right (Mark)", editbuffer, SLOT(UFWordRightM()));
	conf->connectFunction(sEditBuffer, "Page Up (Mark)", editbuffer, SLOT(UFPageUpM()));
	conf->connectFunction(sEditBuffer, "Page Down (Mark)", editbuffer, SLOT(UFPageDownM()));

		// Connect additional actions:	
	conf->connectFunction(sEditBuffer, "Cut", editbuffer, SLOT(UFCut()));
	conf->connectFunction(sEditBuffer, "Copy", editbuffer, SLOT(UFCopy()));
	conf->connectFunction(sEditBuffer, "Paste", editbuffer, SLOT(UFPaste()));
	conf->connectFunction(sEditBuffer, "Kill Line", editbuffer, SLOT(UFKillLine()));
	conf->connectFunction(sEditBuffer, "New Line", editbuffer, SLOT(UFNewLine()));	
	conf->connectFunction(sEditBuffer, "Delete", editbuffer, SLOT(UFDelete()));
	conf->connectFunction(sEditBuffer, "Backspace", editbuffer, SLOT(UFBackspace()));	
	conf->connectFunction(sEditBuffer, "Undo", editbuffer, SLOT(UFUndo()));
	conf->connectFunction(sEditBuffer, "Redo", editbuffer, SLOT(UFRedo()));	
	conf->connectFunction(sEditBuffer, "Toggle Mode", editbuffer, SLOT(UFInsertToggle()));	

		// Connect additional actions to this:
	conf->connectFunction(sEditor, "Select Font", this, SLOT(selectFontSlot()));
	conf->connectFunction(sEditor, "New File", this, SLOT(newFileSlot()));
	conf->connectFunction(sEditor, "Open File", this, SLOT(openFileSlot()));
	conf->connectFunction(sEditor, "Save File", this, SLOT(saveFileSlot()));
	conf->connectFunction(sEditor, "Close", this, SLOT(closeWindowSlot()));
	conf->connectFunction(sEditor, "Save And Close", this, SLOT(saveFileAndCloseWindowSlot()));
}



void Editor::changeFileState(const QString& name)
{
	setTitle(name);
	updateDirtyFlagSlot();
    fileName = name;
}



void Editor::setupModes()
{
	modeMenu = new QPopupMenu; 				// setup member variable 
	modeMenu->setCheckable(true);			// make menu show checkmarks

	modeFiles.setPath(kapp->kde_datadir() + RulesDir);
	modeFiles.setNameFilter("*.rules");
	firstModeID = lastModeID = -1;
	for(unsigned int i = 0; i < modeFiles.count(); i++)
	{
		QString r(modeFiles[i]);
		QString mode(r.left(r.find('.')));	// r always contains '.'!
		int id = modeMenu->insertItem(i18n(mode));
		if(firstModeID == -1)
			firstModeID = id;
		lastModeID = id;
	}		
	
	modeIndex = StartupModeIndex;
	modeMenu->setItemChecked(firstModeID + modeIndex, true);
}



/////////////////////////////////////////////////////
//
// static functions
//

Editor* Editor::findEditorWidget(QString& filename)
{
	for(Editor* e = Editors.first(); e != 0; e = Editors.next())
		if(filename == e->fileName)
			return e;

	return 0;
}

