/***************************************************************************
 *   Copyright (C) 2003 by S�astien Laot                                 *
 *   slaout@linux62.org                                                    *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <tqdragobject.h>
#include <tqdom.h>
#include <tqpainter.h>
#include <tqstyle.h>
#include <tdestyle.h>
#include <tqtooltip.h>
#include <tqlistview.h>
#include <tqcursor.h>
#include <tqsimplerichtext.h>
#include <tqpushbutton.h>
#include <ktextedit.h>
#include <tqpoint.h>
#include <tqstringlist.h>
#include <tdeapplication.h>
#include <tdeglobalsettings.h>
#include <kopenwith.h>
#include <kservice.h>
#include <tdelocale.h>
#include <kglobalaccel.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tdefiledialog.h>
#include <tdeaboutdata.h>
#include <klineedit.h>
#include <ksavefile.h>
#include <kdebug.h>
#include <tqvbox.h>

#include <unistd.h> // For sleep()

#include <tdepopupmenu.h>
#include <kiconloader.h>
#include <krun.h>

#include <tqtoolbar.h>
#include <tqclipboard.h>

#include <tdemessagebox.h>
#include <tqinputdialog.h>

#include <tqlayout.h>

#include <stdlib.h>     // rand() function
#include <tqdatetime.h>  // seed for rand()

#include "basket.h"
#include "note.h"
#include "notedrag.h"
#include "notefactory.h"
#include "noteedit.h"
#include "tagsedit.h"
#include "xmlwork.h"
#include "global.h"
#include "backgroundmanager.h"
#include "settings.h"
#include "tools.h"
#include "debugwindow.h"
#include "exporterdialog.h"
#include "popupmenu.h"
#ifdef HAVE_LIBGPGME
#include "kgpgme.h"
#endif

#include <iostream>

/** Class NoteSelection: */

NoteSelection* NoteSelection::nextStacked()
{
	// First, search in the childs:
	if (firstChild) {
		if (firstChild->note && firstChild->note->content()) {
			return firstChild;
		}
		else {
			return firstChild->nextStacked();
		}
	}

	// Then, in the next:
	if (next) {
		if (next->note && next->note->content()) {
			return next;
		}
		else {
			return next->nextStacked();
		}
	}

	// And finally, in the parent:
	NoteSelection *node = parent;
	while (node)
		if (node->next)
			if (node->next->note && node->next->note->content())
				return node->next;
			else
				return node->next->nextStacked();
		else
			node = node->parent;

	// Not found:
	return 0;
}

NoteSelection* NoteSelection::firstStacked()
{
	if (!this)
		return 0;

	if (note && note->content())
		return this;
	else
		return nextStacked();
}

void NoteSelection::append(NoteSelection *node)
{
	if (!this || !node)
		return;

	if (firstChild) {
		NoteSelection *last = firstChild;
		while (last->next)
			last = last->next;
		last->next = node;
	} else
		firstChild = node;

	while (node) {
		node->parent = this;
		node = node->next;
	}
}

int NoteSelection::count()
{
	if (!this)
		return 0;

	int count = 0;

	for (NoteSelection *node = this; node; node = node->next)
		if (node->note && node->note->content())
			++count;
		else
			count += node->firstChild->count();

	return count;
}

TQValueList<Note*> NoteSelection::parentGroups()
{
	TQValueList<Note*> groups;

	// For each note:
	for (NoteSelection *node = firstStacked(); node; node = node->nextStacked())
		// For each parent groups of the note:
		for (Note *note = node->note->parentNote(); note; note = note->parentNote())
			// Add it (if it was not already in the list):
			if (!note->isColumn() && !groups.contains(note))
				groups.append(note);

	return groups;
}

/** Class DecoratedBasket: */

DecoratedBasket::DecoratedBasket(TQWidget *parent, const TQString &folderName, const char *name, WFlags fl)
 : TQWidget(parent, name, fl)
{
	m_layout = new TQVBoxLayout(this);
	m_filter = new FilterBar(this);
	m_basket = new Basket(this, folderName);
	m_layout->addWidget(m_basket);
	setFilterBarPosition(Settings::filterOnTop());

	m_filter->setShown(true);
	m_basket->setFocus(); // To avoid the filter bar have focus on load

	connect( m_filter, TQ_SIGNAL(newFilter(const FilterData&)), m_basket, TQ_SLOT(newFilter(const FilterData&)) );
	connect( m_filter, TQ_SIGNAL(escapePressed()),              m_basket, TQ_SLOT(cancelFilter())               );
	connect( m_filter, TQ_SIGNAL(returnPressed()),              m_basket, TQ_SLOT(validateFilter())             );

	connect( m_basket, TQ_SIGNAL(postMessage(const TQString&)),      Global::bnpView, TQ_SLOT(postStatusbarMessage(const TQString&)) );
	connect( m_basket, TQ_SIGNAL(setStatusBarText(const TQString&)), Global::bnpView, TQ_SLOT(setStatusBarHint(const TQString&))     );
	connect( m_basket, TQ_SIGNAL(resetStatusBarText()),             Global::bnpView, TQ_SLOT(updateStatusBarHint())                );
}

DecoratedBasket::~DecoratedBasket()
{
}

void DecoratedBasket::setFilterBarPosition(bool onTop)
{
	m_layout->remove(m_filter);
	if (onTop) {
		m_layout->insertWidget(0, m_filter);
		setTabOrder(this/*(TQWidget*)parent()*/, m_filter);
		setTabOrder(m_filter, m_basket);
		setTabOrder(m_basket, (TQWidget*)parent());
	} else {
		m_layout->addWidget(m_filter);
		setTabOrder(this/*(TQWidget*)parent()*/, m_basket);
		setTabOrder(m_basket, m_filter);
		setTabOrder(m_filter, (TQWidget*)parent());
	}
}

void DecoratedBasket::setFilterBarShown(bool show, bool switchFocus)
{
//	m_basket->setShowFilterBar(true);//show);
//	m_basket->save();
	// In this order (m_basket and then m_filter) because setShown(false)
	//  will call resetFilter() that will update actions, and then check the
	//  Ctrl+F action whereas it should be unchecked
	//  FIXME: It's very uggly all those things
	m_filter->setShown(true);//show);
	if (show) {
		if (switchFocus)
			m_filter->setEditFocus();
	} else if (m_filter->hasEditFocus())
		m_basket->setFocus();
}

void DecoratedBasket::resetFilter()
{
	m_filter->reset();
}

/** Class TransparentWidget */

TransparentWidget::TransparentWidget(Basket *basket)
 : TQWidget(basket->viewport(), "", TQt::WNoAutoErase), m_basket(basket)
{
	setFocusPolicy(TQWidget::NoFocus);
	setWFlags(TQt::WNoAutoErase);
	setMouseTracking(true); // To receive mouseMoveEvents

	basket->viewport()->installEventFilter(this);
}

/*void TransparentWidget::reparent(TQWidget *parent, WFlags f, const TQPoint &p, bool showIt)
{
	TQWidget::reparent(parent, TQt::WNoAutoErase, p, showIt);
}*/

void TransparentWidget::setPosition(int x, int y)
{
	m_x = x;
	m_y = y;
}

void TransparentWidget::paintEvent(TQPaintEvent*event)
{
	TQWidget::paintEvent(event);
	TQPainter painter(this);

//	painter.save();

	painter.translate(-m_x, -m_y);
	m_basket->drawContents(&painter, m_x, m_y, width(), height());

//	painter.restore();
//	painter.setPen(TQt::blue);
//	painter.drawRect(0, 0, width(), height());
}

void TransparentWidget::mouseMoveEvent(TQMouseEvent *event)
{
	TQMouseEvent *translated = new TQMouseEvent(TQEvent::MouseMove, event->pos() + TQPoint(m_x, m_y), event->button(), event->state());
	m_basket->contentsMouseMoveEvent(translated);
	delete translated;
}

bool TransparentWidget::eventFilter(TQObject */*object*/, TQEvent *event)
{
	// If the parent basket viewport has changed, we should change too:
	if (event->type() == TQEvent::Paint)
		update();

	return false; // Event not consumed, in every cases (because it's only a notification)!
}

/** Class Basket: */

const int Basket::FRAME_DELAY = 50/*1500*/; // Delay between two animation "frames" in milliseconds

/*
 * Convenient function (defined in note.cpp !):
 */
void drawGradient( TQPainter *p, const TQColor &colorTop, const TQColor & colorBottom,
                   int x, int y, int w, int h,
                   bool sunken, bool horz, bool flat  );

/*
 * Defined in note.cpp:
 */
extern void substractRectOnAreas(const TQRect &rectToSubstract, TQValueList<TQRect> &areas, bool andRemove = true);

void debugZone(int zone)
{
	TQString s;
	switch (zone) {
		case Note::Handle:        s = "Handle";              break;
		case Note::Group:         s = "Group";               break;
		case Note::TagsArrow:     s = "TagsArrow";           break;
		case Note::Custom0:       s = "Custom0";             break;
		case Note::GroupExpander: s = "GroupExpander";       break;
		case Note::Content:       s = "Content";             break;
		case Note::Link:          s = "Link";                break;
		case Note::TopInsert:     s = "TopInsert";           break;
		case Note::TopGroup:      s = "TopGroup";            break;
		case Note::BottomInsert:  s = "BottomInsert";        break;
		case Note::BottomGroup:   s = "BottomGroup";         break;
		case Note::BottomColumn:  s = "BottomColumn";        break;
		case Note::None:          s = "None";                break;
		default:
			if (zone == Note::Emblem0)
				s = "Emblem0";
			else
				s = "Emblem0+" + TQString::number(zone - Note::Emblem0);
			break;
	}
	std::cout << s.local8Bit() << std::endl;
}

#define FOR_EACH_NOTE(noteVar) \
	for (Note *noteVar = firstNote(); noteVar; noteVar = noteVar->next())

void Basket::prependNoteIn(Note *note, Note *in)
{
	if (!note)
		// No note to prepend:
		return;

	if (in) {
		// The normal case:
		preparePlug(note);

		Note *last = note->lastSibling();

		for (Note *n = note; n; n = n->next())
			n->setParentNote(in);
//		note->setPrev(0L);
		last->setNext(in->firstChild());

		if (in->firstChild())
			in->firstChild()->setPrev(last);

		in->setFirstChild(note);

		if (m_loaded)
			signalCountsChanged();
	} else
		// Prepend it directly in the basket:
		appendNoteBefore(note, firstNote());
}

void Basket::appendNoteIn(Note *note, Note *in)
{
	if (!note)
		// No note to append:
		return;

	if (in) {
		// The normal case:
		preparePlug(note);

//		Note *last = note->lastSibling();
		Note *lastChild = in->lastChild();

		for (Note *n = note; n; n = n->next())
			n->setParentNote(in);
		note->setPrev(lastChild);
//		last->setNext(0L);

		if (!in->firstChild())
			in->setFirstChild(note);

		if (lastChild)
			lastChild->setNext(note);

		if (m_loaded)
			signalCountsChanged();
	} else
		// Prepend it directly in the basket:
		appendNoteAfter(note, lastNote());
}

void Basket::appendNoteAfter(Note *note, Note *after)
{
	if (!note)
		// No note to append:
		return;

	if (!after)
		// By default, insert after the last note:
		after = lastNote();

	if (m_loaded && after && !after->isFree() && !after->isColumn())
		for (Note *n = note; n; n = n->next())
			n->inheritTagsOf(after);

//	if (!alreadyInBasket)
	preparePlug(note);

	Note *last = note->lastSibling();
	if (after) {
		// The normal case:
		for (Note *n = note; n; n = n->next())
			n->setParentNote(after->parentNote());
		note->setPrev(after);
		last->setNext(after->next());
		after->setNext(note);
		if (last->next())
			last->next()->setPrev(last);
	} else {
		// There is no note in the basket:
		for (Note *n = note; n; n = n->next())
			n->setParentNote(0);
		m_firstNote = note;
//		note->setPrev(0);
//		last->setNext(0);
	}

//	if (!alreadyInBasket)
	if (m_loaded)
		signalCountsChanged();
}

void Basket::appendNoteBefore(Note *note, Note *before)
{
	if (!note)
		// No note to append:
		return;

	if (!before)
		// By default, insert before the first note:
		before = firstNote();

	if (m_loaded && before && !before->isFree() && !before->isColumn())
		for (Note *n = note; n; n = n->next())
			n->inheritTagsOf(before);

	preparePlug(note);

	Note *last = note->lastSibling();
	if (before) {
		// The normal case:
		for (Note *n = note; n; n = n->next())
			n->setParentNote(before->parentNote());
		note->setPrev(before->prev());
		last->setNext(before);
		before->setPrev(last);
		if (note->prev())
			note->prev()->setNext(note);
		else {
			if (note->parentNote())
				note->parentNote()->setFirstChild(note);
			else
				m_firstNote = note;
		}
	} else {
		// There is no note in the basket:
		for (Note *n = note; n; n = n->next())
			n->setParentNote(0);
		m_firstNote = note;
//		note->setPrev(0);
//		last->setNext(0);
	}

	if (m_loaded)
		signalCountsChanged();
}

DecoratedBasket* Basket::decoration()
{
	return (DecoratedBasket*)parent();
}

void Basket::preparePlug(Note *note)
{
	// Select only the new notes, compute the new notes count and the new number of found notes:
	if (m_loaded)
		unselectAll();
	int count  = 0;
	int founds = 0;
	Note *last = 0;
	for (Note *n = note; n; n = n->next()) {
		if (m_loaded)
			n->setSelectedRecursivly(true); // Notes should have a parent basket (and they have, so that's OK).
		count  += n->count();
		founds += n->newFilter(decoration()->filterData());
		last = n;
	}
	m_count += count;
	m_countFounds += founds;

	// Focus the last inserted note:
	if (m_loaded && last) {
		setFocusedNote(last);
		m_startOfShiftSelectionNote = (last->isGroup() ? last->lastRealChild() : last);
	}

	// If some notes don't match (are hidden), tell it to the user:
	if (m_loaded && founds < count) {
		if      (count == 1)          postMessage( i18n("The new note does not match the filter and is hidden.")  );
		else if (founds == count - 1) postMessage( i18n("A new note does not match the filter and is hidden.")    );
		else if (founds > 0)          postMessage( i18n("Some new notes do not match the filter and are hidden.") );
		else                          postMessage( i18n("The new notes do not match the filter and are hidden.")  );
	}
}

void Basket::unplugNote(Note *note)
{
	// If there is nothing to do...
	if (!note)
		return;

//	if (!willBeReplugged) {
	note->setSelectedRecursivly(false); // To removeSelectedNote() and decrease the selectedsCount.
	m_count -= note->count();
	m_countFounds -= note->newFilter(decoration()->filterData());
	signalCountsChanged();
//	}

	// If it was the first note, change the first note:
	if (m_firstNote == note)
		m_firstNote = note->next();

	// Change previous and next notes:
	if (note->prev())
		note->prev()->setNext(note->next());
	if (note->next())
		note->next()->setPrev(note->prev());

	if (note->parentNote()) {
		// If it was the first note of a group, change the first note of the group:
		if (note->parentNote()->firstChild() == note)
			note->parentNote()->setFirstChild( note->next() );

		if (!note->parentNote()->isColumn()) {
			// Ungroup if still 0 note inside parent group:
			if ( ! note->parentNote()->firstChild() )
				unplugNote(note->parentNote()); // TODO delete

			// Ungroup if still 1 note inside parent group:
			else if ( ! note->parentNote()->firstChild()->next() )
				ungroupNote(note->parentNote());
		}
	}

	note->setParentNote(0);
	note->setPrev(0);
	note->setNext(0);

//	recomputeBlankRects(); // FIXME: called too much time. It's here because when dragging and moving a note to another basket and then go back to the original basket, the note is deleted but the note rect is not painter anymore.
}

void Basket::ungroupNote(Note *group)
{
	Note *note            = group->firstChild();
	Note *lastGroupedNote = group;
	Note *nextNote;

	// Move all notes after the group (not before, to avoid to change m_firstNote or group->m_firstChild):
	while (note) {
		nextNote = note->next();

		if (lastGroupedNote->next())
			lastGroupedNote->next()->setPrev(note);
		note->setNext(lastGroupedNote->next());
		lastGroupedNote->setNext(note);
		note->setParentNote(group->parentNote());
		note->setPrev(lastGroupedNote);

		note->setGroupWidth(group->groupWidth() - Note::GROUP_WIDTH);
		lastGroupedNote = note;
		note = nextNote;
	}

	// Unplug the group:
	group->setFirstChild(0);
	unplugNote(group); // TODO: delete

	relayoutNotes(true);
}

void Basket::groupNoteBefore(Note *note, Note *with)
{
	if (!note || !with)
		// No note to group or nowhere to group it:
		return;

//	if (m_loaded && before && !with->isFree() && !with->isColumn())
	for (Note *n = note; n; n = n->next())
		n->inheritTagsOf(with);

	preparePlug(note);

	Note *last = note->lastSibling();

	Note *group = new Note(this);
	group->setPrev(with->prev());
	group->setNext(with->next());
	group->setX(with->x());
	group->setY(with->y());
	if (with->parentNote() && with->parentNote()->firstChild() == with)
		with->parentNote()->setFirstChild(group);
	else if (m_firstNote == with)
		m_firstNote = group;
	group->setParentNote(with->parentNote());
	group->setFirstChild(note);
	group->setGroupWidth(with->groupWidth() + Note::GROUP_WIDTH);

	if (with->prev())
		with->prev()->setNext(group);
	if (with->next())
		with->next()->setPrev(group);
	with->setParentNote(group);
	with->setPrev(last);
	with->setNext(0L);

	for (Note *n = note; n; n = n->next())
		n->setParentNote(group);
//	note->setPrev(0L);
	last->setNext(with);

	if (m_loaded)
		signalCountsChanged();
}

void Basket::groupNoteAfter(Note *note, Note *with)
{
	if (!note || !with)
		// No note to group or nowhere to group it:
		return;

//	if (m_loaded && before && !with->isFree() && !with->isColumn())
	for (Note *n = note; n; n = n->next())
		n->inheritTagsOf(with);

	preparePlug(note);

//	Note *last = note->lastSibling();

	Note *group = new Note(this);
	group->setPrev(with->prev());
	group->setNext(with->next());
	group->setX(with->x());
	group->setY(with->y());
	if (with->parentNote() && with->parentNote()->firstChild() == with)
		with->parentNote()->setFirstChild(group);
	else if (m_firstNote == with)
		m_firstNote = group;
	group->setParentNote(with->parentNote());
	group->setFirstChild(with);
	group->setGroupWidth(with->groupWidth() + Note::GROUP_WIDTH);

	if (with->prev())
		with->prev()->setNext(group);
	if (with->next())
		with->next()->setPrev(group);
	with->setParentNote(group);
	with->setPrev(0L);
	with->setNext(note);

	for (Note *n = note; n; n = n->next())
		n->setParentNote(group);
	note->setPrev(with);
//	last->setNext(0L);

	if (m_loaded)
		signalCountsChanged();
}

void Basket::loadNotes(const TQDomElement &notes, Note *parent)
{
	Note *note;
	for (TQDomNode n = notes.firstChild(); !n.isNull(); n = n.nextSibling()) {
		TQDomElement e = n.toElement();
		if (e.isNull()) // Cannot handle that!
			continue;
		note = 0;
		// Load a Group:
		if (e.tagName() == "group") {
			note = new Note(this);      // 1. Create the group...
			loadNotes(e, note);         // 3. ... And populate it with child notes.
			int noteCount = note->count();
			if (noteCount > 0 || (parent == 0 && !isFreeLayout())) { // But don't remove columns!
				appendNoteIn(note, parent); // 2. ... Insert it... FIXME: Initially, the if() the insrtion was the step 2. Was it on purpose?
				// The notes in the group are counted two times (it's why appendNoteIn() was called before loadNotes):
				m_count       -= noteCount;// TODO: Recompute note count every time noteCount() is emitted!
				m_countFounds -= noteCount;
			}
		}
		// Load a Content-Based Note:
		if (e.tagName() == "note" || e.tagName() == "item") { // Keep compatible with 0.6.0 Alpha 1
			note = new Note(this);      // Create the note...
			NoteFactory__loadNode(XMLWork::getElement(e, "content"), e.attribute("type"), note, /*lazyLoad=*/m_finishLoadOnFirstShow); // ... Populate it with content...
			if (e.attribute("type") == "text")
				m_shouldConvertPlainTextNotes = true; // Convert Pre-0.6.0 baskets: plain text notes should be converted to rich text ones once all is loaded!
			appendNoteIn(note, parent); // ... And insert it.
			// Load dates:
			if (e.hasAttribute("added"))
				note->setAddedDate(           TQDateTime::fromString(e.attribute("added"),            TQt::ISODate));
			if (e.hasAttribute("lastModification"))
				note->setLastModificationDate(TQDateTime::fromString(e.attribute("lastModification"), TQt::ISODate));
		}
		// If we successfully loaded a note:
		if (note) {
			// Free Note Properties:
			if (note->isFree()) {
				int x = e.attribute("x").toInt();
				int y = e.attribute("y").toInt();
				note->setX(x < 0 ? 0 : x);
				note->setY(y < 0 ? 0 : y);
			}
			// Resizeable Note Properties:
			if (note->hasResizer() || note->isColumn())
				note->setGroupWidth(e.attribute("width", "200").toInt());
			// Group Properties:
			if (note->isGroup() && !note->isColumn() && XMLWork::trueOrFalse(e.attribute("folded", "false")))
				note->toggleFolded(false);
			// Tags:
			if (note->content()) {
				TQString tagsString = XMLWork::getElementText(e, "tags", "");
				TQStringList tagsId = TQStringList::split(";", tagsString);
				for (TQStringList::iterator it = tagsId.begin(); it != tagsId.end(); ++it) {
					State *state = Tag::stateForId(*it);
					if (state)
						note->addState(state, /*orReplace=*/true);
				}
			}
		}
//		kapp->processEvents();
	}
}

void Basket::saveNotes(TQDomDocument &document, TQDomElement &element, Note *parent)
{
	Note *note = (parent ? parent->firstChild() : firstNote());
	while (note) {
		// Create Element:
		TQDomElement noteElement = document.createElement(note->isGroup() ? "group" : "note");
		element.appendChild(noteElement);
		// Free Note Properties:
		if (note->isFree()) {
			noteElement.setAttribute("x", note->finalX());
			noteElement.setAttribute("y", note->finalY());
		}
		// Resizeable Note Properties:
		if (note->hasResizer())
			noteElement.setAttribute("width", note->groupWidth());
		// Group Properties:
		if (note->isGroup() && !note->isColumn())
			noteElement.setAttribute("folded", XMLWork::trueOrFalse(note->isFolded()));
		// Save Content:
		if (note->content()) {
			// Save Dates:
			noteElement.setAttribute("added",            note->addedDate().toString(TQt::ISODate)           );
			noteElement.setAttribute("lastModification", note->lastModificationDate().toString(TQt::ISODate));
			// Save Content:
			noteElement.setAttribute("type", note->content()->lowerTypeName());
			TQDomElement content = document.createElement("content");
			noteElement.appendChild(content);
			note->content()->saveToNode(document, content);
			// Save Tags:
			if (note->states().count() > 0) {
				TQString tags;
				for (State::List::iterator it = note->states().begin(); it != note->states().end(); ++it)
					tags += (tags.isEmpty() ? "" : ";") + (*it)->id();
				XMLWork::addElement(document, noteElement, "tags", tags);
			}
		} else
			// Save Child Notes:
			saveNotes(document, noteElement, note);
		// Go to the Next One:
		note = note->next();
	}
}

void Basket::loadProperties(const TQDomElement &properties)
{
	// Compute Default Values for When Loading the Properties:
	TQString defaultBackgroundColor = (backgroundColorSetting().isValid() ? backgroundColorSetting().name() : "");
	TQString defaultTextColor       = (textColorSetting().isValid()       ? textColorSetting().name()       : "");

	// Load the Properties:
	TQString icon = XMLWork::getElementText(properties, "icon", this->icon() );
	TQString name = XMLWork::getElementText(properties, "name", basketName() );

	TQDomElement appearance = XMLWork::getElement(properties, "appearance");
	// In 0.6.0-Alpha versions, there was a typo error: "backround" instead of "background"
	TQString backgroundImage       = appearance.attribute( "backgroundImage", appearance.attribute( "backroundImage", backgroundImageName()  ) );
	TQString backgroundColorString = appearance.attribute( "backgroundColor", appearance.attribute( "backroundColor", defaultBackgroundColor ) );
	TQString textColorString       = appearance.attribute( "textColor",      defaultTextColor       );
	TQColor  backgroundColor = (backgroundColorString.isEmpty() ? TQColor() : TQColor(backgroundColorString));
	TQColor  textColor       = (textColorString.isEmpty()       ? TQColor() : TQColor(textColorString)      );

	TQDomElement disposition = XMLWork::getElement(properties, "disposition");
	bool free        = XMLWork::trueOrFalse( disposition.attribute( "free",        XMLWork::trueOrFalse(isFreeLayout())   ) );
	int  columnCount =                       disposition.attribute( "columnCount", TQString::number(this->columnsCount())  ).toInt();
	bool mindMap     = XMLWork::trueOrFalse( disposition.attribute( "mindMap",     XMLWork::trueOrFalse(isMindMap())      ) );

	TQDomElement shortcut = XMLWork::getElement(properties, "shortcut");
	TQString actionStrings[] = { "show", "globalShow", "globalSwitch" };
	TDEShortcut combination  = TDEShortcut( shortcut.attribute( "combination", m_action->shortcut().toStringInternal() ) );
	TQString   actionString =            shortcut.attribute( "action" );
	int action = shortcutAction();
	if (actionString == actionStrings[0]) action = 0;
	if (actionString == actionStrings[1]) action = 1;
	if (actionString == actionStrings[2]) action = 2;

	TQDomElement protection = XMLWork::getElement(properties, "protection");
	m_encryptionType = protection.attribute( "type" ).toInt();
	m_encryptionKey = protection.attribute( "key" );

	// Apply the Properties:
	setDisposition((free ? (mindMap ? 2 : 1) : 0), columnCount);
	setShortcut(combination, action);
	setAppearance(icon, name, backgroundImage, backgroundColor, textColor); // Will emit propertiesChanged(this)
}

void Basket::saveProperties(TQDomDocument &document, TQDomElement &properties)
{
	XMLWork::addElement( document, properties, "name", basketName() );
	XMLWork::addElement( document, properties, "icon", icon()       );

	TQDomElement appearance = document.createElement("appearance");
	properties.appendChild(appearance);
	appearance.setAttribute( "backgroundImage", backgroundImageName() );
	appearance.setAttribute( "backgroundColor", backgroundColorSetting().isValid() ? backgroundColorSetting().name() : "" );
	appearance.setAttribute( "textColor",       textColorSetting().isValid()       ? textColorSetting().name()       : "" );

	TQDomElement disposition = document.createElement("disposition");
	properties.appendChild(disposition);
	disposition.setAttribute( "free",        XMLWork::trueOrFalse(isFreeLayout()) );
	disposition.setAttribute( "columnCount", TQString::number(columnsCount())      );
	disposition.setAttribute( "mindMap",     XMLWork::trueOrFalse(isMindMap())    );

	TQDomElement shortcut = document.createElement("shortcut");
	properties.appendChild(shortcut);
	TQString actionStrings[] = { "show", "globalShow", "globalSwitch" };
	shortcut.setAttribute( "combination", m_action->shortcut().toStringInternal() );
	shortcut.setAttribute( "action",      actionStrings[shortcutAction()]         );

	TQDomElement protection = document.createElement("protection");
	properties.appendChild(protection);
	protection.setAttribute( "type", m_encryptionType );
	protection.setAttribute( "key",  m_encryptionKey );
}

void Basket::subscribeBackgroundImages()
{
	if (!m_backgroundImageName.isEmpty()) {
		Global::backgroundManager->subscribe(m_backgroundImageName);
		Global::backgroundManager->subscribe(m_backgroundImageName, this->backgroundColor());
		Global::backgroundManager->subscribe(m_backgroundImageName, selectionRectInsideColor());
		m_backgroundPixmap         = Global::backgroundManager->pixmap(m_backgroundImageName);
		m_opaqueBackgroundPixmap   = Global::backgroundManager->opaquePixmap(m_backgroundImageName, this->backgroundColor());
		m_selectedBackgroundPixmap = Global::backgroundManager->opaquePixmap(m_backgroundImageName, selectionRectInsideColor());
		m_backgroundTiled          = Global::backgroundManager->tiled(m_backgroundImageName);
	}
}

void Basket::unsubscribeBackgroundImages()
{
	if (hasBackgroundImage()) {
		Global::backgroundManager->unsubscribe(m_backgroundImageName);
		Global::backgroundManager->unsubscribe(m_backgroundImageName, this->backgroundColor());
		Global::backgroundManager->unsubscribe(m_backgroundImageName, selectionRectInsideColor());
		m_backgroundPixmap         = 0;
		m_opaqueBackgroundPixmap   = 0;
		m_selectedBackgroundPixmap = 0;
	}
}

void Basket::setAppearance(const TQString &icon, const TQString &name, const TQString &backgroundImage, const TQColor &backgroundColor, const TQColor &textColor)
{
	unsubscribeBackgroundImages();

	m_icon                   = icon;
	m_basketName             = name;
	m_backgroundImageName    = backgroundImage;
	m_backgroundColorSetting = backgroundColor;
	m_textColorSetting       = textColor;

	m_action->setText("BASKET SHORTCUT: " + name);

	// Basket should ALWAYS have an icon (the "basket" icon by default):
	TQPixmap iconTest = kapp->iconLoader()->loadIcon(m_icon, TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0L, /*canReturnNull=*/true);
	if (iconTest.isNull())
		m_icon = "basket";

	// We don't request the background images if it's not loaded yet (to make the application startup fast).
	// When the basket is loading (because requested by the user: he/she want to access it)
	// it load the properties, subscribe to (and then load) the images, update the "Loading..." message with the image,
	// load all the notes and it's done!
	if (m_loadingLaunched)
		subscribeBackgroundImages();

	recomputeAllStyles(); // If a note have a tag with the same background color as the basket one, then display a "..."
	recomputeBlankRects(); // See the drawing of blank areas in Basket::drawContents()
	unbufferizeAll();
	updateContents();

	if (isDuringEdit() && m_editor->widget()) {
		m_editor->widget()->setPaletteBackgroundColor( m_editor->note()->backgroundColor() );
		m_editor->widget()->setPaletteForegroundColor( m_editor->note()->textColor()       );
	}

	emit propertiesChanged(this);
}

void Basket::setDisposition(int disposition, int columnCount)
{
	static const int COLUMNS_LAYOUT  = 0;
	static const int FREE_LAYOUT     = 1;
	static const int MINDMAPS_LAYOUT = 2;

	int currentDisposition = (isFreeLayout() ? (isMindMap() ? MINDMAPS_LAYOUT : FREE_LAYOUT) : COLUMNS_LAYOUT);

	if (currentDisposition == COLUMNS_LAYOUT && disposition == COLUMNS_LAYOUT) {
		if (firstNote() && columnCount > m_columnsCount) {
			// Insert each new columns:
			for (int i = m_columnsCount; i < columnCount; ++i) {
				Note *newColumn = new Note(this);
				insertNote(newColumn, /*clicked=*/lastNote(), /*zone=*/Note::BottomInsert, TQPoint(), /*animateNewPosition=*/false);
			}
		} else if (firstNote() && columnCount < m_columnsCount) {
			Note *column = firstNote();
			Note *cuttedNotes = 0;
			for (int i = 1; i <= m_columnsCount; ++i) {
				Note *columnToRemove = column;
				column = column->next();
				if (i > columnCount) {
					// Remove the columns that are too much:
					unplugNote(columnToRemove);
					// "Cut" the content in the columns to be deleted:
					if (columnToRemove->firstChild()) {
						for (Note *it = columnToRemove->firstChild(); it; it = it->next())
							it->setParentNote(0);
						if (!cuttedNotes)
							cuttedNotes = columnToRemove->firstChild();
						else {
							Note *lastCuttedNote = cuttedNotes;
							while (lastCuttedNote->next())
								lastCuttedNote = lastCuttedNote->next();
							lastCuttedNote->setNext(columnToRemove->firstChild());
							columnToRemove->firstChild()->setPrev(lastCuttedNote);
						}
						columnToRemove->setFirstChild(0);
					}
				}
			}
			// Paste the content in the last column:
			if (cuttedNotes)
				insertNote(cuttedNotes, /*clicked=*/lastNote(), /*zone=*/Note::BottomColumn, TQPoint(), /*animateNewPosition=*/true);
			unselectAll();
		}
		if (columnCount != m_columnsCount) {
			m_columnsCount = (columnCount <= 0 ? 1 : columnCount);
			equalizeColumnSizes(); // Will relayoutNotes()
		}
	} else if (currentDisposition == COLUMNS_LAYOUT && (disposition == FREE_LAYOUT || disposition == MINDMAPS_LAYOUT)) {
		Note *column = firstNote();
		m_columnsCount = 0; // Now, so relayoutNotes() will not relayout the free notes as if they were columns!
		while (column) {
			// Move all childs on the first level:
			Note *nextColumn = column->next();
			ungroupNote(column);
			column = nextColumn;
		}
		unselectAll();
		m_mindMap = (disposition == MINDMAPS_LAYOUT);
		relayoutNotes(true);
	} else if ((currentDisposition == FREE_LAYOUT || currentDisposition == MINDMAPS_LAYOUT) && disposition == COLUMNS_LAYOUT) {
		if (firstNote()) {
			// TODO: Reorder notes!
			// Remove all notes (but keep a reference to them, we're not crazy ;-) ):
			Note *notes = m_firstNote;
			m_firstNote = 0;
			m_count = 0;
			m_countFounds = 0;
			// Insert the number of columns that is needed:
			Note *lastInsertedColumn = 0;
			for (int i = 0; i < columnCount; ++i) {
				Note *column = new Note(this);
				if (lastInsertedColumn)
					insertNote(column, /*clicked=*/lastInsertedColumn, /*zone=*/Note::BottomInsert, TQPoint(), /*animateNewPosition=*/false);
				else
					m_firstNote = column;
				lastInsertedColumn = column;
			}
			// Reinsert the old notes in the first column:
			insertNote(notes, /*clicked=*/firstNote(), /*zone=*/Note::BottomColumn, TQPoint(), /*animateNewPosition=*/true);
			unselectAll();
		} else {
			// Insert the number of columns that is needed:
			Note *lastInsertedColumn = 0;
			for (int i = 0; i < columnCount; ++i) {
				Note *column = new Note(this);
				if (lastInsertedColumn)
					insertNote(column, /*clicked=*/lastInsertedColumn, /*zone=*/Note::BottomInsert, TQPoint(), /*animateNewPosition=*/false);
				else
					m_firstNote = column;
				lastInsertedColumn = column;
			}
		}
		m_columnsCount = (columnCount <= 0 ? 1 : columnCount);
		equalizeColumnSizes(); // Will relayoutNotes()
	}
}

void Basket::equalizeColumnSizes()
{
	if (!firstNote())
		return;

	// Necessary to know the available space;
	relayoutNotes(true);

	int availableSpace = visibleWidth();
	int columnWidth = (visibleWidth() - (columnsCount()-1)*Note::GROUP_WIDTH) / columnsCount();
	int columnCount = columnsCount();
	Note *column = firstNote();
	while (column) {
		int minGroupWidth = column->minRight() - column->x();
		if (minGroupWidth > columnWidth) {
			availableSpace -= minGroupWidth;
			--columnCount;
		}
		column = column->next();
	}
	columnWidth = (availableSpace - (columnsCount()-1)*Note::GROUP_WIDTH) / columnCount;

	column = firstNote();
	while (column) {
		int minGroupWidth = column->minRight() - column->x();
		if (minGroupWidth > columnWidth)
			column->setGroupWidth(minGroupWidth);
		else
			column->setGroupWidth(columnWidth);
		column = column->next();
	}

	relayoutNotes(true);
}

void Basket::enableActions()
{
	Global::bnpView->enableActions();
	setFocusPolicy(isLocked() ? TQWidget::NoFocus : TQWidget::StrongFocus);
	if (isLocked())
		viewport()->setCursor(TQt::ArrowCursor); // When locking, the cursor stays the last form it was
}

bool Basket::save()
{
	if (!m_loaded)
		return false;

	DEBUG_WIN << "Basket[" + folderName() + "]: Saving...";

	// Create Document:
	TQDomDocument document(/*doctype=*/"basket");
	TQDomElement root = document.createElement("basket");
	document.appendChild(root);

	// Create Properties Element and Populate It:
	TQDomElement properties = document.createElement("properties");
	saveProperties(document, properties);
	root.appendChild(properties);

	// Create Notes Element and Populate It:
	TQDomElement notes = document.createElement("notes");
	saveNotes(document, notes, 0);
	root.appendChild(notes);

	// Write to Disk:
	if(!saveToFile(fullPath() + ".basket", "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString()))
	{
		DEBUG_WIN << "Basket[" + folderName() + "]: <font color=red>FAILED to save</font>!";
		return false;
	}

	Global::bnpView->setUnsavedStatus(false);
	return true;
}

void Basket::aboutToBeActivated()
{
	if (m_finishLoadOnFirstShow) {
		FOR_EACH_NOTE (note)
			note->finishLazyLoad();

		//relayoutNotes(/*animate=*/false);
		setFocusedNote(0); // So that during the focusInEvent that will come shortly, the FIRST note is focused.

		if (Settings::playAnimations() && !decoration()->filterBar()->filterData().isFiltering && Global::bnpView->currentBasket() == this) // No animation when filtering all!
			animateLoad();//TQTimer::singleShot( 0, this, TQ_SLOT(animateLoad()) );

		m_finishLoadOnFirstShow = false;
	}
}

void Basket::load()
{
	// Load only once:
	if (m_loadingLaunched)
		return;
	m_loadingLaunched = true;

//	StopWatch::start(10);

	DEBUG_WIN << "Basket[" + folderName() + "]: Loading...";
	TQDomDocument *doc = 0;
	TQString content;

//	StopWatch::start(0);

	if (loadFromFile(fullPath() + ".basket", &content)) {
		doc = new TQDomDocument("basket");
		if ( ! doc->setContent(content) ) {
			DEBUG_WIN << "Basket[" + folderName() + "]: <font color=red>FAILED to parse XML</font>!";
			delete doc;
			doc = 0;
		}
	}
	if(isEncrypted())
		DEBUG_WIN << "Basket is encrypted.";
	if ( ! doc) {
		DEBUG_WIN << "Basket[" + folderName() + "]: <font color=red>FAILED to load</font>!";
		m_loadingLaunched = false;
		if (isEncrypted())
			m_locked = true;
		Global::bnpView->notesStateChanged(); // Show "Locked" instead of "Loading..." in the statusbar
		return;
	}
	m_locked = false;

	TQDomElement docElem = doc->documentElement();
	TQDomElement properties = XMLWork::getElement(docElem, "properties");

	loadProperties(properties); // Since we are loading, this time the background image will also be loaded!
	// Now that the background image is loaded and subscribed, we display it during the load process:
	delete doc;
	updateContents();
//	kapp->processEvents();

	//BEGIN Compatibility with 0.6.0 Pre-Alpha versions:
	TQDomElement notes = XMLWork::getElement(docElem, "notes");
	if (notes.isNull())
		notes = XMLWork::getElement(docElem, "items");
	m_watcher->stopScan();
	m_shouldConvertPlainTextNotes = false; // Convert Pre-0.6.0 baskets: plain text notes should be converted to rich text ones once all is loaded!
//	StopWatch::check(0);

//	StopWatch::start(1);
	m_finishLoadOnFirstShow = (Global::bnpView->currentBasket() != this);
	loadNotes(notes, 0L);
//	StopWatch::check(1);
//	StopWatch::start(2);

	if (m_shouldConvertPlainTextNotes)
		convertTexts();
	m_watcher->startScan();
	//loadNotes(XMLWork::getElement(docElem, "notes"), 0L);
	//END

//	StopWatch::check(0);

	signalCountsChanged();
	if (isColumnsLayout()) {
		// Count the number of columns:
		int columnsCount = 0;
		Note *column = firstNote();
		while (column) {
			++columnsCount;
			column = column->next();
		}
		m_columnsCount = columnsCount;
	}

	relayoutNotes(false);

	// On application start, the current basket is not focused yet, so the focus rectangle is not shown when calling focusANote():
	if (Global::bnpView->currentBasket() == this)
		setFocus();
	focusANote();

	if (Settings::playAnimations() && !decoration()->filterBar()->filterData().isFiltering && Global::bnpView->currentBasket() == this) // No animation when filtering all!
		animateLoad();//TQTimer::singleShot( 0, this, TQ_SLOT(animateLoad()) );
	else
		m_loaded = true;
	enableActions();
//	StopWatch::check(2);

//	StopWatch::check(10);
}

void Basket::filterAgain(bool andEnsureVisible/* = true*/)
{
	newFilter(decoration()->filterData(), andEnsureVisible);
}

void Basket::filterAgainDelayed()
{
	TQTimer::singleShot( 0, this, TQ_SLOT(filterAgain()) );
}

void Basket::newFilter(const FilterData &data, bool andEnsureVisible/* = true*/)
{
	if (!isLoaded())
		return;

//StopWatch::start(20);

	m_countFounds = 0;
	for (Note *note = firstNote(); note; note = note->next())
		m_countFounds += note->newFilter(data);

	relayoutNotes(true);
	signalCountsChanged();

	if (hasFocus())   // if (!hasFocus()), focusANote() will be called at focusInEvent()
		focusANote(); //  so, we avoid de-focus a note if it will be re-shown soon
	if (andEnsureVisible && m_focusedNote != 0L)
		ensureNoteVisible(m_focusedNote);

	Global::bnpView->setFiltering(data.isFiltering);

//StopWatch::check(20);
}

void Basket::cancelFilter()
{
	decoration()->filterBar()->reset();
	validateFilter();
}

void Basket::validateFilter()
{
	if (isDuringEdit())
		m_editor->widget()->setFocus();
	else
		setFocus();
}

bool Basket::isFiltering()
{
	return decoration()->filterBar()->filterData().isFiltering;
}



TQString Basket::fullPath()
{
	return Global::basketsFolder() + folderName();
}

TQString Basket::fullPathForFileName(const TQString &fileName)
{
	return fullPath() + fileName;
}

/*static*/ TQString Basket::fullPathForFolderName(const TQString &folderName)
{
	return Global::basketsFolder() + folderName;
}


void Basket::setShortcut(TDEShortcut shortcut, int action)
{
	if(!Global::globalAccel)
		return;
	TQString sAction = "global_basket_activate_" + folderName();
	Global::globalAccel->remove(sAction);
	Global::globalAccel->updateConnections();

	m_action->setShortcut(shortcut);
	m_shortcutAction = action;

	if (action > 0)
		Global::globalAccel->insert(sAction, m_action->text(), /*whatsThis=*/"", m_action->shortcut(), TDEShortcut(), this, TQ_SLOT(activatedShortcut()), /*configurable=*/false);
	Global::globalAccel->updateConnections();
}

void Basket::activatedShortcut()
{
	Global::bnpView->setCurrentBasket(this);

	if (m_shortcutAction == 1)
		Global::bnpView->setActive(true);
}

void Basket::signalCountsChanged()
{
	if (!m_timerCountsChanged.isActive())
		m_timerCountsChanged.start(0/*ms*/, /*singleShot=*/true);
}

void Basket::countsChangedTimeOut()
{
	emit countsChanged(this);
}


Basket::Basket(TQWidget *parent, const TQString &folderName)
 : TQScrollView(parent),
   TQToolTip(viewport()),
   m_noActionOnMouseRelease(false), m_ignoreCloseEditorOnNextMouseRelease(false), m_pressPos(-100, -100), m_canDrag(false),
   m_firstNote(0), m_columnsCount(1), m_mindMap(false), m_resizingNote(0L), m_pickedResizer(0), m_movingNote(0L), m_pickedHandle(0, 0),
   m_clickedToInsert(0), m_zoneToInsert(0), m_posToInsert(-1, -1),
   m_isInsertPopupMenu(false),
   m_loaded(false), m_loadingLaunched(false), m_locked(false), m_decryptBox(0), m_button(0), m_encryptionType(NoEncryption),
#ifdef HAVE_LIBGPGME
   m_gpg(0),
#endif
   m_backgroundPixmap(0), m_opaqueBackgroundPixmap(0), m_selectedBackgroundPixmap(0),
   m_action(0), m_shortcutAction(0),
   m_hoveredNote(0), m_hoveredZone(Note::None), m_lockedHovering(false), m_underMouse(false),
   m_inserterRect(), m_inserterShown(false), m_inserterSplit(true), m_inserterTop(false), m_inserterGroup(false),
   m_isSelecting(false), m_selectionStarted(false),
   m_count(0), m_countFounds(0), m_countSelecteds(0),
   m_folderName(folderName),
   m_editor(0), m_leftEditorBorder(0), m_rightEditorBorder(0), m_redirectEditActions(false), m_editorWidth(-1), m_editorHeight(-1),
   m_doNotCloseEditor(false), m_editParagraph(0), m_editIndex(0),
   m_isDuringDrag(false), m_draggedNotes(),
   m_focusedNote(0), m_startOfShiftSelectionNote(0),
   m_finishLoadOnFirstShow(false), m_relayoutOnNextShow(false)
{
	TQString sAction = "local_basket_activate_" + folderName;
	m_action = new TDEAction("FAKE TEXT", "FAKE ICON", TDEShortcut(), this, TQ_SLOT(activatedShortcut()), Global::bnpView->actionCollection(), sAction.utf8());
	m_action->setShortcutConfigurable(false); // We do it in the basket properties dialog (and keep it in sync with the global one)

	if (!m_folderName.endsWith("/"))
		m_folderName += "/";

	setFocusPolicy(TQWidget::StrongFocus);
	setWFlags(TQt::WNoAutoErase);
	setDragAutoScroll(true);

	// By default, there is no corner widget: we set one for the corner area to be painted!
	// If we don't set one and there are two scrollbars present, slowly resizing up the window show graphical glitches in that area!
	m_cornerWidget = new TQWidget(this);
	setCornerWidget(m_cornerWidget);

	viewport()->setAcceptDrops(true);
	viewport()->setMouseTracking(true);
	viewport()->setBackgroundMode(NoBackground); // Do not clear the widget before paintEvent() because we always draw every pixels (faster and flicker-free)

	// File Watcher:
	m_watcher = new KDirWatch(this);
	connect( m_watcher,       TQ_SIGNAL(dirty(const TQString&)),   this, TQ_SLOT(watchedFileModified(const TQString&)) );
	connect( m_watcher,       TQ_SIGNAL(deleted(const TQString&)), this, TQ_SLOT(watchedFileDeleted(const TQString&))  );
	connect( &m_watcherTimer, TQ_SIGNAL(timeout()),               this, TQ_SLOT(updateModifiedNotes())               );

	// Various Connections:
	connect( &m_animationTimer,           TQ_SIGNAL(timeout()),   this, TQ_SLOT(animateObjects())            );
	connect( &m_autoScrollSelectionTimer, TQ_SIGNAL(timeout()),   this, TQ_SLOT(doAutoScrollSelection())     );
	connect( &m_timerCountsChanged,       TQ_SIGNAL(timeout()),   this, TQ_SLOT(countsChangedTimeOut())      );
	connect( &m_inactivityAutoSaveTimer,  TQ_SIGNAL(timeout()),   this, TQ_SLOT(inactivityAutoSaveTimeout()) );
	connect( &m_inactivityAutoLockTimer,  TQ_SIGNAL(timeout()),   this, TQ_SLOT(inactivityAutoLockTimeout()) );
	connect( this, TQ_SIGNAL(contentsMoving(int, int)), this, TQ_SLOT(contentsMoved()) );
#ifdef HAVE_LIBGPGME
	m_gpg = new KGpgMe();
#endif
	m_locked = isFileEncrypted();
}

void Basket::contentsMoved()
{
	// This slot is called BEFORE the content move, so we delay the hover effects:
	TQTimer::singleShot(0, this, TQ_SLOT(doHoverEffects()));
}

void Basket::enterEvent(TQEvent *)
{
	m_underMouse = true;
	doHoverEffects();
}

void Basket::leaveEvent(TQEvent *)
{
	m_underMouse = false;
	doHoverEffects();

	if (m_lockedHovering)
		return;

	removeInserter();
	if (m_hoveredNote) {
		m_hoveredNote->setHovered(false);
		m_hoveredNote->setHoveredZone(Note::None);
		updateNote(m_hoveredNote);
	}
	m_hoveredNote = 0;
}

void Basket::setFocusIfNotInPopupMenu()
{
	if (!kapp->activePopupWidget()) {
		if (isDuringEdit()) {
			m_editor->widget()->setFocus();
		}
		else {
			setFocus();
		}
	}
}

void Basket::contentsMousePressEvent(TQMouseEvent *event)
{
	// If user click the basket, focus it!
	// The focus is delayed because if the click results in showing a popup menu,
	// the interface flicker by showing the focused rectangle (as the basket gets focus)
	// and immediatly removing it (because the popup menu now have focus).
	if (!isDuringEdit())
		TQTimer::singleShot(0, this, TQ_SLOT(setFocusIfNotInPopupMenu()));

	// Convenient variables:
	bool controlPressed = event->stateAfter() & TQt::ControlButton;
	bool shiftPressed   = event->stateAfter() & TQt::ShiftButton;

	// Do nothing if we disabled the click some milliseconds sooner.
	// For instance when a popup menu has been closed with click, we should not do action:
	if (event->button() == TQt::LeftButton && (kapp->activePopupWidget() || m_lastDisableClick.msecsTo(TQTime::currentTime()) <= 80)) {
		doHoverEffects();
		m_noActionOnMouseRelease = true;
		// But we allow to select:
		// The code is the same as at the bottom of this method:
		if (event->button() == TQt::LeftButton) {
			m_selectionStarted = true;
			m_selectionBeginPoint = event->pos();
			m_selectionInvert = controlPressed || shiftPressed;
		}
		return;
	}

	// Figure out what is the clicked note and zone:
	Note *clicked = noteAt(event->pos().x(), event->pos().y());
	Note::Zone zone = (clicked ? clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()) ) : Note::None);

	// Popup Tags menu:
	if (zone == Note::TagsArrow && !controlPressed && !shiftPressed && event->button() != TQt::MidButton) {
		if (!clicked->isSelected())
			unselectAllBut(clicked);
		setFocusedNote(clicked); /// /// ///
		m_startOfShiftSelectionNote = clicked;
		m_noActionOnMouseRelease = true;
		popupTagsMenu(clicked);
		return;
	}

	if (event->button() == TQt::LeftButton) {
		// Prepare to allow drag and drop when moving mouse further:
		if ( (zone == Note::Handle || zone == Note::Group) ||
		     (clicked && clicked->isSelected() &&
		       (zone == Note::TagsArrow || zone == Note::Custom0 || zone == Note::Content || zone == Note::Link /**/ || zone >= Note::Emblem0 /**/)) ) {
			if (!shiftPressed && !controlPressed) {
				m_pressPos = event->pos(); // TODO: Allow to drag emblems to assign them to other notes. Then don't allow drag at Emblem0!!
				m_canDrag  = true;
				// Saving where we were editing, because during a drag, the mouse can fly over the text edit and move the cursor position:
				if (m_editor && m_editor->textEdit()) {
					TQTextEdit *editor = m_editor->textEdit();
					editor->getCursorPosition(&m_editParagraph, &m_editIndex);
				}
			}
		}

		// Initializing Resizer move:
		if (zone == Note::Resizer) {
			m_resizingNote  = clicked;
			m_pickedResizer = event->pos().x() - clicked->rightLimit();
			m_noActionOnMouseRelease = true;
			m_lockedHovering = true;
			return;
		}

		// Select note(s):
		if (zone == Note::Handle || zone == Note::Group || (zone == Note::GroupExpander && (controlPressed || shiftPressed))) {
			Note *end = clicked;
			if (clicked->isGroup() && shiftPressed) {
				if (clicked->contains(m_startOfShiftSelectionNote)) {
					m_startOfShiftSelectionNote = clicked->firstRealChild();
					end = clicked->lastRealChild();
				} else if (clicked->firstRealChild()->isAfter(m_startOfShiftSelectionNote))
					end = clicked->lastRealChild();
				else
					end = clicked->firstRealChild();
			}
			if (controlPressed && shiftPressed)
				selectRange(m_startOfShiftSelectionNote, end, /*unselectOthers=*/false);
			else if (shiftPressed)
				selectRange(m_startOfShiftSelectionNote, end);
			else if (controlPressed)
				clicked->setSelectedRecursivly(!clicked->allSelected());
			else if (!clicked->allSelected())
				unselectAllBut(clicked);
			setFocusedNote(end); /// /// ///
			m_startOfShiftSelectionNote = (end->isGroup() ? end->firstRealChild() : end);
			//m_noActionOnMouseRelease = false;
			m_noActionOnMouseRelease = true;
			return;
		}
		// MOVED TO RELEASE EVENT:
		/* else if (clicked && zone != Note::None && zone != Note::BottomColumn && zone != Note::Resizer && (controlPressed || shiftPressed)) {
			if (controlPressed && shiftPressed)
				selectRange(m_startOfShiftSelectionNote, clicked, / *unselectOthers=* /false);
			else if (shiftPressed)
				selectRange(m_startOfShiftSelectionNote, clicked);
			else if (controlPressed)
				clicked->setSelectedRecursivly(!clicked->allSelected());
			setFocusedNote(clicked); /// /// ///
			m_startOfShiftSelectionNote = (clicked->isGroup() ? clicked->firstRealChild() : clicked);
			m_noActionOnMouseRelease = true;
			return;
		}*/

		// Initializing Note move:
/*		if ((zone == Note::Group || zone == Note::Handle) && clicked->isFree()) {
			m_movingNote   = clicked;
			m_pickedHandle = TQPoint(event->pos().x() - clicked->x(), event->pos().y() - clicked->y());
			m_noActionOnMouseRelease = true;
			m_lockedHovering = true;
			return;
		}
*/

		// Folding/Unfolding group:
		if (zone == Note::GroupExpander) {
			clicked->toggleFolded(Settings::playAnimations());
			relayoutNotes(true);
			m_noActionOnMouseRelease = true;
			return;
		}
	}

	// Popup menu for tag emblems:
	if (event->button() == TQt::RightButton && zone >= Note::Emblem0) {
		if (!clicked->isSelected())
			unselectAllBut(clicked);
		setFocusedNote(clicked); /// /// ///
		m_startOfShiftSelectionNote = clicked;
		popupEmblemMenu(clicked, zone - Note::Emblem0);
		m_noActionOnMouseRelease = true;
		return;
	}

	// Insertion Popup Menu:
	if ( (event->button() == TQt::RightButton) &&
	     ((!clicked && isFreeLayout()) ||
	      (clicked && (zone == Note::TopInsert || zone == Note::TopGroup || zone == Note::BottomInsert || zone == Note::BottomGroup || zone == Note::BottomColumn))) ) {
		unselectAll();
		m_clickedToInsert = clicked;
		m_zoneToInsert    = zone;
		m_posToInsert     = event->pos();
		TDEPopupMenu* menu = (TDEPopupMenu*)(Global::bnpView->popupMenu("insert_popup"));
		if (!menu->title(/*id=*/120).isEmpty()) // If we already added a title, remove it because it would be kept and then added several times:
			menu->removeItem(/*id=*/120);
		menu->insertTitle((zone == Note::TopGroup || zone == Note::BottomGroup ? i18n("The verb (Group New Note)", "Group") : i18n("The verb (Insert New Note)", "Insert")), /*id=*/120, /*index=*/0);
		setInsertPopupMenu();
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(delayedCancelInsertPopupMenu()) );
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())               );
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick())             );
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(hideInsertPopupMenu())          );
		doHoverEffects(clicked, zone); // In the case where another popup menu was open, we should do that manually!
		m_lockedHovering = true;
		menu->exec(TQCursor::pos());
		m_noActionOnMouseRelease = true;
		return;
	}

	// Note Context Menu:
	if (event->button() == TQt::RightButton && clicked && !clicked->isColumn() && zone != Note::Resizer) {
		if (!clicked->isSelected())
			unselectAllBut(clicked);
		setFocusedNote(clicked); /// /// ///
		if (editedNote() == clicked) {
			closeEditor();
			clicked->setSelected(true);
		}
		m_startOfShiftSelectionNote = (clicked->isGroup() ? clicked->firstRealChild() : clicked);
		TQPopupMenu* menu = Global::bnpView->popupMenu("note_popup");
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())   );
		connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick()) );
		doHoverEffects(clicked, zone); // In the case where another popup menu was open, we should do that manually!
		m_lockedHovering = true;
		menu->exec(TQCursor::pos());
		m_noActionOnMouseRelease = true;
		return;
	}

	// Paste selection under cursor (but not "create new primary note under cursor" because this is on moveRelease):
	if (event->button() == TQt::MidButton && zone != Note::Resizer && (!isDuringEdit() || clicked != editedNote())) {
		if ((Settings::middleAction() != 0) && (event->state() == TQt::ShiftButton)) {
			m_clickedToInsert = clicked;
			m_zoneToInsert    = zone;
			m_posToInsert     = event->pos();
			closeEditor();
			removeInserter();                     // If clicked at an insertion line and the new note shows a dialog for editing,
			NoteType::Id type = (NoteType::Id)0;  //  hide that inserter before the note edition instead of after the dialog is closed
			switch (Settings::middleAction()) {
				case 1:
					m_isInsertPopupMenu = true;
					pasteNote();
					break;
				case 2: type = NoteType::Image;    break;
				case 3: type = NoteType::Link;     break;
				case 4: type = NoteType::Launcher; break;
				default:
					m_noActionOnMouseRelease = false;
					return; // Other options should be done on mouse release (to avoid mouse release to cancel them!)
/*				case 5: type = NoteType::Color;    break;
				case 6:
					Global::bnpView->grabScreenshot();
					break;
				case 7:
					Global::bnpView->slotColorFromScreen();
					break;
				case 8:
					Global::bnpView->insertWizard(3); // loadFromFile
					break;
				case 9:
					Global::bnpView->insertWizard(1); // importKMenuLauncher
					break;
				case 10:
					Global::bnpView->insertWizard(2); // importIcon
					break;
*/			}
			if (type != 0) {
				m_ignoreCloseEditorOnNextMouseRelease = true;
				Global::bnpView->insertEmpty(type);
			}
		} else {
			if (clicked)
				zone = clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()), true );
			closeEditor();
			clickedToInsert(event, clicked, zone);
			save();
		}
		m_noActionOnMouseRelease = true;
		return;
	}

	// Finally, no action has been done durint pressEvent, so an action can be done on releaseEvent:
	m_noActionOnMouseRelease = false;

	/* Selection scenario:
	 * On contentsMousePressEvent, put m_selectionStarted to true and init Begin and End selection point.
	 * On contentsMouseMoveEvent, if m_selectionStarted, update End selection point, update selection rect,
	 * and if it's larger, switching to m_isSelecting mode: we can draw the selection rectangle.
	 */
	// Prepare selection:
	if (event->button() == TQt::LeftButton) {
		m_selectionStarted = true;
		m_selectionBeginPoint = event->pos();
		// We usualy invert the selection with the Ctrl key, but some environements (like GNOME or The Gimp) do it with the Shift key.
		// Since the Shift key has no specific usage, we allow to invert selection ALSO with Shift for Gimp people
		m_selectionInvert = controlPressed || shiftPressed;
	}
}

void Basket::delayedCancelInsertPopupMenu()
{
	TQTimer::singleShot( 0, this, TQ_SLOT(cancelInsertPopupMenu()) );
}

void Basket::contentsContextMenuEvent(TQContextMenuEvent *event)
{
	if (event->reason() == TQContextMenuEvent::Keyboard) {
		if (countFounds/*countShown*/() == 0) { // TODO: Count shown!!
			TQRect basketRect( mapToGlobal(TQPoint(0,0)), size() );
			TQPopupMenu *menu = Global::bnpView->popupMenu("insert_popup");
			setInsertPopupMenu();
			connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(delayedCancelInsertPopupMenu()) );
			connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())               );
			connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick())             );
			removeInserter();
			m_lockedHovering = true;
			PopupMenu::execAtRectCenter(*menu, basketRect); // Popup at center or the basket
		} else {
			if ( ! m_focusedNote->isSelected() )
				unselectAllBut(m_focusedNote);
			setFocusedNote(m_focusedNote); /// /// ///
			m_startOfShiftSelectionNote = (m_focusedNote->isGroup() ? m_focusedNote->firstRealChild() : m_focusedNote);
			// Popup at bottom (or top) of the focused note, if visible :
			TQPopupMenu *menu = Global::bnpView->popupMenu("note_popup");
			connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())   );
			connect( menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick()) );
			doHoverEffects(m_focusedNote, Note::Content); // In the case where another popup menu was open, we should do that manually!
			m_lockedHovering = true;
			PopupMenu::execAtRectBottom(*menu, noteVisibleRect(m_focusedNote), true);
		}
	}
}

TQRect Basket::noteVisibleRect(Note *note)
{
	TQRect rect( contentsToViewport(TQPoint(note->x(), note->y())), TQSize(note->width(),note->height()) );
	TQPoint basketPoint = mapToGlobal(TQPoint(0,0));
	rect.moveTopLeft( rect.topLeft() + basketPoint + TQPoint(frameWidth(), frameWidth()) );

	// Now, rect contain the global note rectangle on the screen.
	// We have to clip it by the basket widget :
	if (rect.bottom() > basketPoint.y() + visibleHeight() + 1) { // Bottom too... bottom
		rect.setBottom( basketPoint.y() + visibleHeight() + 1);
		if (rect.height() <= 0) // Have at least one visible pixel of height
			rect.setTop(rect.bottom());
	}
	if (rect.top() < basketPoint.y() + frameWidth()) { // Top too... top
		rect.setTop( basketPoint.y() + frameWidth());
		if (rect.height() <= 0)
			rect.setBottom(rect.top());
	}
	if (rect.right() > basketPoint.x() + visibleWidth() + 1) { // Right too... right
		rect.setRight( basketPoint.x() + visibleWidth() + 1);
		if (rect.width() <= 0) // Have at least one visible pixel of width
			rect.setLeft(rect.right());
	}
	if (rect.left() < basketPoint.x() + frameWidth()) { // Left too... left
		rect.setLeft( basketPoint.x() + frameWidth());
		if (rect.width() <= 0)
			rect.setRight(rect.left());
	}

	return rect;
}

void Basket::disableNextClick()
{
	m_lastDisableClick = TQTime::currentTime();
}

void Basket::recomputeAllStyles()
{
	FOR_EACH_NOTE (note)
		note->recomputeAllStyles();
}

void Basket::removedStates(const TQValueList<State*> &deletedStates)
{
	bool modifiedBasket = false;

	FOR_EACH_NOTE (note)
		if (note->removedStates(deletedStates))
			modifiedBasket = true;

	if (modifiedBasket)
		save();
}

void Basket::insertNote(Note *note, Note *clicked, int zone, const TQPoint &pos, bool animateNewPosition)
{
	if (!note) {
		std::cout << "Wanted to insert NO note" << std::endl;
		return;
	}

	if (clicked && zone == Note::BottomColumn) {
		// When inserting at the bottom of a column, it's obvious the new note SHOULD inherit tags.
		// We ensure that by changing the insertion point after the last note of the column:
		Note *last = clicked->lastChild();
		if (last) {
			clicked = last;
			zone = Note::BottomInsert;
		}
	}

	/// Insertion at the bottom of a column:
	if (clicked && zone == Note::BottomColumn) {
		note->setWidth(clicked->rightLimit() - clicked->x());
		Note *lastChild = clicked->lastChild();
		if (!animateNewPosition || !Settings::playAnimations())
			for (Note *n = note; n; n = n->next()) {
				n->setXRecursivly(clicked->x());
				n->setYRecursivly((lastChild ? lastChild : clicked)->bottom() + 1);
			}
		appendNoteIn(note, clicked);

	/// Insertion relative to a note (top/bottom, insert/group):
	} else if (clicked) {
		note->setWidth(clicked->width());
		if (!animateNewPosition || !Settings::playAnimations())
			for (Note *n = note; n; n = n->next()) {
				if (zone == Note::TopGroup || zone == Note::BottomGroup)
					n->setXRecursivly(clicked->x() + Note::GROUP_WIDTH);
				else
					n->setXRecursivly(clicked->x());
				if (zone == Note::TopInsert || zone == Note::TopGroup)
					n->setYRecursivly(clicked->y());
				else
					n->setYRecursivly(clicked->bottom() + 1);
			}

		if      (zone == Note::TopInsert)    { appendNoteBefore(note, clicked); }
		else if (zone == Note::BottomInsert) { appendNoteAfter(note,  clicked); }
		else if (zone == Note::TopGroup)     { groupNoteBefore(note,  clicked); }
		else if (zone == Note::BottomGroup)  { groupNoteAfter(note,   clicked); }

	/// Free insertion:
	} else if (isFreeLayout()) {
		// Group if note have siblings:
		if (note->next()) {
			Note *group = new Note(this);
			for (Note *n = note; n; n = n->next())
				n->setParentNote(group);
			group->setFirstChild(note);
			note = group;
		}
		// Insert at cursor position:
		const int initialWidth = 250;
		note->setWidth(note->isGroup() ? Note::GROUP_WIDTH : initialWidth);
		if (note->isGroup() && note->firstChild())
			note->setInitialHeight(note->firstChild()->height());
		//note->setGroupWidth(initialWidth);
		if (animateNewPosition && Settings::playAnimations())
			note->setFinalPosition(pos.x(), pos.y());
		else {
			note->setXRecursivly(pos.x());
			note->setYRecursivly(pos.y());
		}
		appendNoteAfter(note, lastNote());
	}

	relayoutNotes(true);
}

void Basket::clickedToInsert(TQMouseEvent *event, Note *clicked, /*Note::Zone*/int zone)
{
	Note *note;
	if (event->button() == TQt::MidButton)
		note = NoteFactory::dropNote(TDEApplication::clipboard()->data(TQClipboard::Selection), this);
	else
		note = NoteFactory::createNoteText("", this);

	if (!note)
		return;

	insertNote(note, clicked, zone, event->pos(), /*animateNewPosition=*/false);

//	ensureNoteVisible(lastInsertedNote()); // TODO: in insertNote()

	if (event->button() != TQt::MidButton) {
		removeInserter(); // Case: user clicked below a column to insert, the note is inserted and doHoverEffects() put a new inserter below. We don't want it.
		closeEditor();
		noteEdit(note, /*justAdded=*/true);
	}
}

void Basket::contentsDragEnterEvent(TQDragEnterEvent *event)
{
	m_isDuringDrag = true;
	Global::bnpView->updateStatusBarHint();
	if (NoteDrag::basketOf(event) == this)
		m_draggedNotes = NoteDrag::notesOf(event);
}

void Basket::contentsDragMoveEvent(TQDragMoveEvent *event)
{
//	m_isDuringDrag = true;

//	if (isLocked())
//		return;

//	FIXME: viewportToContents does NOT work !!!
//	TQPoint pos = viewportToContents(event->pos());
//	TQPoint pos( event->pos().x() + contentsX(), event->pos().y() + contentsY() );

//	if (insertAtCursorPos())
//		computeInsertPlace(pos);
	doHoverEffects(event->pos());

//	showFrameInsertTo();
	if (isFreeLayout() || noteAt(event->pos().x(), event->pos().y())) // Cursor before rightLimit() or hovering the dragged source notes
		acceptDropEvent(event);
	else {
		event->acceptAction(false);
		event->accept(false);
	}

/*	Note *hoveredNote = noteAt(event->pos().x(), event->pos().y());
	if ( (isColumnsLayout() && !hoveredNote) || (draggedNotes().contains(hoveredNote)) ) {
		event->acceptAction(false);
		event->accept(false);
	} else
		acceptDropEvent(event);*/

	// A workarround since TQScrollView::dragAutoScroll seem to have no effect :
//	ensureVisible(event->pos().x() + contentsX(), event->pos().y() + contentsY(), 30, 30);
//	TQScrollView::dragMoveEvent(event);
}

void Basket::contentsDragLeaveEvent(TQDragLeaveEvent*)
{
//	resetInsertTo();
	m_isDuringDrag = false;
	m_draggedNotes.clear();
	m_noActionOnMouseRelease = true;
	emit resetStatusBarText();
	doHoverEffects();
}

void Basket::contentsDropEvent(TQDropEvent *event)
{
	TQPoint pos = event->pos();
	std::cout << "Contents Drop Event at position " << pos.x() << ":" << pos.y() << std::endl;

	m_isDuringDrag = false;
	emit resetStatusBarText();

//	if (isLocked())
//		return;

	// Do NOT check the bottom&right borders.
	// Because imagine someone drag&drop a big note from the top to the bottom of a big basket (with big vertical scrollbars),
	// the note is first removed, and relayoutNotes() compute the new height that is smaller
	// Then noteAt() is called for the mouse pointer position, because the basket is now smaller, the cursor is out of boundaries!!!
	// Should, of course, not return 0:
	Note *clicked = noteAt(event->pos().x(), event->pos().y());

	if (NoteFactory::movingNotesInTheSameBasket(event, this, event->action()) && event->action() == TQDropEvent::Move) {
		m_doNotCloseEditor = true;
	}

	Note *note = NoteFactory::dropNote( event, this, true, event->action(), dynamic_cast<Note*>(event->source()) );

	if (note) {
		Note::Zone zone = (clicked ? clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()), /*toAdd=*/true ) : Note::None);
		bool animateNewPosition = NoteFactory::movingNotesInTheSameBasket(event, this, event->action());
		if (animateNewPosition) {
			FOR_EACH_NOTE (n)
				n->setOnTop(false);
			// FOR_EACH_NOTE_IN_CHUNK(note)
			for (Note *n = note; n; n = n->next())
				n->setOnTop(true);
		}

		insertNote(note, clicked, zone, event->pos(), animateNewPosition);

		// If moved a note on bottom, contentsHeight has been disminished, then view scrolled up, and we should re-scroll the view down:
		ensureNoteVisible(note);

//		if (event->button() != TQt::MidButton) {
//			removeInserter(); // Case: user clicked below a column to insert, the note is inserted and doHoverEffects() put a new inserter below. We don't want it.
//		}

//		resetInsertTo();
//		doHoverEffects(); called by insertNote()
		save();
	}

	m_draggedNotes.clear();

	m_doNotCloseEditor = false;
	// When starting the drag, we saved where we were editing.
	// This is because during a drag, the mouse can fly over the text edit and move the cursor position, and even HIDE the cursor.
	// So we re-show the cursor, and re-position it at the right place:
	if (m_editor && m_editor->textEdit()) {
		TQTextEdit *editor = m_editor->textEdit();
		editor->setCursorPosition(m_editParagraph, m_editIndex);
	}
}

// handles dropping of a note to basket that is not shown
// (usually through its entry in the basket list)
void Basket::blindDrop(TQDropEvent* event)
{
	if (!m_isInsertPopupMenu && redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->paste();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->paste();
	} else {
		if (!isLoaded()) {
			Global::bnpView->showPassiveLoading(this);
			load();
		}
		closeEditor();
		unselectAll();
		Note *note = NoteFactory::dropNote( event, this, true, event->action(),
											dynamic_cast<Note*>(event->source()) );
		if (note) {
			insertCreatedNote(note);
			//unselectAllBut(note);
			if (Settings::usePassivePopup())
				Global::bnpView->showPassiveDropped(i18n("Dropped to basket <i>%1</i>"));
		}
	}
	save();
}

void Basket::insertEmptyNote(int type)
{
	if (!isLoaded())
		load();
	if (isDuringEdit())
		closeEditor();
	Note *note = NoteFactory::createEmptyNote((NoteType::Id)type, this);
	insertCreatedNote(note/*, / *edit=* /true*/);
	noteEdit(note, /*justAdded=*/true);
}

void Basket::insertWizard(int type)
{
	saveInsertionData();
	Note *note = 0;
	switch (type) {
		default:
		case 1: note = NoteFactory::importKMenuLauncher(this); break;
		case 2: note = NoteFactory::importIcon(this);          break;
		case 3: note = NoteFactory::importFileContent(this);   break;
	}
	if (!note)
		return;
	restoreInsertionData();
	insertCreatedNote(note);
	unselectAllBut(note);
	resetInsertionData();
}

void Basket::insertColor(const TQColor &color)
{
	Note *note = NoteFactory::createNoteColor(color, this);
	restoreInsertionData();
	insertCreatedNote(note);
	unselectAllBut(note);
	resetInsertionData();
}

void Basket::insertImage(const TQPixmap &image)
{
	Note *note = NoteFactory::createNoteImage(image, this);
	restoreInsertionData();
	insertCreatedNote(note);
	unselectAllBut(note);
	resetInsertionData();
}

void Basket::pasteNote(TQClipboard::Mode mode)
{
	if (!m_isInsertPopupMenu && redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->paste();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->paste();
	} else {
		if (!isLoaded()) {
			Global::bnpView->showPassiveLoading(this);
			load();
		}
		closeEditor();
		unselectAll();
		Note *note = NoteFactory::dropNote(TDEApplication::clipboard()->data(mode), this);
		if (note) {
			insertCreatedNote(note);
			//unselectAllBut(note);
		}
	}
}

void Basket::insertCreatedNote(Note *note)
{
	// Get the insertion data if the user clicked inside the basket:
	Note *clicked = m_clickedToInsert;
	int zone      = m_zoneToInsert;
	TQPoint pos    = m_posToInsert;

	// If it isn't the case, use the default position:
	if (!clicked && (pos.x() < 0 || pos.y() < 0)) {
		// Insert right after the focused note:
		focusANote();
		if (m_focusedNote) {
			clicked = m_focusedNote;
			zone    = (m_focusedNote->isFree() ? Note::BottomGroup : Note::BottomInsert);
			pos     = TQPoint(m_focusedNote->x(), m_focusedNote->finalBottom());
		// Insert at the end of the last column:
		} else if (isColumnsLayout()) {
			Note *column = /*(Settings::newNotesPlace == 0 ?*/ firstNote() /*: lastNote())*/;
			/*if (Settings::newNotesPlace == 0 && column->firstChild()) { // On Top, if at least one child in the column
				clicked = column->firstChild();
				zone    = Note::TopInsert;
			} else { // On Bottom*/
				clicked = column;
				zone    = Note::BottomColumn;
			/*}*/
		// Insert at free position:
		} else {
			pos = TQPoint(0, 0);
		}
	}

	insertNote(note, clicked, zone, pos);
//	ensureNoteVisible(lastInsertedNote());
	removeInserter(); // Case: user clicked below a column to insert, the note is inserted and doHoverEffects() put a new inserter below. We don't want it.
//	resetInsertTo();
	save();
}

void Basket::saveInsertionData()
{
	m_savedClickedToInsert = m_clickedToInsert;
	m_savedZoneToInsert    = m_zoneToInsert;
	m_savedPosToInsert     = m_posToInsert;
}

void Basket::restoreInsertionData()
{
	m_clickedToInsert = m_savedClickedToInsert;
	m_zoneToInsert    = m_savedZoneToInsert;
	m_posToInsert     = m_savedPosToInsert;
}

void Basket::resetInsertionData()
{
	m_clickedToInsert = 0;
	m_zoneToInsert    = 0;
	m_posToInsert     = TQPoint(-1, -1);
}

void Basket::hideInsertPopupMenu()
{
	TQTimer::singleShot( 50/*ms*/, this, TQ_SLOT(timeoutHideInsertPopupMenu()) );
}

void Basket::timeoutHideInsertPopupMenu()
{
	resetInsertionData();
}

void Basket::acceptDropEvent(TQDropEvent *event, bool preCond)
{
	// FIXME: Should not accept all actions! Or not all actions (link not supported?!)
	event->acceptAction(preCond && 1);
	event->accept(preCond);
}

void Basket::contentsMouseReleaseEvent(TQMouseEvent *event)
{
	// Now disallow drag:
	m_canDrag = false;

	// Cancel Resizer move:
	if (m_resizingNote) {
		m_resizingNote  = 0;
		m_pickedResizer = 0;
		m_lockedHovering = false;
		doHoverEffects();
		save();
	}

	// Cancel Note move:
/*	if (m_movingNote) {
		m_movingNote   = 0;
		m_pickedHandle = TQPoint(0, 0);
		m_lockedHovering = false;
		//doHoverEffects();
		save();
	}
*/

	// Cancel Selection rectangle:
	if (m_isSelecting) {
		m_isSelecting = false;
		stopAutoScrollSelection();
		resetWasInLastSelectionRect();
		doHoverEffects();
		updateContents(m_selectionRect);
	}
	m_selectionStarted = false;

	Note *clicked = noteAt(event->pos().x(), event->pos().y());
	Note::Zone zone = (clicked ? clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()) ) : Note::None);
	if ((zone == Note::Handle || zone == Note::Group) && editedNote() && editedNote() == clicked) {
		if (m_ignoreCloseEditorOnNextMouseRelease)
			m_ignoreCloseEditorOnNextMouseRelease = false;
		else {
			bool editedNoteStillThere = closeEditor();
			if (editedNoteStillThere)
				//clicked->setSelected(true);
				unselectAllBut(clicked);
		}
	}


	if (event->stateAfter() == 0 && (zone == Note::Group || zone == Note::Handle)) {
		closeEditor();
		unselectAllBut(clicked);
	}


	// Do nothing if an action has already been made during mousePressEvent,
	// or if user made a selection and canceled it by regressing to a very small rectangle.
	if (m_noActionOnMouseRelease)
		return;
	// We immediatly set it to true, to avoid actions set on mouseRelease if NO mousePress event has been triggered.
	// This is the case when a popup menu is shown, and user click to the basket area to close it:
	// the menu then receive the mousePress event and the basket area ONLY receive the mouseRelease event.
	// Obviously, nothing should be done in this case:
	m_noActionOnMouseRelease = true;



	if (event->button() == TQt::MidButton && zone != Note::Resizer && (!isDuringEdit() || clicked != editedNote())) {
		if ((Settings::middleAction() != 0) && (event->stateAfter() == TQt::ShiftButton)) {
			m_clickedToInsert = clicked;
			m_zoneToInsert    = zone;
			m_posToInsert     = event->pos();
			closeEditor();
			removeInserter();                     // If clicked at an insertion line and the new note shows a dialog for editing,
			NoteType::Id type = (NoteType::Id)0;  //  hide that inserter before the note edition instead of after the dialog is closed
			switch (Settings::middleAction()) {
				case 5: type = NoteType::Color;    break;
				case 6:
					Global::bnpView->grabScreenshot();
					return;
				case 7:
					Global::bnpView->slotColorFromScreen();
					return;
				case 8:
					Global::bnpView->insertWizard(3); // loadFromFile
					return;
				case 9:
					Global::bnpView->insertWizard(1); // importKMenuLauncher
					return;
				case 10:
					Global::bnpView->insertWizard(2); // importIcon
					return;
			}
			if (type != 0) {
				m_ignoreCloseEditorOnNextMouseRelease = true;
				Global::bnpView->insertEmpty(type);
				return;
			}
		}
	}

//	Note *clicked = noteAt(event->pos().x(), event->pos().y());
	if ( ! clicked ) {
		if (isFreeLayout() && event->button() == TQt::LeftButton) {
			clickedToInsert(event);
			save();
		}
		return;
	}
//	Note::Zone zone = clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()) );

	// Convenient variables:
	bool controlPressed = event->stateAfter() & TQt::ControlButton;
	bool shiftPressed   = event->stateAfter() & TQt::ShiftButton;

	if (clicked && zone != Note::None && zone != Note::BottomColumn && zone != Note::Resizer && (controlPressed || shiftPressed)) {
		if (controlPressed && shiftPressed)
			selectRange(m_startOfShiftSelectionNote, clicked, /*unselectOthers=*/false);
		else if (shiftPressed)
			selectRange(m_startOfShiftSelectionNote, clicked);
		else if (controlPressed)
			clicked->setSelectedRecursivly(!clicked->allSelected());
		setFocusedNote(clicked); /// /// ///
		m_startOfShiftSelectionNote = (clicked->isGroup() ? clicked->firstRealChild() : clicked);
		m_noActionOnMouseRelease = true;
		return;
	}

	// Switch tag states:
	if (zone >= Note::Emblem0) {
		if (event->button() == TQt::LeftButton) {
			int icons = -1;
			for (State::List::iterator it = clicked->states().begin(); it != clicked->states().end(); ++it) {
				if ( ! (*it)->emblem().isEmpty() )
					icons++;
				if (icons == zone - Note::Emblem0) {
					State *state = (*it)->nextState();
					if (!state)
						return;
					it = clicked->states().insert(it, state);
					++it;
					clicked->states().remove(it);
					clicked->recomputeStyle();
					clicked->unbufferize();
					updateNote(clicked);
					updateEditorAppearance();
					filterAgain();
					save();
					break;
				}
			}
			return;
		}/* else if (event->button() == TQt::RightButton) {
		popupEmblemMenu(clicked, zone - Note::Emblem0);
		return;
	}*/
	}

	// Insert note or past clipboard:
	TQString  text;
//	Note *note;
	TQString  link;
	//int zone = zone;
	if (event->button() == TQt::MidButton && zone == Note::Resizer)
		return; //zone = clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()), true );
	if (event->button() == TQt::RightButton && (clicked->isColumn() || zone == Note::Resizer))
		return;
	if (clicked->isGroup() && zone == Note::None)
		return;
	switch (zone) {
		case Note::Handle:
		case Note::Group:
			// We select note on mousePress if it was unselected or Ctrl is pressed.
			// But the user can want to drag select_s_ notes, so it the note is selected, we only select it alone on mouseRelease:
			if (event->stateAfter() == 0) {
				std::cout << "EXEC" << std::endl;
				if ( !(event->stateAfter() & TQt::ControlButton) && clicked->allSelected())
					unselectAllBut(clicked);
				if (zone == Note::Handle && isDuringEdit() && editedNote() == clicked) {
					closeEditor();
					clicked->setSelected(true);
				}
			}
			break;

		case Note::Custom0:
			//unselectAllBut(clicked);
			setFocusedNote(clicked);
			noteOpen(clicked);
			break;

		case Note::GroupExpander:
		case Note::TagsArrow:
			break;

		case Note::Link:
			link = clicked->linkAt(event->pos() - TQPoint(clicked->x(), clicked->y()));
			if ( ! link.isEmpty() ) {
				if (link == "basket-internal-remove-basket") {
					// TODO: ask confirmation: "Do you really want to delete the welcome baskets?\n You can re-add them at any time in the Help menu."
					Global::bnpView->doBasketDeletion(this);
				} else if (link == "basket-internal-import") {
					TQPopupMenu *menu = Global::bnpView->popupMenu("fileimport");
					menu->exec(event->globalPos());
				} else {
					KRun *run = new KRun(link); //  open the URL.
					run->setAutoDelete(true);
				}
				break;
			} // If there is no link, edit note content
		case Note::Content:
			closeEditor();
			unselectAllBut(clicked);
			noteEdit(clicked, /*justAdded=*/false, event->pos());
			break;

		case Note::TopInsert:
		case Note::TopGroup:
		case Note::BottomInsert:
		case Note::BottomGroup:
		case Note::BottomColumn:
			clickedToInsert(event, clicked, zone);
			save();
			break;

		case Note::None:
		default:
			KMessageBox::information(viewport(),
				i18n("This message should never appear. If it does, this program is buggy! "
				"Please report the bug to the developer."));
			break;
	}
}

void Basket::contentsMouseDoubleClickEvent(TQMouseEvent *event)
{
	Note *clicked = noteAt(event->pos().x(), event->pos().y());
	Note::Zone zone = (clicked ? clicked->zoneAt( event->pos() - TQPoint(clicked->x(), clicked->y()) ) : Note::None);

	if (event->button() == TQt::LeftButton && (zone == Note::Group || zone == Note::Handle)) {
		doCopy(CopyToSelection);
		m_noActionOnMouseRelease = true;
	} else
		contentsMousePressEvent(event);
}

void Basket::contentsMouseMoveEvent(TQMouseEvent *event)
{
	// Drag the notes:
	if (m_canDrag && (m_pressPos - event->pos()).manhattanLength() > TDEApplication::startDragDistance()) {
		m_canDrag          = false;
		m_isSelecting      = false; // Don't draw selection rectangle ater drag!
		m_selectionStarted = false;
		NoteSelection *selection = selectedNotes();
		if (selection && selection->firstStacked()) {
			TQDragObject *d = NoteDrag::dragObject(selection, /*cutting=*/false, /*source=*/this); // d will be deleted by TQt
		/*bool shouldRemove = */d->drag();
//		delete selection;

		// Never delete because URL is dragged and the file must be available for the extern appliation
//		if (shouldRemove && d->target() == 0) // If target is another application that request to remove the note
//			emit wantDelete(this);
		}
		return;
	}

	// Moving a Resizer:
	if (m_resizingNote) {
		int groupWidth = event->pos().x() - m_resizingNote->x() - m_pickedResizer;
		int minRight   = m_resizingNote->minRight();
		int maxRight   = 100 * contentsWidth(); // A big enough value (+infinity) for free layouts.
		Note *nextColumn = m_resizingNote->next();
		if (m_resizingNote->isColumn()) {
			if (nextColumn)
				maxRight = nextColumn->x() + nextColumn->rightLimit() - nextColumn->minRight() - Note::RESIZER_WIDTH;
			else
				maxRight = contentsWidth();
		}
		if (groupWidth > maxRight - m_resizingNote->x())
			groupWidth = maxRight - m_resizingNote->x();
		if (groupWidth < minRight - m_resizingNote->x())
			groupWidth = minRight - m_resizingNote->x();
		int delta = groupWidth - m_resizingNote->groupWidth();
		m_resizingNote->setGroupWidth(groupWidth);
		// If resizing columns:
		if (m_resizingNote->isColumn()) {
			Note *column = m_resizingNote;
			if ( (column = column->next()) ) {
				// Next columns should not have them X coordinate animated, because it would flicker:
				column->setXRecursivly(column->x() + delta);
				// And the resizer should resize the TWO sibling columns, and not push the other columns on th right:
				column->setGroupWidth(column->groupWidth() - delta);
			}
		}
		relayoutNotes(true);
	}

	// Moving a Note:
/*	if (m_movingNote) {
		int x = event->pos().x() - m_pickedHandle.x();
		int y = event->pos().y() - m_pickedHandle.y();
		if (x < 0) x = 0;
		if (y < 0) y = 0;
		m_movingNote->setX(x);
		m_movingNote->setY(y);
		m_movingNote->relayoutAt(x, y, / *animate=* /false);
		relayoutNotes(true);
	}
*/

	// Dragging the selection rectangle:
	if (m_selectionStarted)
		doAutoScrollSelection();

	doHoverEffects(event->pos());
}

void Basket::doAutoScrollSelection()
{
	static const int AUTO_SCROLL_MARGIN = 50;  // pixels
	static const int AUTO_SCROLL_DELAY  = 100; // milliseconds

	TQPoint pos = viewport()->mapFromGlobal(TQCursor::pos());

	// Do the selection:

	if (m_isSelecting)
		updateContents(m_selectionRect);

	m_selectionEndPoint = viewportToContents(pos);
	m_selectionRect = TQRect(m_selectionBeginPoint, m_selectionEndPoint).normalize();
	if (m_selectionRect.left() < 0)                    m_selectionRect.setLeft(0);
	if (m_selectionRect.top() < 0)                     m_selectionRect.setTop(0);
	if (m_selectionRect.right() >= contentsWidth())    m_selectionRect.setRight(contentsWidth() - 1);
	if (m_selectionRect.bottom() >= contentsHeight())  m_selectionRect.setBottom(contentsHeight() - 1);

	if ( (m_selectionBeginPoint - m_selectionEndPoint).manhattanLength() > TQApplication::startDragDistance() ) {
		m_isSelecting = true;
		selectNotesIn(m_selectionRect, m_selectionInvert);
		updateContents(m_selectionRect);
		m_noActionOnMouseRelease = true;
	} else {
			// If the user was selecting but cancel by making the rectangle too small, cancel it really!!!
		if (m_isSelecting) {
			if (m_selectionInvert)
				selectNotesIn(TQRect(), m_selectionInvert);
			else
				unselectAllBut(0); // TODO: unselectAll();
		}
		if (m_isSelecting)
			resetWasInLastSelectionRect();
		m_isSelecting = false;
		stopAutoScrollSelection();
		return;
	}

	// Do the auto-scrolling:
	// FIXME: It's still flickering

	TQRect insideRect(AUTO_SCROLL_MARGIN, AUTO_SCROLL_MARGIN, visibleWidth() - 2*AUTO_SCROLL_MARGIN, visibleHeight() - 2*AUTO_SCROLL_MARGIN);

	int dx = 0;
	int dy = 0;

	if (pos.y() < AUTO_SCROLL_MARGIN)
		dy = pos.y() - AUTO_SCROLL_MARGIN;
	else if (pos.y() > visibleHeight() - AUTO_SCROLL_MARGIN)
		dy = pos.y() - visibleHeight() + AUTO_SCROLL_MARGIN;

	if (pos.x() < AUTO_SCROLL_MARGIN)
		dx = pos.x() - AUTO_SCROLL_MARGIN;
	else if (pos.x() > visibleWidth() - AUTO_SCROLL_MARGIN)
		dx = pos.x() - visibleWidth() + AUTO_SCROLL_MARGIN;

	if (dx || dy) {
		kapp->sendPostedEvents(); // Do the repaints, because the scrolling will make the area to repaint to be wrong
		scrollBy(dx, dy);
		if (!m_autoScrollSelectionTimer.isActive())
			m_autoScrollSelectionTimer.start(AUTO_SCROLL_DELAY);
	} else
		stopAutoScrollSelection();
}

void Basket::stopAutoScrollSelection()
{
	m_autoScrollSelectionTimer.stop();
}

void Basket::resetWasInLastSelectionRect()
{
	Note *note = m_firstNote;
	while (note) {
		note->resetWasInLastSelectionRect();
		note = note->next();
	}
}

void Basket::selectAll()
{
	if (redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->selectAll();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->selectAll();
	} else {
		// First select all in the group, then in the parent group...
		Note *child  = m_focusedNote;
		Note *parent = (m_focusedNote ? m_focusedNote->parentNote() : 0);
		while (parent) {
			if (!parent->allSelected()) {
				parent->setSelectedRecursivly(true);
				return;
			}
			child  = parent;
			parent = parent->parentNote();
		}
		// Then, select all:
		FOR_EACH_NOTE (note)
			note->setSelectedRecursivly(true);
	}
}

void Basket::unselectAll()
{
	if (redirectEditActions()) {
		if (m_editor->textEdit()) {
			m_editor->textEdit()->removeSelection();
			selectionChangedInEditor(); // THIS IS NOT EMITED BY TQt!!!
		} else if (m_editor->lineEdit())
			m_editor->lineEdit()->deselect();
	} else {
		if (countSelecteds() > 0) // Optimisation
			FOR_EACH_NOTE (note)
				note->setSelectedRecursivly(false);
	}
}

void Basket::invertSelection()
{
	FOR_EACH_NOTE (note)
		note->invertSelectionRecursivly();
}

void Basket::unselectAllBut(Note *toSelect)
{
	FOR_EACH_NOTE (note)
		note->unselectAllBut(toSelect);
}

void Basket::invertSelectionOf(Note *toSelect)
{
	FOR_EACH_NOTE (note)
		note->invertSelectionOf(toSelect);
}

void Basket::selectNotesIn(const TQRect &rect, bool invertSelection, bool unselectOthers /*= true*/)
{
	FOR_EACH_NOTE (note)
		note->selectIn(rect, invertSelection, unselectOthers);
}

void Basket::doHoverEffects()
{
	doHoverEffects(  viewportToContents( viewport()->mapFromGlobal(TQCursor::pos()) )  );
}

void Basket::doHoverEffects(Note *note, Note::Zone zone, const TQPoint &pos)
{
	// Inform the old and new hovered note (if any):
	Note *oldHoveredNote = m_hoveredNote;
	if (note != m_hoveredNote) {
		if (m_hoveredNote) {
			m_hoveredNote->setHovered(false);
			m_hoveredNote->setHoveredZone(Note::None);
			updateNote(m_hoveredNote);
		}
		m_hoveredNote = note;
		if (note)
			note->setHovered(true);
	}

	// If we are hovering a note, compute which zone is hovered and inform the note:
	if (m_hoveredNote) {
		if (zone != m_hoveredZone || oldHoveredNote != m_hoveredNote) {
			m_hoveredZone = zone;
			m_hoveredNote->setCursor(zone);
			updateNote(m_hoveredNote);
		}
		m_hoveredNote->setHoveredZone(zone);
		// If we are hovering an insert line zone, update this thing:
		if (zone == Note::TopInsert || zone == Note::TopGroup || zone == Note::BottomInsert || zone == Note::BottomGroup || zone == Note::BottomColumn)
			placeInserter(m_hoveredNote, zone);
		else
			removeInserter();
		// If we are hovering an embedded link in a rich text element, show the destination in the statusbar:
		if (zone == Note::Link)
			emit setStatusBarText(m_hoveredNote->linkAt( pos - TQPoint(m_hoveredNote->x(), m_hoveredNote->y()) ));
		else if (m_hoveredNote->content())
			emit setStatusBarText(m_hoveredNote->content()->statusBarMessage(m_hoveredZone));//resetStatusBarText();
	// If we aren't hovering a note, reset all:
	} else {
		if (isFreeLayout() && !isSelecting())
			viewport()->setCursor(TQt::CrossCursor);
		else
			viewport()->unsetCursor();
		m_hoveredZone = Note::None;
		removeInserter();
		emit resetStatusBarText();
	}
}

void Basket::doHoverEffects(const TQPoint &pos)
{
//	if (isDuringEdit())
//		viewport()->unsetCursor();

	// Do we have the right to do hover effects?
	if ( ! m_loaded || m_lockedHovering)
		return;

	// enterEvent() (mouse enter in the widget) set m_underMouse to true, and leaveEvent() make it false.
	// But some times the enterEvent() is not trigerred: eg. when dragging the scrollbar:
	// Ending the drag INSIDE the basket area will make NO hoverEffects() because m_underMouse is false.
	// User need to leave the area and re-enter it to get effects.
	// This hack solve that by dismissing the m_underMouse variable:
	bool underMouse = Global::bnpView->currentBasket() == this && TQRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()).contains(pos);

	// Don't do hover effects when a popup menu is opened.
	// Primarily because the basket area will only receive mouseEnterEvent and mouveLeaveEvent.
	// It willn't be noticed of mouseMoveEvent, which would result in a apparently broken application state:
	if (kapp->activePopupWidget())
		underMouse = false;

	// Compute which note is hovered:
	Note       *note = (m_isSelecting || !underMouse ? 0 : noteAt(pos.x(), pos.y()));
	Note::Zone  zone = (note ? note->zoneAt( pos - TQPoint(note->x(), note->y()), isDuringDrag() ) : Note::None);

	// Inform the old and new hovered note (if any) and update the areas:
	doHoverEffects(note, zone, pos);
}

void Basket::mouseEnteredEditorWidget()
{
	if (!m_lockedHovering && !kapp->activePopupWidget())
		doHoverEffects(editedNote(), Note::Content, TQPoint());
}

void Basket::removeInserter()
{
	if (m_inserterShown) { // Do not hide (and then update/repaint the view) if it is already hidden!
		m_inserterShown = false;
		updateContents(m_inserterRect);
	}
}

void Basket::placeInserter(Note *note, int zone)
{
	// Remove the inserter:
	if (!note) {
		removeInserter();
		return;
	}

	// Update the old position:
	if (inserterShown())
		updateContents(m_inserterRect);
	// Some comodities:
	m_inserterShown = true;
	m_inserterTop   = (zone == Note::TopGroup || zone == Note::TopInsert);
	m_inserterGroup = (zone == Note::TopGroup || zone == Note::BottomGroup);
	// X and width:
	int groupIndent = (note->isGroup() ? note->width() : Note::HANDLE_WIDTH);
	int x     = note->x();
	int width = (note->isGroup() ? note->rightLimit() - note->x() : note->width());
	if (m_inserterGroup) {
		x     += groupIndent;
		width -= groupIndent;
	}
	m_inserterSplit = (Settings::groupOnInsertionLine() && note && !note->isGroup() && !note->isFree() && !note->isColumn());
//	if (note->isGroup())
//		width = note->rightLimit() - note->x() - (m_inserterGroup ? groupIndent : 0);
	// Y:
	int y = note->y() - (m_inserterGroup && m_inserterTop ? 1 : 3);
	if (!m_inserterTop)
		y += (note->isColumn() ? note->finalHeight() : note->height());
	// Assigning result:
	m_inserterRect = TQRect(x, y, width, 6 - (m_inserterGroup ? 2 : 0));
	// Update the new position:
	updateContents(m_inserterRect);
}

inline void drawLineByRect(TQPainter &painter, int x, int y, int width, int height)
{
	painter.drawLine(x, y, x + width - 1, y + height - 1);
}

void Basket::drawInserter(TQPainter &painter, int xPainter, int yPainter)
{
	if (!m_inserterShown)
		return;

	TQRect rect = m_inserterRect; // For shorter code-lines when drawing!
	rect.moveBy(-xPainter, -yPainter);
	int lineY  = (m_inserterGroup && m_inserterTop ? 0 : 2);
	int roundY = (m_inserterGroup && m_inserterTop ? 0 : 1);

	TQColor dark  = TDEApplication::palette().active().dark();
	TQColor light = dark.light().light();
	if (m_inserterGroup && Settings::groupOnInsertionLine())
		light = Tools::mixColor(light, TDEGlobalSettings::highlightColor());
	painter.setPen(dark);
	// The horizontal line:
	//painter.drawRect(       rect.x(),                    rect.y() + lineY,  rect.width(), 2);
	int width = rect.width() - 4;
	drawGradient(&painter, dark,  light, rect.x() + 2,           rect.y() + lineY, width/2,         2, /*sunken=*/false, /*horz=*/false, /*flat=*/false);
	drawGradient(&painter, light, dark,  rect.x() + 2 + width/2, rect.y() + lineY, width - width/2, 2, /*sunken=*/false, /*horz=*/false, /*flat=*/false);
	// The left-most and right-most edges (biggest vertical lines):
	drawLineByRect(painter, rect.x(),                    rect.y(),          1,            (m_inserterGroup ? 4 : 6));
	drawLineByRect(painter, rect.x() + rect.width() - 1, rect.y(),          1,            (m_inserterGroup ? 4 : 6));
	// The left and right mid vertical lines:
	drawLineByRect(painter, rect.x() + 1,                rect.y() + roundY, 1,            (m_inserterGroup ? 3 : 4));
	drawLineByRect(painter, rect.x() + rect.width() - 2, rect.y() + roundY, 1,            (m_inserterGroup ? 3 : 4));
	// Draw the split as a feedback to know where is the limit between insert and group:
	if (m_inserterSplit) {
		int noteWidth = rect.width() + (m_inserterGroup ? Note::HANDLE_WIDTH : 0);
		int xSplit = rect.x() - (m_inserterGroup ? Note::HANDLE_WIDTH : 0) + noteWidth / 2;
		painter.setPen(Tools::mixColor(dark, light));
		painter.drawRect(xSplit - 2, rect.y() + lineY, 4, 2);
		painter.setPen(dark);
		painter.drawRect(xSplit - 1, rect.y() + lineY, 2, 2);
	}
}

void Basket::maybeTip(const TQPoint &pos)
{
	if ( !m_loaded || !Settings::showNotesToolTip() )
		return;

	TQString message;
	TQRect   rect;

	TQPoint contentPos = viewportToContents(pos);
	Note *note = noteAt(contentPos.x(), contentPos.y());

	if (!note && isFreeLayout()) {
		message = i18n("Insert note here\nRight click for more options");
		TQRect itRect;
		for (TQValueList<TQRect>::iterator it = m_blankAreas.begin(); it != m_blankAreas.end(); ++it) {
			itRect = TQRect(0, 0, visibleWidth(), visibleHeight()).intersect(*it);
			if (itRect.contains(contentPos)) {
				rect = itRect;
				rect.moveLeft(rect.left() - contentsX());
				rect.moveTop( rect.top()  - contentsY());
				break;
			}
		}
	} else {
		if (!note)
			return;

		Note::Zone zone = note->zoneAt( contentPos - TQPoint(note->x(), note->y()) );
		switch (zone) {
			case Note::Resizer:       message = (note->isColumn() ?
			                                    i18n("Resize those columns") :
			                                    (note->isGroup() ?
			                                    i18n("Resize this group") :
			                                    i18n("Resize this note")));                 break;
			case Note::Handle:        message = i18n("Select or move this note");           break;
			case Note::Group:         message = i18n("Select or move this group");          break;
			case Note::TagsArrow:     message = i18n("Assign or remove tags from this note");
			                          if (note->states().count() > 0) {
			                          	message = "<qt><nobr>" + message + "</nobr><br>" + i18n("<b>Assigned Tags</b>: %1");
			                          	TQString tagsString = "";
			                          	for (State::List::iterator it = note->states().begin(); it != note->states().end(); ++it) {
			                          		TQString tagName = "<nobr>" + Tools::textToHTMLWithoutP((*it)->fullName()) + "</nobr>";
			                          		if (tagsString.isEmpty())
			                          			tagsString = tagName;
			                          		else
			                          			tagsString = i18n("%1, %2").arg(tagsString, tagName);
			                          	}
			                          	message = message.arg(tagsString);
			                          }
			                          break;
			case Note::Custom0:       message = note->content()->zoneTip(zone);             break; //"Open this link/Open this file/Open this sound file/Launch this application"
			case Note::GroupExpander: message = (note->isFolded() ?
			                                    i18n("Expand this group") :
			                                    i18n("Collapse this group"));               break;
			case Note::Link:
			case Note::Content:       message = note->content()->editToolTipText();         break;
			case Note::TopInsert:
			case Note::BottomInsert:  message = i18n("Insert note here\nRight click for more options");              break;
			case Note::TopGroup:      message = i18n("Group note with the one below\nRight click for more options"); break;
			case Note::BottomGroup:   message = i18n("Group note with the one above\nRight click for more options"); break;
			case Note::BottomColumn:  message = i18n("Insert note here\nRight click for more options");              break;
			case Note::None:          message = "** Zone NONE: internal error **";                                   break;
			default:
				if (zone >= Note::Emblem0)
					message = note->stateForEmblemNumber(zone - Note::Emblem0)->fullName();
				else
					message = "";
				break;
		}

		if (zone == Note::Content || zone == Note::Link || zone == Note::Custom0) {
			TQStringList keys;
			TQStringList values;

			note->content()->toolTipInfos(&keys, &values);
			keys.append(i18n("Added"));
			keys.append(i18n("Last Modification"));
			values.append(note->addedStringDate());
			values.append(note->lastModificationStringDate());

			message = "<qt><nobr>" + message;
			TQStringList::iterator key;
			TQStringList::iterator value;
			for (key = keys.begin(), value = values.begin(); key != keys.end() && value != values.end(); ++key, ++value)
				message += "<br>" + i18n("of the form 'key: value'", "<b>%1</b>: %2").arg(*key, *value);
			message += "</nobr></qt>";
		} else if (m_inserterSplit && (zone == Note::TopInsert || zone == Note::BottomInsert))
			message += "\n" + i18n("Click on the right to group instead of insert");
		else if (m_inserterSplit && (zone == Note::TopGroup || zone == Note::BottomGroup))
			message += "\n" + i18n("Click on the left to insert instead of group");

		rect = note->zoneRect( zone, contentPos - TQPoint(note->x(), note->y()) );

		rect.moveLeft(rect.left() - contentsX());
		rect.moveTop( rect.top()  - contentsY());

		rect.moveLeft(rect.left() + note->x());
		rect.moveTop( rect.top()  + note->y());
	}

	tip(rect, message);
}

Note* Basket::lastNote()
{
	Note *note = firstNote();
	while (note && note->next())
		note = note->next();
	return note;
}

void Basket::deleteNotes()
{
	Note *note = m_firstNote;

	while (note){
		Note *tmp = note->next();
		delete note;
		note = tmp;
	}
	m_firstNote = 0;
	m_resizingNote = 0;
	m_movingNote = 0;
	m_focusedNote = 0;
	m_startOfShiftSelectionNote = 0;
	m_tagPopupNote = 0;
	m_clickedToInsert = 0;
	m_savedClickedToInsert = 0;
	m_hoveredNote = 0;
	m_count = 0;
	m_countFounds = 0;
	m_countSelecteds = 0;

	emit resetStatusBarText();
	emit countsChanged(this);
}

Note* Basket::noteAt(int x, int y)
{
//NO:
// 	// Do NOT check the bottom&right borders.
// 	// Because imagine someone drag&drop a big note from the top to the bottom of a big basket (with big vertical scrollbars),
// 	// the note is first removed, and relayoutNotes() compute the new height that is smaller
// 	// Then noteAt() is called for the mouse pointer position, because the basket is now smaller, the cursor is out of boundaries!!!
// 	// Should, of course, not return 0:
	if (x < 0 || x > contentsWidth() || y < 0 || y > contentsHeight())
		return 0;

	// When resizing a note/group, keep it highlighted:
	if (m_resizingNote)
		return m_resizingNote;

	// Search and return the hovered note:
	Note *note = m_firstNote;
	Note *possibleNote;
	while (note) {
		possibleNote = note->noteAt(x, y);
		if (possibleNote) {
			if (draggedNotes().contains(possibleNote))
				return 0;
			else
				return possibleNote;
		}
		note = note->next();
	}

	// If the basket is layouted in columns, return one of the columns to be able to add notes in them:
	if (isColumnsLayout()) {
		Note *column = m_firstNote;
		while (column) {
			if (x >= column->x() && x < column->rightLimit())
				return column;
			column = column->next();
		}
	}

	// Nothing found, no note is hovered:
	return NULL;
}

Basket::~Basket()
{
	//delete m_action;
	if(m_decryptBox)
		delete m_decryptBox;
#ifdef HAVE_LIBGPGME
	delete m_gpg;
#endif
	deleteNotes();
}

void Basket::viewportResizeEvent(TQResizeEvent *event)
{
	relayoutNotes(true);
	//cornerWidget()->setShown(horizontalScrollBar()->isShown() && verticalScrollBar()->isShown());
	if (horizontalScrollBar()->isShown() && verticalScrollBar()->isShown()) {
		if (!cornerWidget())
			setCornerWidget(m_cornerWidget);
	} else {
		if (cornerWidget())
			setCornerWidget(0);
	}
//	if (isDuringEdit())
//		ensureNoteVisible(editedNote());
	TQScrollView::viewportResizeEvent(event);
}

void Basket::animateLoad()
{
	const int viewHeight = contentsY() + visibleHeight();

	TQTime t = TQTime::currentTime(); // Set random seed
	srand(t.hour()*12 + t.minute()*60 + t.second()*60);

	Note *note = firstNote();
	while (note) {
		if ((note->finalY() < viewHeight) && note->matching())
			note->initAnimationLoad();
		note = note->next();
	}

	m_loaded = true;
}

TQColor Basket::selectionRectInsideColor()
{
	return Tools::mixColor(Tools::mixColor(backgroundColor(), TDEGlobalSettings::highlightColor()), backgroundColor());
}

TQColor alphaBlendColors(const TQColor &bgColor, const TQColor &fgColor, const int a)
{
	// normal button...
	TQRgb rgb = bgColor.rgb();
	TQRgb rgb_b = fgColor.rgb();
	int alpha = a;
	if (alpha>255) alpha = 255;
	if (alpha<0) alpha = 0;
	int inv_alpha = 255 - alpha;
	TQColor result = TQColor( tqRgb(tqRed(rgb_b)*inv_alpha/255 + tqRed(rgb)*alpha/255,
	                        tqGreen(rgb_b)*inv_alpha/255 + tqGreen(rgb)*alpha/255,
	                        tqBlue(rgb_b)*inv_alpha/255 + tqBlue(rgb)*alpha/255) );

	return result;
}

void Basket::unlock()
{
	TQTimer::singleShot( 0, this, TQ_SLOT(load()) );
}

void Basket::inactivityAutoLockTimeout()
{
	lock();
}

void Basket::drawContents(TQPainter *painter, int clipX, int clipY, int clipWidth, int clipHeight)
{
	// Start the load the first time the basket is shown:
	if (!m_loadingLaunched)
	{
		if(!m_locked)
			TQTimer::singleShot( 0, this, TQ_SLOT(load()) );
		else {
			Global::bnpView->notesStateChanged(); // Show "Locked" instead of "Loading..." in the statusbar
		}
	}

	TQBrush brush(backgroundColor()); // FIXME: share it for all the basket?
	TQRect clipRect(clipX, clipY, clipWidth, clipHeight);

	if(m_locked)
	{
		if(!m_decryptBox)
		{
			m_decryptBox = new TQFrame( this, "m_decryptBox" );
			m_decryptBox->setFrameShape( TQFrame::StyledPanel );
			m_decryptBox->setFrameShadow( TQFrame::Plain );
			m_decryptBox->setLineWidth( 1 );

			TQGridLayout* layout = new TQGridLayout( m_decryptBox, 1, 1, 11, 6, "decryptBoxLayout");

#ifdef HAVE_LIBGPGME
			m_button = new TQPushButton( m_decryptBox, "button" );
			m_button->setText( i18n( "&Unlock" ) );
			layout->addWidget( m_button, 1, 2 );
			connect( m_button, TQ_SIGNAL( clicked() ), this, TQ_SLOT( unlock() ) );
#endif
			TQLabel* label = new TQLabel( m_decryptBox, "label" );
			TQString text = "<b>" + i18n("Password protected basket.") + "</b><br/>";
#ifdef HAVE_LIBGPGME
			label->setText( text + i18n("Press Unlock to access it.") );
#else
			label->setText( text + i18n("Encryption is not supported by<br/>this version of %1.").arg(kapp->aboutData()->programName()) );
#endif
			label->setAlignment( int( TQLabel::AlignTop ) );
			layout->addMultiCellWidget( label, 0, 0, 1, 2 );
			TQLabel* pixmap = new TQLabel( m_decryptBox, "pixmap" );
			pixmap->setPixmap( TDEGlobal::iconLoader()->loadIcon("encrypted", TDEIcon::NoGroup, TDEIcon::SizeHuge) );
			layout->addMultiCellWidget( pixmap, 0, 1, 0, 0 );

			TQSpacerItem* spacer = new TQSpacerItem( 40, 20, TQSizePolicy::Expanding, TQSizePolicy::Minimum );
			layout->addItem( spacer, 1, 1 );

			label = new TQLabel("<small>" +
				i18n("To make baskets stay unlocked, change the automatic<br>"
				     "locking duration in the application settings.") + "</small>",
				m_decryptBox);
			//label->setFixedWidth(label->sizeHint().width() / 2);
			label->setAlignment( int( TQLabel::AlignTop ) );
			layout->addMultiCellWidget( label, 2,2,0,2 );

			m_decryptBox->resize(layout->sizeHint());
		}
		if(m_decryptBox->isHidden())
		{
			m_decryptBox->show();
		}
#ifdef HAVE_LIBGPGME
		m_button->setFocus();
#endif
		m_decryptBox->move((visibleWidth() - m_decryptBox->width()) / 2,
							(visibleHeight() - m_decryptBox->height()) / 2);
	}
	else
	{
		if(m_decryptBox && m_decryptBox->isShown())
			m_decryptBox->hide();
	}

	// Draw notes (but not when it's not loaded or locked yet):
        Note *note = ((m_loaded || m_locked) ? m_firstNote : 0);
	while (note) {
		note->draw(painter, clipRect);
		note = note->next();
	}
	enableActions();

	// Draw loading message:
	if (!m_loaded) {
		TQPixmap pixmap(visibleWidth(), visibleHeight()); // TODO: Clip it to asked size only!
		TQPainter painter2(&pixmap);
		TQSimpleRichText rt(TQString("<center>%1</center>").arg(i18n("Loading...")), TQScrollView::font());
		rt.setWidth(visibleWidth());
		int hrt = rt.height();
		painter2.fillRect(0, 0, visibleWidth(), visibleHeight(), brush);
		blendBackground(painter2, TQRect(0, 0, visibleWidth(), visibleHeight()), -1, -1, /*opaque=*/true);
		TQColorGroup cg = colorGroup();
		cg.setColor(TQColorGroup::Text, textColor());
		rt.draw(&painter2, 0, (visibleHeight() - hrt) / 2, TQRect(), cg);
		painter2.end();
		painter->drawPixmap(0, 0, pixmap);
		return; // TODO: Clip to the wanted rectangle
	}

	// We will draw blank areas below.
	// For each rectangle to be draw there is three ways to do so:
	// - The rectangle is full of the background COLOR  => we fill a rect directly on screen
	// - The rectangle is full of the background PIXMAP => we draw it directly on screen (we draw m_opaqueBackgroundPixmap that is not transparent)
	// - The rectangle contains the resizer             => We draw it on an offscreen buffer and then paint the buffer on screen
	// If the background image is not tiled, we know that recomputeBlankRects() broken rects so that they are full of either background pixmap or color, but not a mix.

	// Draw blank areas (see the last preparation above):
	TQPixmap  pixmap;
	TQPainter painter2;
	TQRect    rect;
	for (TQValueList<TQRect>::iterator it = m_blankAreas.begin(); it != m_blankAreas.end(); ++it) {
		rect = clipRect.intersect(*it);
		if (rect.width() > 0 && rect.height() > 0) {
			// If there is an inserter to draw, draw the image off screen,
			// apply the inserter and then draw the image on screen:
			if (  (inserterShown() && rect.intersects(inserterRect()))  ||  (m_isSelecting && rect.intersects(m_selectionRect))  ) {
				pixmap.resize(rect.width(), rect.height());
				painter2.begin(&pixmap);
				painter2.fillRect(0, 0, rect.width(), rect.height(), backgroundColor());
				blendBackground(painter2, rect, -1, -1, /*opaque=*/true);
				// Draw inserter:
				if (inserterShown() && rect.intersects(inserterRect()))
					drawInserter(painter2, rect.x(), rect.y());
				// Draw selection rect:
				if (m_isSelecting && rect.intersects(m_selectionRect)) {
					TQRect selectionRect = m_selectionRect;
					selectionRect.moveBy(-rect.x(), -rect.y());
					TQRect selectionRectInside(selectionRect.x() + 1, selectionRect.y() + 1, selectionRect.width() - 2, selectionRect.height() - 2);
					if (selectionRectInside.width() > 0 && selectionRectInside.height() > 0) {
						TQColor insideColor = selectionRectInsideColor();
						painter2.fillRect(selectionRectInside, insideColor);
						selectionRectInside.moveBy(rect.x(), rect.y());
						blendBackground(painter2, selectionRectInside, rect.x(), rect.y(), true, /*&*/m_selectedBackgroundPixmap);
					}
					painter2.setPen(TDEGlobalSettings::highlightColor().dark());
					painter2.drawRect(selectionRect);
					painter2.setPen(Tools::mixColor(TDEGlobalSettings::highlightColor().dark(), backgroundColor()));
					painter2.drawPoint(selectionRect.topLeft());
					painter2.drawPoint(selectionRect.topRight());
					painter2.drawPoint(selectionRect.bottomLeft());
					painter2.drawPoint(selectionRect.bottomRight());
				}
				painter2.end();
				painter->drawPixmap(rect.x(), rect.y(), pixmap);
			// If it's only a blank rectangle to draw, draw it directly on screen (faster!!!):
			} else if ( ! hasBackgroundImage() ) {
				painter->fillRect(rect, backgroundColor());
			// It's either a background pixmap to draw or a background color to fill:
			} else {
				if (isTiledBackground() || (rect.x() < backgroundPixmap()->width() && rect.y() < backgroundPixmap()->height()))
					blendBackground(*painter, rect, 0, 0, /*opaque=*/true);
				else
					painter->fillRect(rect, backgroundColor());
			}
		}
	}
}

/*  rect(x,y,width,height)==(xBackgroundToDraw,yBackgroundToDraw,widthToDraw,heightToDraw)
 */
void Basket::blendBackground(TQPainter &painter, const TQRect &rect, int xPainter, int yPainter, bool opaque, TQPixmap *bg)
{
	if (xPainter == -1 && yPainter == -1) {
		xPainter = rect.x();
		yPainter = rect.y();
	}

	if (hasBackgroundImage()) {
		const TQPixmap *bgPixmap = (bg ? /* * */bg : (opaque ? m_opaqueBackgroundPixmap : m_backgroundPixmap));
		if (isTiledBackground())
			painter.drawTiledPixmap(rect.x() - xPainter, rect.y() - yPainter, rect.width(), rect.height(), *bgPixmap, rect.x(), rect.y());
		else
			painter.drawPixmap(rect.x() - xPainter, rect.y() - yPainter, *bgPixmap, rect.x(), rect.y(), rect.width(), rect.height());
	}
}

void Basket::recomputeBlankRects()
{
	m_blankAreas.clear();
	m_blankAreas.append( TQRect(0, 0, contentsWidth(), contentsHeight()) );

	FOR_EACH_NOTE (note)
		note->recomputeBlankRects(m_blankAreas);

	// See the drawing of blank areas in Basket::drawContents()
	if (hasBackgroundImage() && ! isTiledBackground())
		substractRectOnAreas( TQRect(0, 0, backgroundPixmap()->width(), backgroundPixmap()->height()), m_blankAreas, false );
}

void Basket::addAnimatedNote(Note *note)
{
	if (m_animatedNotes.isEmpty()) {
		m_animationTimer.start(FRAME_DELAY);
		m_lastFrameTime = TQTime::currentTime();
	}

	m_animatedNotes.append(note);
}

void Basket::unsetNotesWidth()
{
	Note *note = m_firstNote;
	while (note) {
		note->unsetWidth();
		note = note->next();
	}
}

void Basket::relayoutNotes(bool animate)
{
	if (Global::bnpView->currentBasket() != this)
		return; // Optimize load time, and basket will be relaid out when activated, anyway

	if (!Settings::playAnimations())
		animate = false;

	if (!animate) {
		m_animatedNotes.clear();
		m_animationTimer.stop();
	}

	int h     = 0;
	tmpWidth  = 0;
	tmpHeight = 0;
	Note *note = m_firstNote;
	while (note) {
		if (note->matching()) {
			note->relayoutAt(0, h, animate);
			if (note->hasResizer()) {
				int minGroupWidth = note->minRight() - note->finalX();
				if (note->groupWidth() < minGroupWidth) {
					note->setGroupWidth(minGroupWidth);
					relayoutNotes(animate); // Redo the thing, but this time it should not recurse
					return;
				}
			}
			h += note->finalHeight();
		}
		note = note->next();
	}

	if (isFreeLayout())
		tmpHeight += 100;
	else
		tmpHeight += 15;

	resizeContents( TQMAX(tmpWidth, visibleWidth()), TQMAX(tmpHeight, visibleHeight()) );
	recomputeBlankRects();
	placeEditor();
	doHoverEffects();
	updateContents();
}

void Basket::updateNote(Note *note)
{
	updateContents(note->rect());
	if (note->hasResizer())
		updateContents(note->resizerRect());
}

void Basket::animateObjects()
{
	TQValueList<Note*>::iterator it;
	for (it = m_animatedNotes.begin(); it != m_animatedNotes.end(); )
//		if ((*it)->y() >= contentsY() && (*it)->bottom() <= contentsY() + contentsWidth())
//			updateNote(*it);
		if ((*it)->advance())
			it = m_animatedNotes.remove(it);
	else {
//			if ((*it)->y() >= contentsY() && (*it)->bottom() <= contentsY() + contentsWidth())
//				updateNote(*it);
		++it;
	}

	if (m_animatedNotes.isEmpty()) {
		// Stop animation timer:
		m_animationTimer.stop();
		// Reset all onTop notes:
		Note* note = m_firstNote;
		while (note) {
			note->setOnTop(false);
			note = note->next();
		}
	}

	if (m_focusedNote)
		ensureNoteVisible(m_focusedNote);

	// We refresh content if it was the last frame,
	// or if the drawing of the last frame was not too long.
	if (!m_animationTimer.isActive() || (m_lastFrameTime.msecsTo(TQTime::currentTime()) < FRAME_DELAY*11/10)) { // *11/10 == *1.1 : We keep a 0.1 security margin
		m_lastFrameTime = m_lastFrameTime.addMSecs(FRAME_DELAY);                                               // because timers are not accurate and can trigger late
		//m_lastFrameTime = TQTime::currentTime();
//std::cout << ">>" << m_lastFrameTime.toString("hh:mm:ss.zzz") << std::endl;
		if (m_underMouse)
			doHoverEffects();
		recomputeBlankRects();
		//relayoutNotes(true); // In case an animated note was to the contents view boundaries, resize the view!
		updateContents();
	// If the drawing of the last frame was too long, we skip the drawing of the current and do the next one:
	} else {
		m_lastFrameTime = m_lastFrameTime.addMSecs(FRAME_DELAY);
//std::cout << "+=" << m_lastFrameTime.toString("hh:mm:ss.zzz") << std::endl;
		animateObjects();
	}

	doHoverEffects();
	placeEditor();

/*	int delta = m_deltaY / 3;
	if (delta == 0       && m_deltaY != 0)
	delta = (m_deltaY > 0 ? 1 : -1);
	m_deltaY -= delta;
	resizeContents(contentsWidth(), contentsHeight() + delta); //m_lastNote->y() + m_lastNote->height()
*/
}

void Basket::popupEmblemMenu(Note *note, int emblemNumber)
{
	m_tagPopupNote = note;
	State *state = note->stateForEmblemNumber(emblemNumber);
	State *nextState = state->nextState(/*cycle=*/false);
	Tag *tag = state->parentTag();
	m_tagPopup = tag;

	TQKeySequence sequence = tag->shortcut().operator TQKeySequence();
	bool sequenceOnDelete = (nextState == 0 && !tag->shortcut().isNull());

	TDEPopupMenu menu(this);
	if (tag->countStates() == 1) {
		menu.insertTitle(/*SmallIcon(state->icon()), */tag->name());
		menu.insertItem( SmallIconSet("edit-delete"), i18n("&Remove"),             1 );
		menu.insertItem( SmallIconSet("configure"),  i18n("&Customize..."),       2 );
		menu.insertSeparator();
		menu.insertItem( SmallIconSet("filter"),     i18n("&Filter by this Tag"), 3 );
	} else {
		menu.insertTitle(tag->name());
		TQValueList<State*>::iterator it;
		State *currentState;

		int i = 10;
		for (it = tag->states().begin(); it != tag->states().end(); ++it) {
			currentState = *it;
			TQKeySequence sequence;
			if (currentState == nextState && !tag->shortcut().isNull())
				sequence = tag->shortcut().operator TQKeySequence();
			menu.insertItem(StateMenuItem::radioButtonIconSet(state == currentState, menu.colorGroup()), new StateMenuItem(currentState, sequence, false), i );
			if (currentState == nextState && !tag->shortcut().isNull())
				menu.setAccel(sequence, i);
			++i;
		}
		menu.insertSeparator();
		menu.insertItem( new IndentedMenuItem(i18n("&Remove"),               "edit-delete", (sequenceOnDelete ? sequence : TQKeySequence())), 1 );
		menu.insertItem( new IndentedMenuItem(i18n("&Customize..."),         "configure"),  2 );
		menu.insertSeparator();
		menu.insertItem( new IndentedMenuItem(i18n("&Filter by this Tag"),   "filter"),     3 );
		menu.insertItem( new IndentedMenuItem(i18n("Filter by this &State"), "filter"),     4 );
	}
	if (sequenceOnDelete)
		menu.setAccel(sequence, 1);

	connect( &menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(toggledStateInMenu(int)) );
	connect( &menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())        );
	connect( &menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick())      );

	m_lockedHovering = true;
	menu.exec(TQCursor::pos());
}

void Basket::toggledStateInMenu(int id)
{
	if (id == 1) {
		removeTagFromSelectedNotes(m_tagPopup);
		//m_tagPopupNote->removeTag(m_tagPopup);
		//m_tagPopupNote->setWidth(0); // To force a new layout computation
		updateEditorAppearance();
		filterAgain();
		save();
		return;
	}
	if (id == 2) { // Customize this State:
		TagsEditDialog dialog(this, m_tagPopupNote->stateOfTag(m_tagPopup));
		dialog.exec();
		return;
	}
	if (id == 3) { // Filter by this Tag
		decoration()->filterBar()->filterTag(m_tagPopup);
		return;
	}
	if (id == 4) { // Filter by this State
		decoration()->filterBar()->filterState(m_tagPopupNote->stateOfTag(m_tagPopup));
		return;
	}

	/*addStateToSelectedNotes*/changeStateOfSelectedNotes(m_tagPopup->states()[id - 10] /*, orReplace=true*/);
	//m_tagPopupNote->addState(m_tagPopup->states()[id - 10], true);
	filterAgain();
	save();
}

State* Basket::stateForTagFromSelectedNotes(Tag *tag)
{
	State *state = 0;

	FOR_EACH_NOTE (note)
		if (note->stateForTagFromSelectedNotes(tag, &state) && state == 0)
			return 0;
	return state;
}

void Basket::activatedTagShortcut(Tag *tag)
{
	// Compute the next state to set:
	State *state = stateForTagFromSelectedNotes(tag);
	if (state)
		state = state->nextState(/*cycle=*/false);
	else
		state = tag->states().first();

	// Set or unset it:
	if (state) {
		FOR_EACH_NOTE (note)
			note->addStateToSelectedNotes(state, /*orReplace=*/true);
		updateEditorAppearance();
	} else
		removeTagFromSelectedNotes(tag);

	filterAgain();
	save();
}

void Basket::popupTagsMenu(Note *note)
{
	m_tagPopupNote = note;

	TDEPopupMenu menu(this);
	menu.insertTitle(i18n("Tags"));
// 	TQValueList<Tag*>::iterator it;
// 	Tag *currentTag;
// 	State *currentState;
// 	int i = 10;
// 	for (it = Tag::all.begin(); it != Tag::all.end(); ++it) {
// 		// Current tag and first state of it:
// 		currentTag = *it;
// 		currentState = currentTag->states().first();
// 		TQKeySequence sequence;
// 		if (!currentTag->shortcut().isNull())
// 			sequence = currentTag->shortcut().operator TQKeySequence();
// 		menu.insertItem(StateMenuItem::checkBoxIconSet(note->hasTag(currentTag), menu.colorGroup()), new StateMenuItem(currentState, sequence, true), i );
// 		if (!currentTag->shortcut().isNull())
// 			menu.setAccel(sequence, i);
// 		++i;
// 	}
//
// 	menu.insertSeparator();
// //	menu.insertItem( /*SmallIconSet("edit-delete"),*/ "&Assign New Tag...", 1 );
// 	//id = menu.insertItem( SmallIconSet("edit-delete"), "&Remove All", -2 );
// 	//if (note->states().isEmpty())
// 	//	menu.setItemEnabled(id, false);
// //	menu.insertItem( SmallIconSet("configure"),  "&Customize...", 3 );
// 	menu.insertItem( new IndentedMenuItem(i18n("&Assign New Tag...")),          1 );
// 	menu.insertItem( new IndentedMenuItem(i18n("&Remove All"),   "edit-delete"), 2 );
// 	menu.insertItem( new IndentedMenuItem(i18n("&Customize..."), "configure"),  3 );
//
// 	if (!selectedNotesHaveTags())//note->states().isEmpty())
// 		menu.setItemEnabled(2, false);
//
// 	connect( &menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(toggledTagInMenu(int)) );
// 	connect( &menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(unlockHovering())      );
// 	connect( &menu, TQ_SIGNAL(aboutToHide()),  this, TQ_SLOT(disableNextClick())    );

	Global::bnpView->populateTagsMenu(menu, note);

	m_lockedHovering = true;
	menu.exec(TQCursor::pos());
}

void Basket::unlockHovering()
{
	m_lockedHovering = false;
	doHoverEffects();
}

void Basket::toggledTagInMenu(int id)
{
	if (id == 1) { // Assign new Tag...
		TagsEditDialog dialog(this, /*stateToEdit=*/0, /*addNewTag=*/true);
		dialog.exec();
		if (!dialog.addedStates().isEmpty()) {
			State::List states = dialog.addedStates();
			for (State::List::iterator itState = states.begin(); itState != states.end(); ++itState)
				FOR_EACH_NOTE (note)
					note->addStateToSelectedNotes(*itState);
			updateEditorAppearance();
			filterAgain();
			save();
		}
		return;
	}
	if (id == 2) { // Remove All
		removeAllTagsFromSelectedNotes();
		filterAgain();
		save();
		return;
	}
	if (id == 3) { // Customize...
		TagsEditDialog dialog(this);
		dialog.exec();
		return;
	}

	Tag *tag = Tag::all[id - 10];
	if (!tag)
		return;

	if (m_tagPopupNote->hasTag(tag))
		removeTagFromSelectedNotes(tag);
	else
		addTagToSelectedNotes(tag);
	m_tagPopupNote->setWidth(0); // To force a new layout computation
	filterAgain();
	save();
}

void Basket::addTagToSelectedNotes(Tag *tag)
{
	FOR_EACH_NOTE (note)
		note->addTagToSelectedNotes(tag);
	updateEditorAppearance();
}

void Basket::removeTagFromSelectedNotes(Tag *tag)
{
	FOR_EACH_NOTE (note)
		note->removeTagFromSelectedNotes(tag);
	updateEditorAppearance();
}

void Basket::addStateToSelectedNotes(State *state)
{
	FOR_EACH_NOTE (note)
		note->addStateToSelectedNotes(state);
	updateEditorAppearance();
}

void Basket::updateEditorAppearance()
{
	if (isDuringEdit() && m_editor->widget()) {
		m_editor->widget()->setFont(m_editor->note()->font());
		m_editor->widget()->setPaletteBackgroundColor(m_editor->note()->backgroundColor());
		m_editor->widget()->setPaletteForegroundColor(m_editor->note()->textColor());

		// Uggly Hack arround TQt bugs: placeCursor() don't call any signal:
		HtmlEditor *htmlEditor = dynamic_cast<HtmlEditor*>(m_editor);
		if (htmlEditor) {
			int para, index;
			m_editor->textEdit()->getCursorPosition(&para, &index);
			if (para == 0 && index == 0) {
				m_editor->textEdit()->moveCursor(TQTextEdit::MoveForward,  /*select=*/false);
				m_editor->textEdit()->moveCursor(TQTextEdit::MoveBackward, /*select=*/false);
			} else {
				m_editor->textEdit()->moveCursor(TQTextEdit::MoveBackward, /*select=*/false);
				m_editor->textEdit()->moveCursor(TQTextEdit::MoveForward,  /*select=*/false);
			}
			htmlEditor->cursorPositionChanged(); // Does not work anyway :-( (when clicking on a red bold text, the toolbar still show black normal text)
		}
	}
}

void Basket::editorPropertiesChanged()
{
	if (isDuringEdit() && m_editor->note()->content()->type() == NoteType::Html) {
		m_editor->textEdit()->setAutoFormatting(Settings::autoBullet() ? TQTextEdit::AutoAll : TQTextEdit::AutoNone);
	}
}

void Basket::changeStateOfSelectedNotes(State *state)
{
	FOR_EACH_NOTE (note)
		note->changeStateOfSelectedNotes(state);
	updateEditorAppearance();
}

void Basket::removeAllTagsFromSelectedNotes()
{
	FOR_EACH_NOTE (note)
		note->removeAllTagsFromSelectedNotes();
	updateEditorAppearance();
}

bool Basket::selectedNotesHaveTags()
{
	FOR_EACH_NOTE (note)
		if (note->selectedNotesHaveTags())
			return true;
	return false;
}

TQColor Basket::backgroundColor()
{
	if (m_backgroundColorSetting.isValid())
		return m_backgroundColorSetting;
	else
		return TDEGlobalSettings::baseColor();
}

TQColor Basket::textColor()
{
	if (m_textColorSetting.isValid())
		return m_textColorSetting;
	else
		return TDEGlobalSettings::textColor();
}

void Basket::unbufferizeAll()
{
	FOR_EACH_NOTE (note)
		note->unbufferizeAll();
}

Note* Basket::editedNote()
{
	if (m_editor)
		return m_editor->note();
	else
		return 0;
}

bool Basket::hasTextInEditor()
{
	if (!isDuringEdit() || !redirectEditActions())
		return false;

	if (m_editor->textEdit())
		return ! m_editor->textEdit()->text().isEmpty();
	else if (m_editor->lineEdit())
		return ! m_editor->lineEdit()->text().isEmpty();
	else
		return false;
}

bool Basket::hasSelectedTextInEditor()
{
	if (!isDuringEdit() || !redirectEditActions())
		return false;

	if (m_editor->textEdit()) {
		// The following line does NOT work if one letter is selected and the user press Shift+Left or Shift+Right to unselect than letter:
		// TQt misteriously tell us there is an invisible selection!!
		//return m_editor->textEdit()->hasSelectedText();
		return !m_editor->textEdit()->selectedText().isEmpty();
	} else if (m_editor->lineEdit())
		return m_editor->lineEdit()->hasSelectedText();
	else
		return false;
}

bool Basket::selectedAllTextInEditor()
{
	if (!isDuringEdit() || !redirectEditActions())
		return false;

	if (m_editor->textEdit())
		return m_editor->textEdit()->text().isEmpty() || m_editor->textEdit()->text() == m_editor->textEdit()->selectedText();
	else if (m_editor->lineEdit())
		return m_editor->lineEdit()->text().isEmpty() || m_editor->lineEdit()->text() == m_editor->lineEdit()->selectedText();
	else
		return false;
}

void Basket::selectionChangedInEditor()
{
	Global::bnpView->notesStateChanged();
}

void Basket::contentChangedInEditor()
{
	// Do not wait 3 seconds, because we need the note to expand as needed (if a line is too wider... the note should grow wider):
	if (m_editor->textEdit())
		m_editor->autoSave(/*toFileToo=*/false);
//	else {
		if (m_inactivityAutoSaveTimer.isActive())
			m_inactivityAutoSaveTimer.stop();
		m_inactivityAutoSaveTimer.start(3 * 1000, /*singleShot=*/true);
		Global::bnpView->setUnsavedStatus(true);
//	}
}

void Basket::inactivityAutoSaveTimeout()
{
	if (m_editor)
		m_editor->autoSave(/*toFileToo=*/true);
}

void Basket::placeEditorAndEnsureVisible()
{
	placeEditor(/*andEnsureVisible=*/true);
}

void Basket::placeEditor(bool /*andEnsureVisible*/ /*= false*/)
{
	if (!isDuringEdit())
		return;

	TQFrame    *editorTQFrame = dynamic_cast<TQFrame*>(m_editor->widget());
	KTextEdit *textEdit     = m_editor->textEdit();
//	TQLineEdit *lineEdit     = m_editor->lineEdit();
	Note      *note         = m_editor->note();

	int frameWidth = (editorTQFrame ? editorTQFrame->frameWidth() : 0);
	int x          = note->x() + note->contentX() + note->content()->xEditorIndent() - frameWidth;
	int y;
	int maxHeight  = TQMAX(visibleHeight(), contentsHeight());
	int height, width;

	if (textEdit) {
		x -= 4;
		// Need to do it 2 times, because it's wrong overwise
		// (sometimes, width depends on height, and sometimes, height depends on with):
		for (int i = 0; i < 2; i++) {
			// FIXME: CRASH: Select all text, press Del or [<--] and editor->removeSelectedText() is called:
			//        editor->sync() CRASH!!
	//		editor->sync();
			y = note->y() + Note::NOTE_MARGIN - frameWidth;
			height = textEdit->contentsHeight() + 2*frameWidth;
//			height = /*TQMAX(*/height/*, note->height())*/;
//			height = TQMIN(height, visibleHeight());
			width  = note->x() + note->width() - x + 1;//      /*note->x() + note->width()*/note->rightLimit() - x + 2*frameWidth + 1;
//width=TQMAX(width,textEdit->contentsWidth()+2*frameWidth);
			if (y + height > maxHeight)
				y = maxHeight - height;
			textEdit->setFixedSize(width, height);
		}
	} else {
		height = note->height() - 2*Note::NOTE_MARGIN + 2*frameWidth;
		width  = note->x() + note->width() - x;//note->rightLimit() - x + 2*frameWidth;
		m_editor->widget()->setFixedSize(width, height);
		x -= 1;
		y = note->y() + Note::NOTE_MARGIN - frameWidth;
	}
	if ((m_editorWidth > 0 && m_editorWidth != width) || (m_editorHeight > 0 && m_editorHeight != height)) {
		m_editorWidth  = width; // Avoid infinite recursion!!!
		m_editorHeight = height;
		m_editor->autoSave(/*toFileToo=*/true);
	}
	m_editorWidth  = width;
	m_editorHeight = height;
	addChild(m_editor->widget(), x, y);
	m_editorX = x;
	m_editorY = y;

	m_leftEditorBorder->setFixedSize( (m_editor->textEdit() ? 3 : 0), height);
//	m_leftEditorBorder->raise();
	addChild(m_leftEditorBorder,     x, y );
	m_leftEditorBorder->setPosition( x, y );

	m_rightEditorBorder->setFixedSize(3, height);
//	m_rightEditorBorder->raise();
//	addChild(m_rightEditorBorder,     note->rightLimit() - Note::NOTE_MARGIN, note->y() + Note::NOTE_MARGIN );
//	m_rightEditorBorder->setPosition( note->rightLimit() - Note::NOTE_MARGIN, note->y() + Note::NOTE_MARGIN );
	addChild(m_rightEditorBorder,     note->x() + note->width() - Note::NOTE_MARGIN, note->y() + Note::NOTE_MARGIN );
	m_rightEditorBorder->setPosition( note->x() + note->width() - Note::NOTE_MARGIN, note->y() + Note::NOTE_MARGIN );

//	if (andEnsureVisible)
//		ensureNoteVisible(note);
}

#include <iostream>
#include <tqrichtext_p.h>
void Basket::editorCursorPositionChanged()
{
	if (!isDuringEdit())
		return;

	FocusedTextEdit *textEdit = (FocusedTextEdit*) m_editor->textEdit();
	const TQTextCursor *cursor = textEdit->textCursor();
//	std::cout << cursor->x() << ";" << cursor->y() << "      "
//			  << cursor->globalX() << ";" << cursor->globalY() << "          "
//			  << cursor->offsetX() << ";" << cursor->offsetY() << ";" << std::endl;

	ensureVisible(m_editorX + cursor->globalX(), m_editorY + cursor->globalY(), 50, 50);
}

void Basket::closeEditorDelayed()
{
	setFocus();
	TQTimer::singleShot( 0, this, TQ_SLOT(closeEditor()) );
}

bool Basket::closeEditor()
{
	if (!isDuringEdit())
		return true;

	if (m_doNotCloseEditor)
		return true;

	if (m_redirectEditActions) {
		disconnect( m_editor->widget(), TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(selectionChangedInEditor()) );
		if (m_editor->textEdit()) {
			disconnect( m_editor->textEdit(), TQ_SIGNAL(textChanged()),               this, TQ_SLOT(selectionChangedInEditor()) );
			disconnect( m_editor->textEdit(), TQ_SIGNAL(textChanged()),               this, TQ_SLOT(contentChangedInEditor())   );
		} else if (m_editor->lineEdit()) {
			disconnect( m_editor->lineEdit(), TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(selectionChangedInEditor()) );
			disconnect( m_editor->lineEdit(), TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(contentChangedInEditor())   );
		}
	}
	m_editor->widget()->disconnect();
	m_editor->widget()->hide();
	m_editor->validate();

	delete m_leftEditorBorder;
	delete m_rightEditorBorder;
	m_leftEditorBorder  = 0;
	m_rightEditorBorder = 0;

	Note *note = m_editor->note();
	note->setWidth(0); // For relayoutNotes() to succeed to take care of the change

	// Delete the editor BEFORE unselecting the note because unselecting the note would trigger closeEditor() recursivly:
	bool isEmpty = m_editor->isEmpty();
	delete m_editor;
	m_editor = 0;
	m_redirectEditActions = false;
	m_editorWidth  = -1;
	m_editorHeight = -1;
	m_inactivityAutoSaveTimer.stop();

	// Delete the note if it is now empty:
	if (isEmpty) {
		focusANonSelectedNoteAboveOrThenBelow();
		note->setSelected(true);
		note->deleteSelectedNotes();
		save();
		note = 0;
	}

	unlockHovering();
	filterAgain(/*andEnsureVisible=*/false);

// Does not work:
//	if (Settings::playAnimations())
//		note->setOnTop(true); // So if it grew, do not obscure it temporarily while the notes below it are moving

	if (note)
		note->setSelected(false);//unselectAll();
	doHoverEffects();
//	save();

	Global::bnpView->m_actEditNote->setEnabled( !isLocked() && countSelecteds() == 1 /*&& !isDuringEdit()*/ );

	emit resetStatusBarText(); // Remove the "Editing. ... to validate." text.

	//if (kapp->activeWindow() == Global::mainContainer)

	// Set focus to the basket, unless the user pressed a letter key in the filter bar and the currently edited note came hidden, then editing closed:
	if (!decoration()->filterBar()->lineEdit()->hasFocus())
		setFocus();

	// Return true if the note is still there:
	return (note != 0);
}

void Basket::closeBasket()
{
  closeEditor();
  unbufferizeAll(); // Keep the memory footprint low
  if (isEncrypted()) {
	if (Settings::enableReLockTimeout()) {
	  int seconds = Settings::reLockTimeoutMinutes() * 60;
	  m_inactivityAutoLockTimer.start(seconds * 1000, /*singleShot=*/true);
	}
  }
}

void Basket::openBasket()
{
        if (m_inactivityAutoLockTimer.isActive())
                m_inactivityAutoLockTimer.stop();
}

Note* Basket::theSelectedNote()
{
	if (countSelecteds() != 1) {
		std::cout << "NO SELECTED NOTE !!!!" << std::endl;
		return 0;
	}

	Note *selectedOne;
	FOR_EACH_NOTE (note) {
		selectedOne = note->theSelectedNote();
		if (selectedOne)
			return selectedOne;
	}

	std::cout << "One selected note, BUT NOT FOUND !!!!" << std::endl;

	return 0;
}

void debugSel(NoteSelection* sel, int n = 0)
{
	for (NoteSelection *node = sel; node; node = node->next) {
		for (int i = 0; i < n; i++)
			std::cout << "-";
		std::cout << (node->firstChild ? "Group" : node->note->content()->toText("").local8Bit()) << std::endl;
		if (node->firstChild)
			debugSel(node->firstChild, n+1);
	}
}

NoteSelection* Basket::selectedNotes()
{
	NoteSelection selection;

	FOR_EACH_NOTE (note)
		selection.append(note->selectedNotes());

	if (!selection.firstChild)
		return 0;

	for (NoteSelection *node = selection.firstChild; node; node = node->next)
		node->parent = 0;

	// If the top-most groups are columns, export only childs of those groups
	// (because user is not consciencious that columns are groups, and don't care: it's not what she want):
	if (selection.firstChild->note->isColumn()) {
		NoteSelection tmpSelection;
		NoteSelection *nextNode;
		NoteSelection *nextSubNode;
		for (NoteSelection *node = selection.firstChild; node; node = nextNode) {
			nextNode = node->next;
			if (node->note->isColumn()) {
				for (NoteSelection *subNode = node->firstChild; subNode; subNode = nextSubNode) {
					nextSubNode = subNode->next;
					tmpSelection.append(subNode);
					subNode->parent = 0;
					subNode->next = 0;
				}
			} else {
				tmpSelection.append(node);
				node->parent = 0;
				node->next = 0;
			}
		}
//		debugSel(tmpSelection.firstChild);
		return tmpSelection.firstChild;
	} else {
//		debugSel(selection.firstChild);
		return selection.firstChild;
	}
}

void Basket::showEditedNoteWhileFiltering()
{
	if (m_editor) {
		Note *note = m_editor->note();
		filterAgain();
		note->setSelected(true);
		relayoutNotes(false);
		note->setX(note->finalX());
		note->setY(note->finalY());
		filterAgainDelayed();
	}
}

void Basket::noteEdit(Note *note, bool justAdded, const TQPoint &clickedPoint) // TODO: Remove the first parameter!!!
{
	if (!note)
		note = theSelectedNote(); // TODO: Or pick the focused note!
	if (!note)
		return;

	if (isDuringEdit()) {
		closeEditor(); // Validate the noteeditors in KLineEdit that does not intercept Enter key press (and edit is triggered with Enter too... Can conflict)
		return;
	}

	if (note != m_focusedNote) {
		setFocusedNote(note);
		m_startOfShiftSelectionNote = note;
	}

	if (justAdded && isFiltering()) {
		TQTimer::singleShot( 0, this, TQ_SLOT(showEditedNoteWhileFiltering()) );
	}

	doHoverEffects(note, Note::Content); // Be sure (in the case Edit was triggered by menu or Enter key...): better feedback!
	//m_lockedHovering = true;

	//m_editorWidget = note->content()->launchEdit(this);
	NoteEditor *editor = NoteEditor::editNoteContent(note->content(), this);

	if (editor->widget()) {
		m_editor = editor;
		m_leftEditorBorder  = new TransparentWidget(this);
		m_rightEditorBorder = new TransparentWidget(this);
		m_editor->widget()->reparent(viewport(), TQPoint(0,0), true);
		m_leftEditorBorder->reparent(viewport(), TQPoint(0,0), true);
		m_rightEditorBorder->reparent(viewport(), TQPoint(0,0), true);
		addChild(m_editor->widget(), 0, 0);
		placeEditorAndEnsureVisible(); //       placeEditor(); // FIXME: After?
		m_redirectEditActions = m_editor->lineEdit() || m_editor->textEdit();
		if (m_redirectEditActions) {
			connect( m_editor->widget(), TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(selectionChangedInEditor()) );
			// In case there is NO text, "Select All" is disabled. But if the user press a key the there is now a text:
			// selection has not changed but "Select All" should be re-enabled:
			if (m_editor->textEdit()) {
				connect( m_editor->textEdit(), TQ_SIGNAL(textChanged()),               this, TQ_SLOT(selectionChangedInEditor()) );
				connect( m_editor->textEdit(), TQ_SIGNAL(textChanged()),               this, TQ_SLOT(contentChangedInEditor())   );
			} else if (m_editor->lineEdit()) {
				connect( m_editor->lineEdit(), TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(selectionChangedInEditor()) );
				connect( m_editor->lineEdit(), TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(contentChangedInEditor())   );
			}
		}
		m_editor->widget()->show();
		//m_editor->widget()->raise();
		m_editor->widget()->setFocus();
		connect( m_editor, TQ_SIGNAL(askValidation()),            this, TQ_SLOT(closeEditorDelayed())       );
		connect( m_editor, TQ_SIGNAL(mouseEnteredEditorWidget()), this, TQ_SLOT(mouseEnteredEditorWidget()) );
		if (m_editor->textEdit()) {
			connect( m_editor->textEdit(), TQ_SIGNAL(textChanged()), this, TQ_SLOT(placeEditorAndEnsureVisible()) );
			if (clickedPoint != TQPoint()) {
				TQPoint pos(clickedPoint.x() - note->x() - note->contentX() + m_editor->textEdit()->frameWidth() + 4   - m_editor->textEdit()->frameWidth(),
				           clickedPoint.y() - note->y()   - m_editor->textEdit()->frameWidth());
				// Do it right before the kapp->processEvents() to not have the cursor to quickly flicker at end (and sometimes stay at end AND where clicked):
				m_editor->textEdit()->moveCursor(KTextEdit::MoveHome, false);
				m_editor->textEdit()->ensureCursorVisible();
				m_editor->textEdit()->placeCursor(pos);
				updateEditorAppearance();
			}
		}
//		kapp->processEvents();     // Show the editor toolbar before ensuring the note is visible
		ensureNoteVisible(note);   //  because toolbar can create a new line and then partially hide the note
		m_editor->widget()->setFocus(); // When clicking in the basket, a TQTimer::singleShot(0, ...) focus the basket! So we focus the the widget after kapp->processEvents()
		emit resetStatusBarText(); // Display "Editing. ... to validate."
	} else {
		// Delete the note user have canceled the addition:
		if ((justAdded && editor->canceled()) || editor->isEmpty() /*) && editor->note()->states().count() <= 0*/) {
			focusANonSelectedNoteAboveOrThenBelow();
			editor->note()->setSelected(true);
			editor->note()->deleteSelectedNotes();
			save();
		}
		delete editor;
		unlockHovering();
		filterAgain();
		unselectAll();
	}
	Global::bnpView->m_actEditNote->setEnabled(false);
}

void Basket::noteDelete()
{
	if (redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->del();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->del();
		return;
	}

	if (countSelecteds() <= 0)
		return;
	int really = KMessageBox::Yes;
	if (Settings::confirmNoteDeletion())
		really = KMessageBox::questionYesNo( this,
			i18n("<qt>Do you really want to delete this note?</qt>",
			     "<qt>Do you really want to delete those <b>%n</b> notes?</qt>",
			     countSelecteds()),
			i18n("Delete Note", "Delete Notes", countSelecteds()),
			KStdGuiItem::del(), KStdGuiItem::cancel());
	if (really == KMessageBox::No)
		return;

	noteDeleteWithoutConfirmation();
}

void Basket::focusANonSelectedNoteBelow(bool inSameColumn)
{
	// First focus another unselected one below it...:
	if (m_focusedNote && m_focusedNote->isSelected()) {
		Note *next = m_focusedNote->nextShownInStack();
		while (next && next->isSelected())
			next = next->nextShownInStack();
		if (next) {
			if (inSameColumn && isColumnsLayout() && m_focusedNote->parentPrimaryNote() == next->parentPrimaryNote()) {
				setFocusedNote(next);
				m_startOfShiftSelectionNote = next;
			}
		}
	}
}

void Basket::focusANonSelectedNoteAbove(bool inSameColumn)
{
	// ... Or above it:
	if (m_focusedNote && m_focusedNote->isSelected()) {
		Note *prev = m_focusedNote->prevShownInStack();
		while (prev && prev->isSelected())
			prev = prev->prevShownInStack();
		if (prev) {
			if (inSameColumn && isColumnsLayout() && m_focusedNote->parentPrimaryNote() == prev->parentPrimaryNote()) {
				setFocusedNote(prev);
				m_startOfShiftSelectionNote = prev;
			}
		}
	}
}

void Basket::focusANonSelectedNoteBelowOrThenAbove()
{
	focusANonSelectedNoteBelow(/*inSameColumn=*/true);
	focusANonSelectedNoteAbove(/*inSameColumn=*/true);
	focusANonSelectedNoteBelow(/*inSameColumn=*/false);
	focusANonSelectedNoteAbove(/*inSameColumn=*/false);
}

void Basket::focusANonSelectedNoteAboveOrThenBelow()
{
	focusANonSelectedNoteAbove(/*inSameColumn=*/true);
	focusANonSelectedNoteBelow(/*inSameColumn=*/true);
	focusANonSelectedNoteAbove(/*inSameColumn=*/false);
	focusANonSelectedNoteBelow(/*inSameColumn=*/false);
}

void Basket::noteDeleteWithoutConfirmation(bool deleteFilesToo)
{
	// If the currently focused note is selected, it will be deleted.
	focusANonSelectedNoteBelowOrThenAbove();

	// Do the deletion:
	Note *note = firstNote();
	Note *next;
	while (note) {
		next = note->next(); // If we delete 'note' on the next line, note->next() will be 0!
		note->deleteSelectedNotes(deleteFilesToo);
		note = next;
	}

	relayoutNotes(true); // FIXME: filterAgain()?
	save();
}

void Basket::doCopy(CopyMode copyMode)
{
	TQClipboard *cb = TDEApplication::clipboard();
	TQClipboard::Mode mode = (copyMode == CopyToSelection ? TQClipboard::Selection : TQClipboard::Clipboard);

	NoteSelection *selection = selectedNotes();
	int countCopied = countSelecteds();
	if (selection && selection->firstStacked()) {
		TQDragObject *d = NoteDrag::dragObject(selection, copyMode == CutToClipboard, /*source=*/0); // d will be deleted by TQt
//		/*bool shouldRemove = */d->drag();
//		delete selection;
		cb->setData(d, mode); // NoteMultipleDrag will be deleted by TQt
//		if (copyMode == CutToClipboard && !note->useFile()) // If useFile(), NoteDrag::dragObject() will delete it TODO
//			note->slotDelete();

		if (copyMode == CutToClipboard)
			noteDeleteWithoutConfirmation(/*deleteFilesToo=*/false);

		switch (copyMode) {
			default:
			case CopyToClipboard: emit postMessage(i18n("Copied note to clipboard.", "Copied notes to clipboard.", countCopied)); break;
			case CutToClipboard:  emit postMessage(i18n("Cut note to clipboard.",    "Cut notes to clipboard.",    countCopied)); break;
			case CopyToSelection: emit postMessage(i18n("Copied note to selection.", "Copied notes to selection.", countCopied)); break;
		}
	}
}

void Basket::noteCopy()
{
	if (redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->copy();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->copy();
	} else
		doCopy(CopyToClipboard);
}

void Basket::noteCut()
{
	if (redirectEditActions()) {
		if (m_editor->textEdit())
			m_editor->textEdit()->cut();
		else if (m_editor->lineEdit())
			m_editor->lineEdit()->cut();
	} else
		doCopy(CutToClipboard);
}

void Basket::noteOpen(Note *note)
{
	/*
	GetSelectedNotes
	NoSelectedNote || Count == 0 ? return
	AllTheSameType ?
	Get { url, message(count) }
	*/

	// TODO: Open ALL selected notes!
	if (!note)
		note = theSelectedNote();
	if (!note)
		return;

	KURL    url     = note->content()->urlToOpen(/*with=*/false);
	TQString message = note->content()->messageWhenOpenning(NoteContent::OpenOne /*NoteContent::OpenSeveral*/);
	if (url.isEmpty()) {
		if (message.isEmpty())
			emit postMessage(i18n("Unable to open this note.") /*"Unable to open those notes."*/);
		else {
			int result = KMessageBox::warningContinueCancel(this, message, /*caption=*/TQString(), KGuiItem(i18n("&Edit"), "edit"));
			if (result == KMessageBox::Continue)
				noteEdit(note);
		}
	} else {
		emit postMessage(message); // "Openning link target..." / "Launching application..." / "Openning note file..."
		// Finally do the opening job:
		TQString customCommand = note->content()->customOpenCommand();
		if (customCommand.isEmpty()) {
			KRun *run = new KRun(url);
			run->setAutoDelete(true);
		} else
			KRun::run(customCommand, url);
	}
}

/** Code from bool KRun::displayOpenWithDialog(const KURL::List& lst, bool tempFiles)
  * It does not allow to set a text, so I ripped it to do that:
  */
bool KRun__displayOpenWithDialog(const KURL::List& lst, bool tempFiles, const TQString &text)
{
	if (kapp && !kapp->authorizeTDEAction("openwith")) {
		KMessageBox::sorry(0L, i18n("You are not authorized to open this file.")); // TODO: Better message, i18n freeze :-(
		return false;
	}
	KOpenWithDlg l(lst, text, TQString(), 0L);
	if (l.exec()) {
		KService::Ptr service = l.service();
		if (!!service)
			return KRun::run(*service, lst, tempFiles);
		//kdDebug(250) << "No service set, running " << l.text() << endl;
		return KRun::run(l.text(), lst); // TODO handle tempFiles
	}
	return false;
}

void Basket::noteOpenWith(Note *note)
{
	if (!note)
		note = theSelectedNote();
	if (!note)
		return;

	KURL    url     = note->content()->urlToOpen(/*with=*/true);
	TQString message = note->content()->messageWhenOpenning(NoteContent::OpenOneWith /*NoteContent::OpenSeveralWith*/);
	TQString text    = note->content()->messageWhenOpenning(NoteContent::OpenOneWithDialog /*NoteContent::OpenSeveralWithDialog*/);
	if (url.isEmpty())
		emit postMessage(i18n("Unable to open this note.") /*"Unable to open those notes."*/);
	else if (KRun__displayOpenWithDialog(url, false, text))
		emit postMessage(message); // "Openning link target with..." / "Openning note file with..."
}

void Basket::noteSaveAs()
{
//	if (!note)
//		note = theSelectedNote();
	Note *note = theSelectedNote();
	if (!note)
		return;

	KURL url = note->content()->urlToOpen(/*with=*/false);
	if (url.isEmpty())
		return;

	TQString fileName = KFileDialog::getSaveFileName(url.fileName(), note->content()->saveAsFilters(), this, i18n("Save to File"));
	// TODO: Ask to overwrite !
	if (fileName.isEmpty())
		return;

	// TODO: Convert format, etc. (use NoteContent::saveAs(fileName))
	TDEIO::copy(url, KURL(fileName));
}

Note* Basket::selectedGroup()
{
	FOR_EACH_NOTE (note) {
		Note *selectedGroup = note->selectedGroup();
		if (selectedGroup) {
			// If the selected group is one group in a column, then return that group, and not the column,
			// because the column is not ungrouppage, and the Ungroup action would be disabled.
			if (selectedGroup->isColumn() && selectedGroup->firstChild() && !selectedGroup->firstChild()->next()) {
				return selectedGroup->firstChild();
			}
			return selectedGroup;
		}
	}
	return 0;
}

bool Basket::selectionIsOneGroup()
{
	return (selectedGroup() != 0);
}

Note* Basket::firstSelected()
{
	Note *first = 0;
	FOR_EACH_NOTE (note) {
		first = note->firstSelected();
		if (first)
			return first;
	}
	return 0;
}

Note* Basket::lastSelected()
{
	Note *last = 0, *tmp = 0;
	FOR_EACH_NOTE (note) {
		tmp = note->lastSelected();
		if (tmp)
			last = tmp;
	}
	return last;
}

bool Basket::convertTexts()
{
	m_watcher->stopScan();
	bool convertedNotes = false;

	if (!isLoaded())
		load();

	FOR_EACH_NOTE (note)
		if (note->convertTexts())
			convertedNotes = true;

	if (convertedNotes)
		save();
	m_watcher->startScan();
	return convertedNotes;
}

void Basket::noteGroup()
{
/*	// Nothing to do?
	if (isLocked() || countSelecteds() <= 1)
		return;

	// If every selected notes are ALREADY in one group, then don't touch anything:
	Note *selectedGroup = this->selectedGroup();
	if (selectedGroup && !selectedGroup->isColumn())
		return;
*/

	// Copied from BNPView::updateNotesActions()
	bool severalSelected = countSelecteds() >= 2;
	Note *selectedGroup = (severalSelected ? this->selectedGroup() : 0);
	bool enabled = !isLocked() && severalSelected && (!selectedGroup || selectedGroup->isColumn());
	if (!enabled)
		return;

	// Get the first selected note: we will group selected items just before:
	Note *first = firstSelected();
//	if (selectedGroup != 0 || first == 0)
//		return;

	m_loaded = false; // Hack to avoid notes to be unselected and new notes to be selected:

	// Create and insert the receiving group:
	Note *group = new Note(this);
	if (first->isFree()) {
		insertNote(group, 0L, Note::BottomColumn, TQPoint(first->finalX(), first->finalY()), /*animateNewPosition=*/false);
	} else {
		insertNote(group, first, Note::TopInsert, TQPoint(), /*animateNewPosition=*/false);
	}

	// Put a FAKE UNSELECTED note in the new group, so if the new group is inside an allSelected() group, the parent group is not moved inside the new group!
	Note *fakeNote = NoteFactory::createNoteColor(TQt::red, this);
	insertNote(fakeNote, group, Note::BottomColumn, TQPoint(), /*animateNewPosition=*/false);

	// Group the notes:
	Note *nextNote;
	Note *note = firstNote();
	while (note) {
		nextNote = note->next();
		note->groupIn(group);
		note = nextNote;
	}

	m_loaded = true; // Part 2 / 2 of the workarround!

	// Do cleanup:
	unplugNote(fakeNote);
	unselectAll();
	group->setSelectedRecursivly(true); // Notes were unselected by unplugging

	relayoutNotes(true);
	save();
}

void Basket::noteUngroup()
{
	Note *group = selectedGroup();
	if (group && !group->isColumn())
		ungroupNote(group);
	save();
}

void Basket::unplugSelection(NoteSelection *selection)
{
	if (!selection)
	{
		return;
	}
	for (NoteSelection *toUnplug = selection->firstStacked(); toUnplug; toUnplug = toUnplug->nextStacked())
		unplugNote(toUnplug->note);
}

void Basket::insertSelection(NoteSelection *selection, Note *after)
{
	if (!selection)
	{
		return;
	}
	for (NoteSelection *toUnplug = selection->firstStacked(); toUnplug; toUnplug = toUnplug->nextStacked()) {
		if (toUnplug->note->isGroup()) {
			Note *group = new Note(this);
			insertNote(group, after, Note::BottomInsert, TQPoint(), /*animateNewPosition=*/false);
			Note *fakeNote = NoteFactory::createNoteColor(TQt::red, this);
			insertNote(fakeNote, group, Note::BottomColumn, TQPoint(), /*animateNewPosition=*/false);
			insertSelection(toUnplug->firstChild, fakeNote);
			unplugNote(fakeNote);
			after = group;
		} else {
			Note *note = toUnplug->note;
			note->setPrev(0);
			note->setNext(0);
			insertNote(note, after, Note::BottomInsert, TQPoint(), /*animateNewPosition=*/true);
			after = note;
		}
	}
}

void Basket::selectSelection(NoteSelection *selection)
{
	if (!selection)
	{
		return;
	}
	for (NoteSelection *toUnplug = selection->firstStacked(); toUnplug; toUnplug = toUnplug->nextStacked()) {
		if (toUnplug->note->isGroup())
			selectSelection(toUnplug);
		else
			toUnplug->note->setSelected(true);
	}
}

void Basket::noteMoveOnTop()
{
	// TODO: Get the group containing the selected notes and first move inside the group, then inside parent group, then in the basket
	// TODO: Move on top/bottom... of the column or basjet

	NoteSelection *selection = selectedNotes();
	unplugSelection(selection);
	// Replug the notes:
	Note *fakeNote = NoteFactory::createNoteColor(TQt::red, this);
	if (isColumnsLayout()) {
		if (firstNote()->firstChild())
			insertNote(fakeNote, firstNote()->firstChild(), Note::TopInsert, TQPoint(), /*animateNewPosition=*/false);
		else
			insertNote(fakeNote, firstNote(), Note::BottomColumn, TQPoint(), /*animateNewPosition=*/false);
	} else {
		// TODO: Also allow to move notes on top of a group!!!!!!!
		insertNote(fakeNote, 0, Note::BottomInsert, TQPoint(0, 0), /*animateNewPosition=*/false);
	}
	insertSelection(selection, fakeNote);
	unplugNote(fakeNote);
	selectSelection(selection);
	relayoutNotes(true);
	save();
}

void Basket::noteMoveOnBottom()
{

	// TODO: Duplicate code: void noteMoveOn();

	// TODO: Get the group containing the selected notes and first move inside the group, then inside parent group, then in the basket
	// TODO: Move on top/bottom... of the column or basjet

	NoteSelection *selection = selectedNotes();
	unplugSelection(selection);
	// Replug the notes:
	Note *fakeNote = NoteFactory::createNoteColor(TQt::red, this);
	if (isColumnsLayout())
		insertNote(fakeNote, firstNote(), Note::BottomColumn, TQPoint(), /*animateNewPosition=*/false);
	else {
		// TODO: Also allow to move notes on top of a group!!!!!!!
		insertNote(fakeNote, 0, Note::BottomInsert, TQPoint(0, 0), /*animateNewPosition=*/false);
	}
	insertSelection(selection, fakeNote);
	unplugNote(fakeNote);
	selectSelection(selection);
	relayoutNotes(true);
	save();
}

void Basket::moveSelectionTo(Note *here, bool below/* = true*/)
{
	NoteSelection *selection = selectedNotes();
	unplugSelection(selection);
	// Replug the notes:
	Note *fakeNote = NoteFactory::createNoteColor(TQt::red, this);
//	if (isColumnsLayout())
		insertNote(fakeNote, here, (below ? Note::BottomInsert : Note::TopInsert), TQPoint(), /*animateNewPosition=*/false);
//	else {
//		// TODO: Also allow to move notes on top of a group!!!!!!!
//		insertNote(fakeNote, 0, Note::BottomInsert, TQPoint(0, 0), /*animateNewPosition=*/false);
//	}
	insertSelection(selection, fakeNote);
	unplugNote(fakeNote);
	selectSelection(selection);
	relayoutNotes(true);
	save();
}

void Basket::noteMoveNoteUp()
{

	// TODO: Move between columns, even if they are empty !!!!!!!

	// TODO: if first note of a group, move just above the group! And let that even if there is no note before that group!!!

	Note *first    = firstSelected();
	Note *previous = first->prevShownInStack();
	if (previous)
		moveSelectionTo(previous, /*below=*/false);
}

void Basket::noteMoveNoteDown()
{
	Note *first = lastSelected();
	Note *next  = first->nextShownInStack();
	if (next)
		moveSelectionTo(next, /*below=*/true);
}

void Basket::wheelEvent(TQWheelEvent *event)
{
	TQScrollView::wheelEvent(event);
}

void Basket::linkLookChanged()
{
	Note *note = m_firstNote;
	while (note) {
		note->linkLookChanged();
		note = note->next();
	}
	relayoutNotes(true);
}

void Basket::slotCopyingDone2(TDEIO::Job *job)
{
	if (job->error()) {
		DEBUG_WIN << "Copy finished, ERROR";
		return;
	}
	TDEIO::FileCopyJob *fileCopyJob = (TDEIO::FileCopyJob*)job;
	Note *note = noteForFullPath(fileCopyJob->destURL().path());
	DEBUG_WIN << "Copy finished, load note: " + fileCopyJob->destURL().path() + (note ? "" : " --- NO CORRESPONDING NOTE");
	if (note != 0L) {
		note->content()->loadFromFile(/*lazyLoad=*/false);
		if(isEncrypted())
			note->content()->saveToFile();
		if (m_focusedNote == note)   // When inserting a new note we ensure it visble
			ensureNoteVisible(note); //  But after loading it has certainly grown and if it was
	}                                //  on bottom of the basket it's not visible entirly anymore
}

Note* Basket::noteForFullPath(const TQString &path)
{
	Note *note = firstNote();
	Note *found;
	while (note) {
		found = note->noteForFullPath(path);
		if (found)
			return found;
		note = note->next();
	}
	return 0;
}

void Basket::deleteFiles()
{
	m_watcher->stopScan();
	Tools::deleteRecursively(fullPath());
}

TQValueList<State*> Basket::usedStates()
{
	TQValueList<State*> states;
	FOR_EACH_NOTE (note)
		note->usedStates(states);
	return states;
}

TQString Basket::saveGradientBackground(const TQColor &color, const TQFont &font, const TQString &folder)
{
	// Construct file name and return if the file already exists:
	TQString fileName = "note_background_" + TQString(color.name()).lower().mid(1) + ".png";
	TQString fullPath = folder + fileName;
	if (TQFile::exists(fullPath))
		return fileName;

	// Get the gradient top and bottom colors:
	TQColor topBgColor;
	TQColor bottomBgColor;
	Note::getGradientColors(color, &topBgColor, &bottomBgColor);

	// Draw and save the gradient image:
	int sampleTextHeight = TQFontMetrics(font)
	                       .boundingRect(0, 0, /*width=*/10000, /*height=*/0, TQt::AlignAuto | TQt::AlignTop | TQt::WordBreak, "Test text")
	                       .height();
	TQPixmap noteGradient(100, sampleTextHeight + Note::NOTE_MARGIN);
	TQPainter painter(&noteGradient);
	drawGradient(&painter, topBgColor, bottomBgColor, 0, 0, noteGradient.width(), noteGradient.height(), /*sunken=*/false, /*horz=*/true, /*flat=*/false);
	painter.end();
	noteGradient.save(fullPath, "PNG");

	// Return the name of the created file:
	return fileName;
}

void Basket::listUsedTags(TQValueList<Tag*> &list)
{
	if (!isLoaded()) {
		load();
	}

	FOR_EACH_NOTE (child)
		child->listUsedTags(list);
}


/** Unfocus the previously focused note (unless it was null)
  * and focus the new @param note (unless it is null) if hasFocus()
  * Update m_focusedNote to the new one
  */
void Basket::setFocusedNote(Note *note) // void Basket::changeFocusTo(Note *note)
{
	// Don't focus an hidden note:
	if (note != 0L && !note->isShown())
		return;
	// When clicking a group, this group gets focused. But only content-based notes should be focused:
	if (note && note->isGroup())
		note = note->firstRealChild();
	// The first time a note is focused, it becomes the start of the Shift selection:
	if (m_startOfShiftSelectionNote == 0)
		m_startOfShiftSelectionNote = note;
	// Unfocus the old focused note:
	if (m_focusedNote != 0L)
		m_focusedNote->setFocused(false);
	// Notify the new one to draw a focus rectangle... only if the basket is focused:
	if (hasFocus() && note != 0L)
		note->setFocused(true);
	// Save the new focused note:
	m_focusedNote = note;
}

/** If no shown note is currently focused, try to find a shown note and focus it
  * Also update m_focusedNote to the new one (or null if there isn't)
  */
void Basket::focusANote()
{
	if (countFounds() == 0) { // No note to focus
		setFocusedNote(0L);
//		m_startOfShiftSelectionNote = 0;
		return;
	}

	if (m_focusedNote == 0L) { // No focused note yet : focus the first shown
		Note *toFocus = (isFreeLayout() ? noteOnHome() : firstNoteShownInStack());
		setFocusedNote(toFocus);
//		m_startOfShiftSelectionNote = m_focusedNote;
		return;
	}

	// Search a visible note to focus if the focused one isn't shown :
	Note *toFocus = m_focusedNote;
	if (toFocus && !toFocus->isShown())
		toFocus = toFocus->nextShownInStack();
	if (!toFocus && m_focusedNote)
		toFocus = m_focusedNote->prevShownInStack();
	setFocusedNote(toFocus);
//	m_startOfShiftSelectionNote = toFocus;
}

Note* Basket::firstNoteInStack()
{
	if (!firstNote())
		return 0;

	if (firstNote()->content())
		return firstNote();
	else
		return firstNote()->nextInStack();
}

Note* Basket::lastNoteInStack()
{
	Note *note = lastNote();
	while (note) {
		if (note->content())
			return note;
		Note *possibleNote = note->lastRealChild();
		if (possibleNote && possibleNote->content())
			return possibleNote;
		note = note->prev();
	}
	return 0;
}

Note* Basket::firstNoteShownInStack()
{
	Note *first = firstNoteInStack();
	while (first && !first->isShown())
		first = first->nextInStack();
	return first;
}

Note* Basket::lastNoteShownInStack()
{
	Note *last = lastNoteInStack();
	while (last && !last->isShown())
		last = last->prevInStack();
	return last;
}

inline int abs(int n)
{
	return (n < 0 ? -n : n);
}

Note* Basket::noteOn(NoteOn side)
{
	Note *bestNote = 0;
	int   distance = -1;
	int   bestDistance = contentsWidth() * contentsHeight() * 10;

	Note *note    = firstNoteShownInStack();
	Note *primary = m_focusedNote->parentPrimaryNote();
	while (note) {
		switch (side) {
			case LEFT_SIDE:   distance = m_focusedNote->distanceOnLeftRight(note, LEFT_SIDE);   break;
			case RIGHT_SIDE:  distance = m_focusedNote->distanceOnLeftRight(note, RIGHT_SIDE);  break;
			case TOP_SIDE:    distance = m_focusedNote->distanceOnTopBottom(note, TOP_SIDE);    break;
			case BOTTOM_SIDE: distance = m_focusedNote->distanceOnTopBottom(note, BOTTOM_SIDE); break;
		}
		if ((side == TOP_SIDE || side == BOTTOM_SIDE || primary != note->parentPrimaryNote()) && note != m_focusedNote && distance > 0 && distance < bestDistance) {
			bestNote     = note;
			bestDistance = distance;
		}
		note = note ->nextShownInStack();
	}

	return bestNote;
}

Note* Basket::firstNoteInGroup()
{
	Note *child  = m_focusedNote;
	Note *parent = (m_focusedNote ? m_focusedNote->parentNote() : 0);
	while (parent) {
		if (parent->firstChild() != child && !parent->isColumn())
			return parent->firstRealChild();
		child  = parent;
		parent = parent->parentNote();
	}
	return 0;
}

Note* Basket::noteOnHome()
{
	// First try to find the first note of the group containing the focused note:
	Note *child  = m_focusedNote;
	Note *parent = (m_focusedNote ? m_focusedNote->parentNote() : 0);
	while (parent) {
		if (parent->nextShownInStack() != m_focusedNote)
			return parent->nextShownInStack();
		child  = parent;
		parent = parent->parentNote();
	}

	// If it was not found, then focus the very first note in the basket:
	if (isFreeLayout()) {
		Note *first = firstNoteShownInStack(); // The effective first note found
		Note *note  = first; // The current note, to conpare with the previous first note, if this new note is more on top
		if (note)
			note = note->nextShownInStack();
		while (note) {
			if (note->finalY() < first->finalY() || (note->finalY() == first->finalY() && note->finalX() < first->finalX()))
				first = note;
			note = note->nextShownInStack();
		}
		return first;
	} else
		return firstNoteShownInStack();
}

Note* Basket::noteOnEnd()
{
	Note *child     = m_focusedNote;
	Note *parent    = (m_focusedNote ? m_focusedNote->parentNote() : 0);
	Note *lastChild;
	while (parent) {
		lastChild = parent->lastRealChild();
		if (lastChild && lastChild != m_focusedNote) {
			if (lastChild->isShown())
				return lastChild;
			lastChild = lastChild->prevShownInStack();
			if (lastChild && lastChild->isShown() && lastChild != m_focusedNote)
				return lastChild;
		}
		child  = parent;
		parent = parent->parentNote();
	}
	if (isFreeLayout()) {
		Note *last;
		Note *note;
		last = note = firstNoteShownInStack();
		note = note->nextShownInStack();
		while (note) {
			if (note->finalBottom() > last->finalBottom() || (note->finalBottom() == last->finalBottom() && note->finalX() > last->finalX()))
				last = note;
			note = note->nextShownInStack();
		}
		return last;
	} else
		return lastNoteShownInStack();
}


void Basket::keyPressEvent(TQKeyEvent *event)
{
	if (isDuringEdit() && event->key() == TQt::Key_Return) {
		//if (m_editor->lineEdit())
		//	closeEditor();
		//else
		m_editor->widget()->setFocus();
	} else if (event->key() == TQt::Key_Escape) {
		if (isDuringEdit())
			closeEditor();
		else if (decoration()->filterData().isFiltering)
			cancelFilter();
		else
			unselectAll();
	}

	if (countFounds() == 0)
		return;

	if (!m_focusedNote)
		return;

	Note *toFocus = 0L;

	switch (event->key()) {
		case TQt::Key_Down:
			toFocus = (isFreeLayout() ? noteOn(BOTTOM_SIDE) : m_focusedNote->nextShownInStack());
			if (toFocus)
				break;
			scrollBy(0, 30); // This cases do not move focus to another note...
			return;
		case TQt::Key_Up:
			toFocus = (isFreeLayout() ? noteOn(TOP_SIDE) : m_focusedNote->prevShownInStack());
			if (toFocus)
				break;
			scrollBy(0, -30); // This cases do not move focus to another note...
			return;
		case TQt::Key_PageDown:
			if (isFreeLayout()) {
				Note *lastFocused = m_focusedNote;
				for (int i = 0; i < 10 && m_focusedNote; ++i)
					m_focusedNote = noteOn(BOTTOM_SIDE);
				toFocus = m_focusedNote;
				m_focusedNote = lastFocused;
			} else {
				toFocus = m_focusedNote;
				for (int i = 0; i < 10 && toFocus; ++i)
					toFocus = toFocus->nextShownInStack();
			}
			if (toFocus == 0L)
				toFocus = (isFreeLayout() ? noteOnEnd() : lastNoteShownInStack());
			if (toFocus && toFocus != m_focusedNote)
				break;
			scrollBy(0, visibleHeight() / 2); // This cases do not move focus to another note...
			return;
		case TQt::Key_PageUp:
			if (isFreeLayout()) {
				Note *lastFocused = m_focusedNote;
				for (int i = 0; i < 10 && m_focusedNote; ++i)
					m_focusedNote = noteOn(TOP_SIDE);
				toFocus = m_focusedNote;
				m_focusedNote = lastFocused;
			} else {
				toFocus = m_focusedNote;
				for (int i = 0; i < 10 && toFocus; ++i)
					toFocus = toFocus->prevShownInStack();
			}
			if (toFocus == 0L)
				toFocus = (isFreeLayout() ? noteOnHome() : firstNoteShownInStack());
			if (toFocus && toFocus != m_focusedNote)
				break;
			scrollBy(0, - visibleHeight() / 2); // This cases do not move focus to another note...
			return;
		case TQt::Key_Home:
			toFocus = noteOnHome();
			break;
		case TQt::Key_End:
			toFocus = noteOnEnd();
			break;
		case TQt::Key_Left:
			if (m_focusedNote->tryFoldParent())
				return;
			if ( (toFocus = noteOn(LEFT_SIDE)) )
				break;
			if ( (toFocus = firstNoteInGroup()) )
				break;
			scrollBy(-30, 0); // This cases do not move focus to another note...
			return;
		case TQt::Key_Right:
			if (m_focusedNote->tryExpandParent())
				return;
			if ( (toFocus = noteOn(RIGHT_SIDE)) )
				break;
			scrollBy(30, 0); // This cases do not move focus to another note...
			return;
		case TQt::Key_Space:  // This case do not move focus to another note...
			if (m_focusedNote) {
				m_focusedNote->setSelected( ! m_focusedNote->isSelected() );
				event->accept();
			} else
				event->ignore();
			return;          // ... so we return after the process
		default:
			return;
	}

	if (toFocus == 0L) { // If no direction keys have been pressed OR reached out the begin or end
		event->ignore(); // Important !!
		return;
	}

	if (event->state() & TQt::ShiftButton) { // Shift+arrowKeys selection
		if (m_startOfShiftSelectionNote == 0L)
			m_startOfShiftSelectionNote = toFocus;
		ensureNoteVisible(toFocus); // Important: this line should be before the other ones because else repaint would be done on the wrong part!
		selectRange(m_startOfShiftSelectionNote, toFocus);
		setFocusedNote(toFocus);
		event->accept();
		return;
	} else /*if (toFocus != m_focusedNote)*/ {  // Move focus to ANOTHER note...
		ensureNoteVisible(toFocus); // Important: this line should be before the other ones because else repaint would be done on the wrong part!
		setFocusedNote(toFocus);
		m_startOfShiftSelectionNote = toFocus;
		if ( ! (event->state() & TQt::ControlButton) )       // ... select only current note if Control
			unselectAllBut(m_focusedNote);
		event->accept();
		return;
	}

	event->ignore(); // Important !!
}

/** Select a range of notes and deselect the others.
  * The order between start and end has no importance (end could be before start)
  */
void Basket::selectRange(Note *start, Note *end, bool unselectOthers /*= true*/)
{
	Note *cur;
	Note *realEnd = 0L;

	// Avoid crash when start (or end) is null
	if (start == 0L)
		start = end;
	else if (end == 0L)
		end = start;
	// And if *both* are null
	if (start == 0L) {
		if (unselectOthers)
			unselectAll();
		return;
	}
	// In case there is only one note to select
	if (start == end) {
		if (unselectOthers)
			unselectAllBut(start);
		else
			start->setSelected(true);
		return;
	}

	// Free layout baskets should select range as if we were drawing a rectangle between start and end:
	if (isFreeLayout()) {
		TQRect startRect( start->finalX(), start->finalY(), start->width(), start->finalHeight() );
		TQRect endRect(     end->finalX(),   end->finalY(),   end->width(),   end->finalHeight() );
		TQRect toSelect = startRect.unite(endRect);
		selectNotesIn(toSelect, /*invertSelection=*/false, unselectOthers);
		return;
	}

	// Search the REAL first (and deselect the others before it) :
	for (cur = firstNoteInStack(); cur != 0L; cur = cur->nextInStack()) {
		if (cur == start || cur == end)
			break;
		if (unselectOthers)
			cur->setSelected(false);
	}

	// Select the notes after REAL start, until REAL end :
	if (cur == start)
		realEnd = end;
	else if (cur == end)
		realEnd = start;

	for (/*cur = cur*/; cur != 0L; cur = cur->nextInStack()) {
		cur->setSelected(cur->isShown()); // Select all notes in the range, but only if they are shown
		if (cur == realEnd)
			break;
	}

	if (!unselectOthers)
		return;

	// Deselect the remaining notes :
	if (cur)
		cur = cur->nextInStack();
	for (/*cur = cur*/; cur != 0L; cur = cur->nextInStack())
		cur->setSelected(false);
}

void Basket::focusInEvent(TQFocusEvent*)
{
	// Focus cannot be get with Tab when locked, but a click can focus the basket!
	if (isLocked()) {
		if (m_button)
			TQTimer::singleShot( 0, m_button, TQ_SLOT(setFocus()) );
	} else
		focusANote();      // hasFocus() is true at this stage, note will be focused
}

void Basket::focusOutEvent(TQFocusEvent*)
{
	if (m_focusedNote != 0L)
		m_focusedNote->setFocused(false);
}

void Basket::ensureNoteVisible(Note *note)
{
	if (!note->isShown()) // Logical!
		return;

	if (note == editedNote()) // HACK: When filtering while editing big notes, etc... cause unwanted scrolls
		return;

	int finalBottom = note->finalY() + TQMIN(note->finalHeight(),                                             visibleHeight());
	int finalRight  = note->finalX() + TQMIN(note->width() + (note->hasResizer() ? Note::RESIZER_WIDTH : 0),  visibleWidth());
	ensureVisible( finalRight,     finalBottom,    0,0 );
	ensureVisible( note->finalX(), note->finalY(), 0,0 );
}

void Basket::addWatchedFile(const TQString &fullPath)
{
//	DEBUG_WIN << "Watcher>Add Monitoring Of : <font color=blue>" + fullPath + "</font>";
	m_watcher->addFile(fullPath);
}

void Basket::removeWatchedFile(const TQString &fullPath)
{
//	DEBUG_WIN << "Watcher>Remove Monitoring Of : <font color=blue>" + fullPath + "</font>";
	m_watcher->removeFile(fullPath);
}

void Basket::watchedFileModified(const TQString &fullPath)
{
	if (!m_modifiedFiles.contains(fullPath))
		m_modifiedFiles.append(fullPath);
	// If a big file is saved by an application, notifications are send several times.
	// We wait they are not sent anymore to considere the file complete!
	m_watcherTimer.start(200/*ms*/, true);
	DEBUG_WIN << "Watcher>Modified : <font color=blue>" + fullPath + "</font>";
}

void Basket::watchedFileDeleted(const TQString &fullPath)
{
	Note *note = noteForFullPath(fullPath);
	removeWatchedFile(fullPath);
	if (note) {
		NoteSelection *selection = selectedNotes();
		unselectAllBut(note);
		noteDeleteWithoutConfirmation();
		while (selection) {
			selection->note->setSelected(true);
			selection = selection->nextStacked();
		}
	}
	DEBUG_WIN << "Watcher>Removed : <font color=blue>" + fullPath + "</font>";
}

void Basket::updateModifiedNotes()
{
	for (TQValueList<TQString>::iterator it = m_modifiedFiles.begin(); it != m_modifiedFiles.end(); ++it) {
		Note *note = noteForFullPath(*it);
		if (note)
			note->content()->loadFromFile(/*lazyLoad=*/false);
	}
	m_modifiedFiles.clear();
}

bool Basket::setProtection(int type, TQString key)
{
#ifdef HAVE_LIBGPGME
	if(type == PasswordEncryption || // Ask a new password
		m_encryptionType != type || m_encryptionKey != key)
	{
		int savedType = m_encryptionType;
		TQString savedKey = m_encryptionKey;

		m_encryptionType = type;
		m_encryptionKey = key;
		m_gpg->clearCache();

		if(saveAgain())
		{
			emit propertiesChanged(this);
		}
		else
		{
			m_encryptionType = savedType;
			m_encryptionKey = savedKey;
			m_gpg->clearCache();
			return false;
		}
	}
	return true;
#else
	m_encryptionType = type;
	m_encryptionKey = key;
	return false;
#endif
}

bool Basket::saveAgain()
{
	bool result = false;

	m_watcher->stopScan();
	// Re-encrypt basket file:
	result = save();
	// Re-encrypt every note files recursively:
	if(result)
	{
		FOR_EACH_NOTE (note)
		{
			result = note->saveAgain();
			if(!result)
				break;
		}
	}
	m_watcher->startScan();
	return result;
}

bool Basket::loadFromFile(const TQString &fullPath, TQString *string, bool isLocalEncoding)
{
	TQByteArray array;

	if(loadFromFile(fullPath, &array)){
		if (isLocalEncoding)
			*string = TQString::fromLocal8Bit(array.data(), array.size());
		else
			*string = TQString::fromUtf8(array.data(), array.size());
		return true;
	}
	else
		return false;
}

bool Basket::isEncrypted()
{
	return (m_encryptionType != NoEncryption);
}

bool Basket::isFileEncrypted()
{
	TQFile file(fullPath() + ".basket");

	if (file.open(IO_ReadOnly)){
		TQString line;

		file.readLine(line, 32);
		if(line.startsWith("-----BEGIN PGP MESSAGE-----"))
		return true;
	}
	return false;
}

bool Basket::loadFromFile(const TQString &fullPath, TQByteArray *array)
{
	TQFile file(fullPath);
	bool encrypted = false;

	if (file.open(IO_ReadOnly)){
		*array = file.readAll();
		const char* magic = "-----BEGIN PGP MESSAGE-----";
		uint i = 0;

		if(array->size() > strlen(magic))
			for (i = 0; array->at(i) == magic[i]; ++i)
				;
		if (i == strlen(magic))
		{
			encrypted = true;
		}
		file.close();
#ifdef HAVE_LIBGPGME
		if(encrypted)
		{
			TQByteArray tmp(*array);

			tmp.detach();
			// Only use gpg-agent for private key encryption since it doesn't
			// cache password used in symmetric encryption.
			m_gpg->setUseGnuPGAgent(Settings::useGnuPGAgent() && m_encryptionType == PrivateKeyEncryption);
			if(m_encryptionType == PrivateKeyEncryption)
				m_gpg->setText(i18n("Please enter the password for the following private key:"), false);
			else
				m_gpg->setText(i18n("Please enter the password for the basket <b>%1</b>:").arg(basketName()), false); // Used when decrypting
			return m_gpg->decrypt(tmp, array);
		}
#else
		if(encrypted)
		{
			return false;
		}
#endif
		return true;
	} else
		return false;
}

bool Basket::saveToFile(const TQString& fullPath, const TQString& string, bool isLocalEncoding)
{
	TQCString bytes = (isLocalEncoding ? string.local8Bit() : string.utf8());
	return saveToFile(fullPath, bytes, bytes.length());
}

bool Basket::saveToFile(const TQString& fullPath, const TQByteArray& array)
{
	return saveToFile(fullPath, array, array.size());
}

bool Basket::saveToFile(const TQString& fullPath, const TQByteArray& array, TQ_ULONG length)
{
	bool success = true;
	TQByteArray tmp;

#ifdef HAVE_LIBGPGME
	if(isEncrypted())
	{
		TQString key = TQString();

		// We only use gpg-agent for private key encryption and saving without
		// public key doesn't need one.
		m_gpg->setUseGnuPGAgent(false);
		if(m_encryptionType == PrivateKeyEncryption)
		{
			key = m_encryptionKey;
			// public key doesn't need password
			m_gpg->setText("", false);
		}
		else
			m_gpg->setText(i18n("Please assign a password to the basket <b>%1</b>:").arg(basketName()), true); // Used when defining a new password

		success = m_gpg->encrypt(array, length, &tmp, key);
		length = tmp.size();
	}
	else
		tmp = array;

#else
	success = !isEncrypted();
	if(success)
		tmp = array;
#endif
	/*if (success && (success = file.open(IO_WriteOnly))){
		success = (file.writeBlock(tmp) == (TQ_LONG)tmp.size());
		file.close();
	}*/

	if (success)
		return safelySaveToFile(fullPath, tmp, length);
	else
		return false;
}

/** Same as saveToFile(), but it is static, and does not crypt the data if needed.
  * Basically, to save a file owned by a basket (a basket or a note file), use saveToFile().
  * But to save another file (eg. the basket hierarchy), use this safelySaveToFile() static method.
  */
/*static*/ bool Basket::safelySaveToFile(const TQString& fullPath, const TQByteArray& array, TQ_ULONG length)
{
	// Here, we take a double protection:
	// - We use KSaveFile to write atomically to the file (either it's a success or the file is untouched)
	// - We show a modal dialog to the user when no disk space is left or access is denied and retry every couple of seconds

	// Static, because safelySaveToFile() can be called a second time while blocked.
	// Example:
	// User type something and press Enter: safelySaveToFile() is called and block.
	// Three seconds later, a timer ask to save changes, and this second safelySaveToFile() block too.
	// Do not show the dialog twice in this case!
	static DiskErrorDialog *dialog = 0;

	//std::cout << "---------- Saving " << fullPath << ":" << std::endl;
	bool openSuccess;
	bool closeSuccess;
	bool errorWhileWritting;
	do {
		KSaveFile saveFile(fullPath);
		//std::cout << "==>>" << std::endl << "SAVE FILE CREATED: " << strerror(saveFile.status()) << std::endl;
		openSuccess = (saveFile.status() == 0 && saveFile.file() != 0);
		if (openSuccess) {
			saveFile.file()->writeBlock(array, length);
			//std::cout << "FILE WRITTEN: " << strerror(saveFile.status()) << std::endl;
			closeSuccess = saveFile.close();
			//std::cout << "FILE CLOSED: " << (closeSuccess ? "well" : "erroneous") << std::endl;
		}
		errorWhileWritting = (!openSuccess || !closeSuccess || saveFile.status() != 0);
		if (errorWhileWritting) {
			//std::cout << "ERROR DETECTED" << std::endl;
			if (dialog == 0) {
				//std::cout << "Opening dialog for " << fullPath << std::endl;
				dialog = new DiskErrorDialog(
					(openSuccess
						? i18n("Insufficient Disk Space to Save Basket Data")
						: i18n("Wrong Basket File Permissions")
					),
					(openSuccess
						? i18n("Please remove files on the disk <b>%1</b> to let the application safely save your changes.")
							.arg(TDEIO::findPathMountPoint(fullPath))
						: i18n("File permissions are bad for <b>%1</b>. Please check that you have write access to it and the parent folders.")
							.arg(fullPath)
					),
					kapp->activeWindow()
				);
			}
			if (!dialog->isShown())
				dialog->show();
			const int retryDelay = 1000/*ms*/;
			const int sleepDelay = 50/*ms*/;
			for (int i = 0; i < retryDelay / sleepDelay; ++i) {
				kapp->processEvents();
				usleep(sleepDelay);
			}
		}
	} while (errorWhileWritting);
	if (dialog) {
		delete dialog;
		dialog = 0;
	}

	return true; // Hum...?!
}

/*static*/ bool Basket::safelySaveToFile(const TQString& fullPath, const TQString& string, bool isLocalEncoding)
{
	TQCString bytes = (isLocalEncoding ? string.local8Bit() : string.utf8());
	return safelySaveToFile(fullPath, bytes, bytes.length() - 1);
}

/*static*/ bool Basket::safelySaveToFile(const TQString& fullPath, const TQByteArray& array)
{
	return safelySaveToFile(fullPath, array, array.size());
}

DiskErrorDialog::DiskErrorDialog(const TQString &titleMessage, const TQString &message, TQWidget *parent)
 : KDialogBase(KDialogBase::Plain, i18n("Save Error"),
               (KDialogBase::ButtonCode)0, (KDialogBase::ButtonCode)0, parent, /*name=*/"DiskError")
{
	//enableButtonCancel(false);
	//enableButtonClose(false);
	//enableButton(Close, false);
	//enableButtonOK(false);
	setModal(true);
	TQHBoxLayout *layout = new TQHBoxLayout(plainPage(), /*margin=*/0, spacingHint());
	TQPixmap icon = kapp->iconLoader()->loadIcon("drive-harddisk-unmounted", TDEIcon::NoGroup, 64, TDEIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
	TQLabel *iconLabel  = new TQLabel(plainPage());
	iconLabel->setPixmap(icon);
	iconLabel->setFixedSize(iconLabel->sizeHint());
	TQLabel *label = new TQLabel("<p><nobr><b><font size='+1'>" + titleMessage + "</font></b></nobr></p><p>" + message + "</p>", plainPage());
	if (!icon.isNull())
		layout->addWidget(iconLabel);
	layout->addWidget(label);
}

DiskErrorDialog::~DiskErrorDialog()
{
}

void DiskErrorDialog::closeEvent(TQCloseEvent *event)
{
	event->ignore();
}

void DiskErrorDialog::keyPressEvent(TQKeyEvent*)
{
	// Escape should not close the window...
}

void Basket::lock()
{
#ifdef HAVE_LIBGPGME
	closeEditor();
	m_gpg->clearCache();
	m_locked = true;
	enableActions();
	deleteNotes();
	m_loaded = false;
	m_loadingLaunched = false;
	updateContents();
#endif
}

#if 0

#include <tqlayout.h>
#include <tqvbox.h>
#include <tqstring.h>
#include <tqpixmap.h>
#include <tqcolor.h>
#include <tdepopupmenu.h>
#include <kurllabel.h>
#include <tqcheckbox.h>
#include <tqpalette.h>
#include <tqcursor.h>
#include <tqaction.h>
#include <tdestdaccel.h>
#include <tdeglobalsettings.h>
#include <tqevent.h>

#include <tdeapplication.h>
#include <tdeaboutdata.h>
#include <tqinputdialog.h>
#include <tqdragobject.h>
#include <kurldrag.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <kmimetype.h>
#include <tdefiledialog.h>
#include <tqdir.h>
#include <kiconloader.h>
#include <tqregexp.h>
#include <tqfileinfo.h>

#include <tqstringlist.h>
#include <tqdir.h>
#include <kurl.h>
#include <krun.h>
#include <tdemessagebox.h>

#include "kdirwatch.h"
#include <tqstringlist.h>
#include <klineedit.h>

#include <tqtextcodec.h>

#include "basket.h"
#include "note.h"
#include "notefactory.h"
#include "variouswidgets.h"
#include "linklabel.h"
#include "global.h"
#include "container.h"
#include "xmlwork.h"
#include "settings.h"
#include "popupmenu.h"
#include "debugwindow.h"
#include "exporterdialog.h"


/** Basket */

const int Basket::c_updateTime = 200;



// Remove the note from the basket and delete the associated file
// If the note mirror a file, it will ask before deleting or not the file
// But if askForMirroredFile is false, it willn't ask NOR delete the MIRRORED file
//  (it will anyway delete the file if it is not a mirror)
void Basket::delNote(Note *note, bool askForMirroredFile)
{
//...
	if (hasFocus())
		focusANote();       // We need note->next() and note->previous() here [BUT deleted note should be hidden]
	if (note->isSelected())
		note->setSelected(false); //removeSelectedNote();

	relayoutNotes();
	recolorizeNotes();
	resetInsertTo();         // If we delete the first or the last, pointer to it is invalid
	save();

	if (note == m_startOfShiftSelectionNote)
		m_startOfShiftSelectionNote = 0L;

	if (isDuringEdit() && m_editor->editedNote() == note)
		closeEditor(false);
//...
}


// Calculate where to paste or drop
void Basket::computeInsertPlace(const TQPoint &cursorPosition)
{
	int y = cursorPosition.y();

	if (countShown() == 0)
		return;

	// TODO: Memorize the last hovered note to avoid a new computation on dragMoveEvent !!
	//       If the mouse is not over the last note, compute which new is :
	// TODO: Optimization : start from m_insertAtNote and compare y position to search before or after (or the same)
	for (Note *it = firstNote(); it != 0L; it = it->next())
		if ( (it->isShown()) && (it->y() + it->height() >= y) && (it->y() < y) ) {
			int center = it->y() + (it->height() / 2);
			m_insertAtNote = it;
			m_insertAfter  = y > center;
			return;
		}
	// Else, there is at least one shown note but cursor hover NO note, so we are after the last shown note
	m_insertAtNote = lastShownNote();
	m_insertAfter  = true;

	// Code for rectangular notes :
	/*TQRect globalRect = it->rect();
	globalRect.moveTopLeft(it->pos() + contentsY());
	if ( globalRect.contains(curPos) ) {
		it->doInterestingThing();
	}*/
}

void Basket::dragMoveEvent(TQDragMoveEvent* event)
{
//	m_isDuringDrag = true;

	if (isLocked())
		return;

//	FIXME: viewportToContents does NOT work !!!
//	TQPoint pos = viewportToContents(event->pos());
	TQPoint pos( event->pos().x() + contentsX(), event->pos().y() + contentsY() );

//	if (insertAtCursorPos())
		computeInsertPlace(pos);

	showFrameInsertTo();
	acceptDropEvent(event);

	// A workarround since TQScrollView::dragAutoScroll seem to have no effect :
	ensureVisible(event->pos().x() + contentsX(), event->pos().y() + contentsY(), 30, 30);
//	TQScrollView::dragMoveEvent(event);
}

void Basket::dropEvent(TQDropEvent *event)
{
	TQPoint pos = event->pos();
	std::cout << "Drop Event at position " << pos.x() << ":" << pos.y() << std::endl;
	m_isDuringDrag = false;
	emit resetStatusBarText();

	if (isLocked())
		return;

	NoteFactory::dropNote( event, this, true, event->action(), dynamic_cast<Note*>(event->source()) );
	// TODO: need to know if we really inserted an (or several!!!!) note !!!
	ensureNoteVisible(lastInsertedNote());
	unselectAllBut(lastInsertedNote());
	setFocusedNote(lastInsertedNote());

	resetInsertTo();
}

void Basket::moveOnTop()
{
	if (m_countSelecteds == 0)
		return;

	Note *endOfBrowse = firstShownNote();
	Note *topNote     = firstNote();
	Note *prev;
	for (Note *it = lastShownNote(); it != 0L; ) {
		prev = it->previous();
		if (it->isSelected()) {
			m_insertAtNote = topNote;
			m_insertAfter  = false;
			changeNotePlace(it);
			topNote = it;
		}
		if (it == endOfBrowse)
			break;
		it = prev;
	}
	ensureNoteVisible(firstShownNote());
	ensureNoteVisible(m_focusedNote);
}

void Basket::moveOnBottom()
{
	if (m_countSelecteds == 0)
		return;

	Note *endOfBrowse = lastShownNote();
	Note *bottomNote  = lastNote();
	Note *next;
	for (Note *it = firstShownNote(); it != 0L; ) {
		next = it->next();
		if (it->isSelected()) {
			m_insertAtNote = bottomNote;
			m_insertAfter  = true;
			changeNotePlace(it);
			bottomNote = it;
		}
		if (it == endOfBrowse)
			break;
		it = next;
	}
	ensureNoteVisible(lastShownNote());
	ensureNoteVisible(m_focusedNote);
}

void Basket::moveNoteUp()
{
	if (m_countSelecteds == 0)
		return;

	// Begin from the top (important move all selected notes one note up
	// AND to quit early if a selected note is the first shown one
	for (Note *it = firstShownNote(); it != 0L; it = it->next()) {
		if (it->isSelected() && it->isShown()) { // it->isShown() not necessary, but in case...
			if (it == firstShownNote())
				return; // No way...
			m_insertAtNote = nextShownNoteFrom(it, -1); // Previous shown note
			if (m_insertAtNote == 0L) { // Should not appends, since it's not the first shown note,
				resetInsertTo();        // there SHOULD be one before
				return;
			}
			m_insertAfter  = false;
			changeNotePlace(it);
		}
		if (it == lastShownNote())
			break;
	}
	ensureNoteVisible(m_focusedNote);
}

void Basket::moveNoteDown()
{
	if (m_countSelecteds == 0)
		return;

	// Begin from the bottom (important move all selected notes one note down
	// AND to quit early if a selected note is the last shown one
	for (Note *it = lastShownNote(); it != 0L; it = it->previous()) {
		if (it->isSelected() && it->isShown()) { // it->isShown() not necessary, but in case...
			if (it == lastShownNote())
				return; // No way...
			m_insertAtNote = nextShownNoteFrom(it, 1); // Next shown note
			if (m_insertAtNote == 0L) { // Should not appends, since it's not the last shown note,
				resetInsertTo();        // there SHOULD be one before
				return;
			}
			m_insertAfter  = true;
			changeNotePlace(it);
		}
		if (it == firstShownNote())
			break;
	}
	ensureNoteVisible(m_focusedNote);
}

#endif // #if 0

#include "basket.moc"
