/***************************************************************************
* Copyright ( C ) 2003 by S <EFBFBD> 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 \n Right 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 \n Right click for more options " ) ; break ;
case Note : : TopGroup : message = i18n ( " Group note with the one below \n Right click for more options " ) ; break ;
case Note : : BottomGroup : message = i18n ( " Group note with the one above \n Right click for more options " ) ; break ;
case Note : : BottomColumn : message = i18n ( " Insert note here \n Right 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 ( ) ) ;
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
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 ( ) ;
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
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();
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
// // 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 );
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
// 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 ( ) )
# if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
, KStdGuiItem : : del ( ) , KStdGuiItem : : cancel ( ) ) ;
# else
) ;
# endif
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 <tdeversion.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"