/***************************************************************************
* 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 <tqpainter.h>
# include <tdeglobalsettings.h>
# include <tqstyle.h>
# include <tdeapplication.h>
# include <tdestyle.h>
# include <tqcursor.h>
# include <kiconloader.h>
# include <kpixmapeffect.h>
# include <kpixmap.h>
# include <tdeglobal.h>
# include <tdelocale.h>
# include <kurifilter.h>
# include <tqfile.h>
# include <stdlib.h> // rand() function
# include <math.h> // sqrt() and pow() functions
# include <iostream>
# ifdef None
# undef None
# endif
# include "basket.h"
# include "tag.h"
# include "note.h"
# include "tools.h"
# include "settings.h"
# include "notefactory.h" // For NoteFactory::filteredURL()
/** class Note: */
# define FOR_EACH_CHILD(childVar) \
for ( Note * childVar = firstChild ( ) ; childVar ; childVar = childVar - > next ( ) )
// TODO:
# define FOR_EACH_VISIBLE_CHILD(childVar) \
for ( . . . )
int Note : : NOTE_MARGIN = 2 ;
int Note : : INSERTION_HEIGHT = 5 ;
int Note : : EXPANDER_WIDTH = 9 ;
int Note : : EXPANDER_HEIGHT = 9 ;
int Note : : GROUP_WIDTH = 2 * NOTE_MARGIN + EXPANDER_WIDTH ;
int Note : : HANDLE_WIDTH = GROUP_WIDTH ;
int Note : : RESIZER_WIDTH = GROUP_WIDTH ;
int Note : : TAG_ARROW_WIDTH = 5 ;
int Note : : EMBLEM_SIZE = 16 ;
int Note : : MIN_HEIGHT = 2 * NOTE_MARGIN + EMBLEM_SIZE ;
Note : : Note ( Basket * parent )
: m_prev ( 0 ) , m_next ( 0 ) ,
m_x ( 0 ) , m_y ( - 1 ) , m_width ( - 1 ) , m_height ( - 1 ) ,
m_groupWidth ( 250 ) ,
m_isFolded ( false ) , m_firstChild ( 0L ) , m_parentNote ( 0 ) ,
m_basket ( parent ) , m_content ( 0 ) , m_addedDate ( TQDateTime : : currentDateTime ( ) ) , m_lastModificationDate ( TQDateTime : : currentDateTime ( ) ) ,
m_computedAreas ( false ) , m_onTop ( false ) ,
m_deltaX ( 0 ) , m_deltaY ( 0 ) , m_deltaHeight ( 0 ) , m_collapseFinished ( true ) , m_expandingFinished ( true ) ,
m_hovered ( false ) , m_hoveredZone ( Note : : None ) , m_focused ( false ) , m_selected ( false ) , m_wasInLastSelectionRect ( false ) ,
m_computedState ( ) , m_emblemsCount ( 0 ) , m_haveInvisibleTags ( false ) ,
m_matching ( true )
{
}
Note : : ~ Note ( )
{
delete m_content ;
deleteChilds ( ) ;
}
TQString Note : : addedStringDate ( )
{
return TDEGlobal : : locale ( ) - > formatDateTime ( m_addedDate ) ;
}
TQString Note : : lastModificationStringDate ( )
{
return TDEGlobal : : locale ( ) - > formatDateTime ( m_lastModificationDate ) ;
}
TQString Note : : toText ( const TQString & cuttedFullPath )
{
if ( content ( ) ) {
// Convert note to text:
TQString text = content ( ) - > toText ( cuttedFullPath ) ;
// If we should not export tags with the text, return immediatly:
if ( ! Settings : : exportTextTags ( ) )
return text ;
// Compute the text equivalent of the tag states:
TQString firstLine ;
TQString otherLines ;
for ( State : : List : : Iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it ) {
if ( ! ( * it ) - > textEquivalent ( ) . isEmpty ( ) ) {
firstLine + = ( * it ) - > textEquivalent ( ) + " " ;
if ( ( * it ) - > onAllTextLines ( ) )
otherLines + = ( * it ) - > textEquivalent ( ) + " " ;
}
}
// Merge the texts:
if ( firstLine . isEmpty ( ) )
return text ;
if ( otherLines . isEmpty ( ) )
return firstLine + text ;
TQStringList lines = TQStringList : : split ( ' \n ' , text , /*allowEmptyEntries=*/ true ) ;
TQString result = firstLine + lines [ 0 ] + ( lines . count ( ) > 1 ? " \n " : " " ) ;
for ( uint i = 1 /*Skip the first line*/ ; i < lines . count ( ) ; + + i )
result + = otherLines + lines [ i ] + ( i < lines . count ( ) - 1 ? " \n " : " " ) ;
return result ;
} else
return " " ;
}
bool Note : : computeMatching ( const FilterData & data )
{
// Groups are always matching:
if ( ! content ( ) )
return true ;
// If we were editing this note and there is a save operation in the middle, then do not hide it suddently:
if ( basket ( ) - > editedNote ( ) = = this )
return true ;
bool matching ;
// First match tags (they are fast to compute):
switch ( data . tagFilterType ) {
default :
case FilterData : : DontCareTagsFilter : matching = true ; break ;
case FilterData : : NotTaggedFilter : matching = m_states . count ( ) < = 0 ; break ;
case FilterData : : TaggedFilter : matching = m_states . count ( ) > 0 ; break ;
case FilterData : : TagFilter : matching = hasTag ( data . tag ) ; break ;
case FilterData : : StateFilter : matching = hasState ( data . state ) ; break ;
}
// Don't try to match the content text if we are not matching now (the filter is of 'AND' type) or if we shouldn't try to match the string:
if ( matching & & ! data . string . isEmpty ( ) )
matching = content ( ) - > match ( data ) ;
return matching ;
}
int Note : : newFilter ( const FilterData & data )
{
bool wasMatching = matching ( ) ;
m_matching = computeMatching ( data ) ;
setOnTop ( wasMatching & & matching ( ) ) ;
if ( ! matching ( ) )
setSelected ( false ) ;
int countMatches = ( content ( ) & & matching ( ) ? 1 : 0 ) ;
FOR_EACH_CHILD ( child )
countMatches + = child - > newFilter ( data ) ;
return countMatches ;
}
void Note : : deleteSelectedNotes ( bool deleteFilesToo )
{
if ( content ( ) & & isSelected ( ) ) {
basket ( ) - > unplugNote ( this ) ;
if ( deleteFilesToo & & content ( ) & & content ( ) - > useFile ( ) )
Tools : : deleteRecursively ( fullPath ( ) ) ; //basket()->deleteFiles(fullPath()); // Also delete the folder if it's a folder
//delete this;
return ;
}
Note * child = firstChild ( ) ;
Note * next ;
while ( child ) {
next = child - > next ( ) ; // If we delete 'child' on the next line, child->next() will be 0!
child - > deleteSelectedNotes ( deleteFilesToo ) ;
child = next ;
}
}
int Note : : count ( )
{
if ( content ( ) )
return 1 ;
int count = 0 ;
FOR_EACH_CHILD ( child )
count + = child - > count ( ) ;
return count ;
}
int Note : : countDirectChilds ( )
{
int count = 0 ;
FOR_EACH_CHILD ( child )
+ + count ;
return count ;
}
TQString Note : : fullPath ( )
{
if ( content ( ) )
return basket ( ) - > fullPath ( ) + content ( ) - > fileName ( ) ;
else
return " " ;
}
void Note : : update ( )
{
basket ( ) - > updateNote ( this ) ;
}
void Note : : setFocused ( bool focused )
{
if ( m_focused = = focused )
return ;
m_focused = focused ;
unbufferize ( ) ;
update ( ) ; // FIXME: ???
}
void Note : : setSelected ( bool selected )
{
if ( isGroup ( ) )
selected = false ; // A group cannot be selected!
if ( m_selected = = selected )
return ;
if ( ! selected & & basket ( ) - > editedNote ( ) = = this ) {
basket ( ) - > closeEditor ( ) ;
return ; // To avoid a bug that would count 2 less selected notes instead of 1 less! Because m_selected is modified only below.
}
if ( selected )
basket ( ) - > addSelectedNote ( ) ;
else
basket ( ) - > removeSelectedNote ( ) ;
m_selected = selected ;
unbufferize ( ) ;
update ( ) ; // FIXME: ???
}
void Note : : resetWasInLastSelectionRect ( )
{
m_wasInLastSelectionRect = false ;
FOR_EACH_CHILD ( child )
child - > resetWasInLastSelectionRect ( ) ;
}
void Note : : finishLazyLoad ( )
{
if ( content ( ) )
content ( ) - > finishLazyLoad ( ) ;
FOR_EACH_CHILD ( child )
child - > finishLazyLoad ( ) ;
}
void Note : : selectIn ( const TQRect & rect , bool invertSelection , bool unselectOthers /*= true*/ )
{
// TQRect myRect(x(), y(), width(), height());
// bool intersects = myRect.intersects(rect);
// Only intersects with visible areas.
// If the note is not visible, the user don't think it will be selected while selecting the note(s) that hide this, so act like the user think:
bool intersects = false ;
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & r = * it ;
if ( r . intersects ( rect ) ) {
intersects = true ;
break ;
}
}
bool toSelect = intersects | | ( ! unselectOthers & & isSelected ( ) ) ;
if ( invertSelection ) {
if ( m_wasInLastSelectionRect = = intersects )
toSelect = isSelected ( ) ;
else if ( intersects xor m_wasInLastSelectionRect )
toSelect = ! isSelected ( ) ; // xor intersects;
}
setSelected ( toSelect ) ;
m_wasInLastSelectionRect = intersects ;
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > selectIn ( rect , invertSelection , unselectOthers ) ;
else
child - > setSelectedRecursivly ( false ) ;
child = child - > next ( ) ;
first = false ;
}
}
bool Note : : allSelected ( )
{
if ( isGroup ( ) ) {
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
if ( ! child - > allSelected ( ) )
return false ; ;
child = child - > next ( ) ;
first = false ;
}
return true ;
} else
return isSelected ( ) ;
}
void Note : : setSelectedRecursivly ( bool selected )
{
setSelected ( selected & & matching ( ) ) ;
FOR_EACH_CHILD ( child )
child - > setSelectedRecursivly ( selected ) ;
}
void Note : : invertSelectionRecursivly ( )
{
if ( content ( ) )
setSelected ( ! isSelected ( ) & & matching ( ) ) ;
FOR_EACH_CHILD ( child )
child - > invertSelectionRecursivly ( ) ;
}
void Note : : unselectAllBut ( Note * toSelect )
{
if ( this = = toSelect )
setSelectedRecursivly ( true ) ;
else {
setSelected ( false ) ;
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > unselectAllBut ( toSelect ) ;
else
child - > setSelectedRecursivly ( false ) ;
child = child - > next ( ) ;
first = false ;
}
}
}
void Note : : invertSelectionOf ( Note * toSelect )
{
if ( this = = toSelect )
setSelectedRecursivly ( ! isSelected ( ) ) ;
else {
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > invertSelectionOf ( toSelect ) ;
child = child - > next ( ) ;
first = false ;
}
}
}
Note * Note : : theSelectedNote ( )
{
if ( ! isGroup ( ) & & isSelected ( ) )
return this ;
Note * selectedOne ;
Note * child = firstChild ( ) ;
while ( child ) {
selectedOne = child - > theSelectedNote ( ) ;
if ( selectedOne )
return selectedOne ;
child = child - > next ( ) ;
}
return 0 ;
}
NoteSelection * Note : : selectedNotes ( )
{
if ( content ( ) )
if ( isSelected ( ) )
return new NoteSelection ( this ) ;
else
return 0 ;
NoteSelection * selection = new NoteSelection ( this ) ;
FOR_EACH_CHILD ( child )
selection - > append ( child - > selectedNotes ( ) ) ;
if ( selection - > firstChild ) {
if ( selection - > firstChild - > next )
return selection ;
else {
// If 'selection' is a groupe with only one content, return directly that content:
NoteSelection * reducedSelection = selection - > firstChild ;
// delete selection; // TODO: Cut all connexions of 'selection' before deleting it!
for ( NoteSelection * node = reducedSelection ; node ; node = node - > next )
node - > parent = 0 ;
return reducedSelection ;
}
} else {
delete selection ;
return 0 ;
}
}
bool Note : : isAfter ( Note * note )
{
if ( this = = 0 | | note = = 0 )
return true ;
Note * next = this ;
while ( next ) {
if ( next = = note )
return false ;
next = next - > nextInStack ( ) ;
}
return true ;
}
bool Note : : contains ( Note * note )
{
// if (this == note)
// return true;
while ( note )
if ( note = = this )
return true ;
else
note = note - > parentNote ( ) ;
// FOR_EACH_CHILD (child)
// if (child->contains(note))
// return true;
return false ;
}
Note * Note : : firstRealChild ( )
{
Note * child = m_firstChild ;
while ( child ) {
if ( ! child - > isGroup ( ) /*&& child->matching()*/ )
return child ;
child = child - > firstChild ( ) ;
}
// Empty group:
return 0 ;
}
Note * Note : : lastRealChild ( )
{
Note * child = lastChild ( ) ;
while ( child ) {
if ( child - > content ( ) )
return child ;
Note * possibleChild = child - > lastRealChild ( ) ;
if ( possibleChild & & possibleChild - > content ( ) )
return possibleChild ;
child = child - > prev ( ) ;
}
return 0 ;
}
Note * Note : : lastChild ( )
{
Note * child = m_firstChild ;
while ( child & & child - > next ( ) )
child = child - > next ( ) ;
return child ;
}
Note * Note : : lastSibling ( )
{
Note * last = this ;
while ( last & & last - > next ( ) )
last = last - > next ( ) ;
return last ;
}
int Note : : yExpander ( )
{
Note * child = firstRealChild ( ) ;
if ( child & & ! child - > isShown ( ) )
child = child - > nextShownInStack ( ) ; // FIXME: Restrict scope to 'this'
if ( child )
return ( child - > height ( ) - EXPANDER_HEIGHT ) / 2 + ! ( child - > height ( ) % 2 ) ;
else // Groups always have at least 2 notes, except for columns which can have no child (but should exists anyway):
return 0 ;
}
bool Note : : isFree ( )
{
return parentNote ( ) = = 0 & & basket ( ) - > isFreeLayout ( ) ;
}
bool Note : : isColumn ( )
{
return parentNote ( ) = = 0 & & basket ( ) - > isColumnsLayout ( ) ;
}
bool Note : : hasResizer ( )
{
// "isFree" || "isColmun but not the last"
return parentNote ( ) = = 0 & & ( basket ( ) - > isFreeLayout ( ) | | m_next ! = 0L ) ;
}
int Note : : resizerHeight ( )
{
return ( isColumn ( ) ? basket ( ) - > contentsHeight ( ) : height ( ) ) ;
}
void Note : : setHoveredZone ( Zone zone ) // TODO: Remove setHovered(bool) and assume it is hovered if zone != None !!!!!!!
{
if ( m_hoveredZone ! = zone ) {
if ( content ( ) )
content ( ) - > setHoveredZone ( m_hoveredZone , zone ) ;
m_hoveredZone = zone ;
unbufferize ( ) ;
}
}
Note : : Zone Note : : zoneAt ( const TQPoint & pos , bool toAdd )
{
// Keep the resizer highlighted when resizong, even if the cursor is over another note:
if ( basket ( ) - > resizingNote ( ) = = this )
return Resizer ;
// When dropping/pasting something on a column resizer, add it at the bottom of the column, and don't group it whith the whole column:
if ( toAdd & & isColumn ( ) & & hasResizer ( ) ) {
int right = rightLimit ( ) - x ( ) ;
if ( ( pos . x ( ) > = right ) & & ( pos . x ( ) < right + RESIZER_WIDTH ) & & ( pos . y ( ) > = 0 ) & & ( pos . y ( ) < resizerHeight ( ) ) ) // Code copied from below
return BottomColumn ;
}
// Below a column:
if ( isColumn ( ) ) {
if ( pos . y ( ) > = height ( ) & & pos . x ( ) < rightLimit ( ) - x ( ) )
return BottomColumn ;
}
// If toAdd, return only TopInsert, TopGroup, BottomInsert or BottomGroup
// (by spanning those areas in 4 equal rectangles in the note):
if ( toAdd ) {
if ( ! isFree ( ) & & ! Settings : : groupOnInsertionLine ( ) )
return ( pos . y ( ) < height ( ) / 2 ? TopInsert : BottomInsert ) ;
if ( isColumn ( ) & & pos . y ( ) > = height ( ) )
return BottomGroup ;
if ( pos . y ( ) < height ( ) / 2 )
if ( pos . x ( ) < width ( ) / 2 & & ! isFree ( ) )
return TopInsert ;
else
return TopGroup ;
else
if ( pos . x ( ) < width ( ) / 2 & & ! isFree ( ) )
return BottomInsert ;
else
return BottomGroup ;
}
// If in the resizer:
if ( hasResizer ( ) ) {
int right = rightLimit ( ) - x ( ) ;
if ( ( pos . x ( ) > = right ) & & ( pos . x ( ) < right + RESIZER_WIDTH ) & & ( pos . y ( ) > = 0 ) & & ( pos . y ( ) < resizerHeight ( ) ) )
return Resizer ;
}
// If isGroup, return only Group, GroupExpander, TopInsert or BottomInsert:
if ( isGroup ( ) ) {
if ( pos . y ( ) < INSERTION_HEIGHT )
return ( isFree ( ) ? TopGroup : TopInsert ) ;
if ( pos . y ( ) > = height ( ) - INSERTION_HEIGHT )
return ( isFree ( ) ? BottomGroup : BottomInsert ) ;
if ( pos . x ( ) > = NOTE_MARGIN & & pos . x ( ) < NOTE_MARGIN + EXPANDER_WIDTH ) {
int yExp = yExpander ( ) ;
if ( pos . y ( ) > = yExp & & pos . y ( ) < yExp + EXPANDER_HEIGHT )
return GroupExpander ;
}
if ( pos . x ( ) < width ( ) )
return Group ;
else
return Note : : None ;
}
// Else, it's a normal note:
if ( pos . x ( ) < HANDLE_WIDTH )
return Handle ;
if ( pos . y ( ) < INSERTION_HEIGHT )
if ( ( ! isFree ( ) & & ! Settings : : groupOnInsertionLine ( ) ) | | pos . x ( ) < width ( ) / 2 & & ! isFree ( ) )
return TopInsert ;
else
return TopGroup ;
if ( pos . y ( ) > = height ( ) - INSERTION_HEIGHT )
if ( ( ! isFree ( ) & & ! Settings : : groupOnInsertionLine ( ) ) | | pos . x ( ) < width ( ) / 2 & & ! isFree ( ) )
return BottomInsert ;
else
return BottomGroup ;
for ( int i = 0 ; i < m_emblemsCount ; i + + ) {
if ( pos . x ( ) > = HANDLE_WIDTH + ( NOTE_MARGIN + EMBLEM_SIZE ) * i & &
pos . x ( ) < HANDLE_WIDTH + ( NOTE_MARGIN + EMBLEM_SIZE ) * i + NOTE_MARGIN + EMBLEM_SIZE )
return ( Zone ) ( Emblem0 + i ) ;
}
if ( pos . x ( ) < HANDLE_WIDTH + ( NOTE_MARGIN + EMBLEM_SIZE ) * m_emblemsCount + NOTE_MARGIN + TAG_ARROW_WIDTH + NOTE_MARGIN )
return TagsArrow ;
if ( ! linkAt ( pos ) . isEmpty ( ) )
return Link ;
int customZone = content ( ) - > zoneAt ( pos - TQPoint ( contentX ( ) , NOTE_MARGIN ) ) ;
if ( customZone )
return ( Note : : Zone ) customZone ;
return Content ;
}
TQString Note : : linkAt ( const TQPoint & pos )
{
TQString link = m_content - > linkAt ( pos - TQPoint ( contentX ( ) , NOTE_MARGIN ) ) ;
if ( link . isEmpty ( ) )
return link ;
else
return NoteFactory : : filteredURL ( KURL ( link ) ) . prettyURL ( ) ; //KURIFilter::self()->filteredURI(link);
}
int Note : : contentX ( )
{
return HANDLE_WIDTH + NOTE_MARGIN + ( EMBLEM_SIZE + NOTE_MARGIN ) * m_emblemsCount + TAG_ARROW_WIDTH + NOTE_MARGIN ;
}
TQRect Note : : zoneRect ( Note : : Zone zone , const TQPoint & pos )
{
if ( zone > = Emblem0 )
return TQRect ( HANDLE_WIDTH + ( NOTE_MARGIN + EMBLEM_SIZE ) * ( zone - Emblem0 ) ,
INSERTION_HEIGHT ,
NOTE_MARGIN + EMBLEM_SIZE ,
height ( ) - 2 * INSERTION_HEIGHT ) ;
int yExp ;
int right ;
int xGroup = ( isFree ( ) ? ( isGroup ( ) ? 0 : GROUP_WIDTH ) : width ( ) / 2 ) ;
TQRect rect ;
int insertSplit = ( Settings : : groupOnInsertionLine ( ) ? 2 : 1 ) ;
switch ( zone ) {
case Note : : Handle : return TQRect ( 0 , 0 , HANDLE_WIDTH , height ( ) ) ;
case Note : : Group :
yExp = yExpander ( ) ;
if ( pos . y ( ) < yExp ) return TQRect ( 0 , INSERTION_HEIGHT , width ( ) , yExp - INSERTION_HEIGHT ) ;
if ( pos . y ( ) > yExp + EXPANDER_HEIGHT ) return TQRect ( 0 , yExp + EXPANDER_HEIGHT , width ( ) , height ( ) - yExp - EXPANDER_HEIGHT - INSERTION_HEIGHT ) ;
if ( pos . x ( ) < NOTE_MARGIN ) return TQRect ( 0 , 0 , NOTE_MARGIN , height ( ) ) ;
else return TQRect ( width ( ) - NOTE_MARGIN , 0 , NOTE_MARGIN , height ( ) ) ;
case Note : : TagsArrow : return TQRect ( HANDLE_WIDTH + ( NOTE_MARGIN + EMBLEM_SIZE ) * m_emblemsCount ,
INSERTION_HEIGHT ,
NOTE_MARGIN + TAG_ARROW_WIDTH + NOTE_MARGIN ,
height ( ) - 2 * INSERTION_HEIGHT ) ;
case Note : : Custom0 :
case Note : : Content : rect = content ( ) - > zoneRect ( zone , pos - TQPoint ( contentX ( ) , NOTE_MARGIN ) ) ;
rect . moveBy ( contentX ( ) , NOTE_MARGIN ) ;
return rect . intersect ( TQRect ( contentX ( ) , INSERTION_HEIGHT , width ( ) - contentX ( ) , height ( ) - 2 * INSERTION_HEIGHT ) ) ; // Only IN contentRect
case Note : : GroupExpander : return TQRect ( NOTE_MARGIN , yExpander ( ) , EXPANDER_WIDTH , EXPANDER_HEIGHT ) ;
case Note : : Resizer : right = rightLimit ( ) ;
return TQRect ( right - x ( ) , 0 , RESIZER_WIDTH , resizerHeight ( ) ) ;
case Note : : Link :
case Note : : TopInsert : if ( isGroup ( ) ) return TQRect ( 0 , 0 , width ( ) , INSERTION_HEIGHT ) ;
else return TQRect ( HANDLE_WIDTH , 0 , width ( ) / insertSplit - HANDLE_WIDTH , INSERTION_HEIGHT ) ;
case Note : : TopGroup : return TQRect ( xGroup , 0 , width ( ) - xGroup , INSERTION_HEIGHT ) ;
case Note : : BottomInsert : if ( isGroup ( ) ) return TQRect ( 0 , height ( ) - INSERTION_HEIGHT , width ( ) , INSERTION_HEIGHT ) ;
else return TQRect ( HANDLE_WIDTH , height ( ) - INSERTION_HEIGHT , width ( ) / insertSplit - HANDLE_WIDTH , INSERTION_HEIGHT ) ;
case Note : : BottomGroup : return TQRect ( xGroup , height ( ) - INSERTION_HEIGHT , width ( ) - xGroup , INSERTION_HEIGHT ) ;
case Note : : BottomColumn : return TQRect ( 0 , height ( ) , rightLimit ( ) - x ( ) , basket ( ) - > contentsHeight ( ) - height ( ) ) ;
case Note : : None : return TQRect ( /*0, 0, -1, -1*/ ) ;
default : return TQRect ( /*0, 0, -1, -1*/ ) ;
}
}
void Note : : setCursor ( Zone zone )
{
switch ( zone ) {
case Note : : Handle :
case Note : : Group : basket ( ) - > viewport ( ) - > setCursor ( TQt : : SizeAllCursor ) ; break ;
case Note : : Resizer : if ( isColumn ( ) )
basket ( ) - > viewport ( ) - > setCursor ( TQt : : SplitHCursor ) ;
else
basket ( ) - > viewport ( ) - > setCursor ( TQt : : SizeHorCursor ) ; break ;
case Note : : Custom0 : content ( ) - > setCursor ( basket ( ) - > viewport ( ) , zone ) ; break ;
case Note : : Link :
case Note : : TagsArrow :
case Note : : GroupExpander : basket ( ) - > viewport ( ) - > setCursor ( TQt : : PointingHandCursor ) ; break ;
case Note : : Content : basket ( ) - > viewport ( ) - > setCursor ( TQt : : IbeamCursor ) ; break ;
case Note : : TopInsert :
case Note : : TopGroup :
case Note : : BottomInsert :
case Note : : BottomGroup :
case Note : : BottomColumn : basket ( ) - > viewport ( ) - > setCursor ( TQt : : CrossCursor ) ; break ;
case Note : : None : basket ( ) - > viewport ( ) - > unsetCursor ( ) ; break ;
default :
State * state = stateForEmblemNumber ( zone - Emblem0 ) ;
if ( state & & state - > parentTag ( ) - > states ( ) . count ( ) > 1 )
basket ( ) - > viewport ( ) - > setCursor ( TQt : : PointingHandCursor ) ;
else
basket ( ) - > viewport ( ) - > unsetCursor ( ) ;
}
}
void Note : : addAnimation ( int deltaX , int deltaY , int deltaHeight )
{
// Don't process animation that make the note stay in place!
if ( deltaX = = 0 & & deltaY = = 0 & & deltaHeight = = 0 )
return ;
// If it was not animated previsouly, make it animated:
if ( m_deltaX = = 0 & & m_deltaY = = 0 & & m_deltaHeight = = 0 )
basket ( ) - > addAnimatedNote ( this ) ;
// Configure the animation:
m_deltaX + = deltaX ;
m_deltaY + = deltaY ;
m_deltaHeight + = deltaHeight ;
}
void Note : : setFinalPosition ( int x , int y )
{
addAnimation ( x - finalX ( ) , y - finalY ( ) ) ;
}
void Note : : initAnimationLoad ( )
{
int x , y ;
switch ( rand ( ) % 4 ) {
case 0 : // Put it on top:
x = basket ( ) - > contentsX ( ) + rand ( ) % basket ( ) - > contentsWidth ( ) ;
y = - height ( ) ;
break ;
case 1 : // Put it on bottom:
x = basket ( ) - > contentsX ( ) + rand ( ) % basket ( ) - > contentsWidth ( ) ;
y = basket ( ) - > contentsY ( ) + basket ( ) - > visibleHeight ( ) ;
break ;
case 2 : // Put it on left:
x = - width ( ) - ( hasResizer ( ) ? Note : : RESIZER_WIDTH : 0 ) ;
y = basket ( ) - > contentsY ( ) + rand ( ) % basket ( ) - > visibleHeight ( ) ;
break ;
case 3 : // Put it on right:
default : // In the case of...
x = basket ( ) - > contentsX ( ) + basket ( ) - > visibleWidth ( ) ;
y = basket ( ) - > contentsY ( ) + rand ( ) % basket ( ) - > visibleHeight ( ) ;
break ;
}
cancelAnimation ( ) ;
addAnimation ( finalX ( ) - x , finalY ( ) - y ) ;
setX ( x ) ;
setY ( y ) ;
if ( isGroup ( ) ) {
const int viewHeight = basket ( ) - > contentsY ( ) + basket ( ) - > visibleHeight ( ) ;
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( child - > finalY ( ) < viewHeight ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > initAnimationLoad ( ) ;
} else
break ; // 'child' are not a free notes (because child of at least one note, 'this'), so 'child' is ordered vertically.
child = child - > next ( ) ;
first = false ;
}
}
}
bool Note : : advance ( )
{
// Animate X:
if ( m_deltaX ! = 0 ) {
int deltaX = m_deltaX / 3 ;
if ( deltaX = = 0 )
deltaX = ( m_deltaX > 0 ? 1 : - 1 ) ;
setX ( m_x + deltaX ) ;
m_deltaX - = deltaX ;
}
// Animate Y:
if ( m_deltaY ! = 0 ) {
int deltaY = m_deltaY / 3 ;
if ( deltaY = = 0 )
deltaY = ( m_deltaY > 0 ? 1 : - 1 ) ;
setY ( m_y + deltaY ) ;
m_deltaY - = deltaY ;
}
// Animate Height:
if ( m_deltaHeight ! = 0 ) {
int deltaHeight = m_deltaHeight / 3 ;
if ( deltaHeight = = 0 )
deltaHeight = ( m_deltaHeight > 0 ? 1 : - 1 ) ;
m_height + = deltaHeight ;
unbufferize ( ) ;
m_deltaHeight - = deltaHeight ;
}
if ( m_deltaHeight = = 0 ) {
m_collapseFinished = true ;
m_expandingFinished = true ;
}
// Return true if the animation is finished:
return ( m_deltaX = = 0 & & m_deltaY = = 0 & & m_deltaHeight = = 0 ) ;
}
void Note : : unsetWidth ( )
{
m_width = 0 ;
unbufferize ( ) ;
FOR_EACH_CHILD ( child )
child - > unsetWidth ( ) ;
}
void Note : : requestRelayout ( )
{
m_width = 0 ;
unbufferize ( ) ;
basket ( ) - > relayoutNotes ( true ) ; // TODO: A signal that will relayout ONCE and DELAYED if called several times
}
void Note : : setWidth ( int width ) // TODO: inline ?
{
if ( m_width ! = width )
setWidthForceRelayout ( width ) ;
}
void Note : : setWidthForceRelayout ( int width )
{
unbufferize ( ) ;
m_width = ( width < minWidth ( ) ? minWidth ( ) : width ) ;
int contentWidth = width - contentX ( ) - NOTE_MARGIN ;
if ( m_content ) { ///// FIXME: is this OK?
if ( contentWidth < 1 )
contentWidth = 1 ;
if ( contentWidth < m_content - > minWidth ( ) )
contentWidth = m_content - > minWidth ( ) ;
m_height = m_content - > setWidthAndGetHeight ( contentWidth /* < 1 ? 1 : contentWidth*/ ) + 2 * NOTE_MARGIN ;
if ( m_height < 3 * INSERTION_HEIGHT ) // Assure a minimal size...
m_height = 3 * INSERTION_HEIGHT ;
}
}
int Note : : minWidth ( )
{
if ( m_content )
return contentX ( ) + m_content - > minWidth ( ) + NOTE_MARGIN ;
else
return GROUP_WIDTH ; ///// FIXME: is this OK?
}
int Note : : minRight ( )
{
if ( isGroup ( ) ) {
int right = finalX ( ) + width ( ) ;
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
right = TQMAX ( right , child - > minRight ( ) ) ;
child = child - > next ( ) ;
first = false ;
}
if ( isColumn ( ) ) {
int minColumnRight = finalX ( ) + 2 * HANDLE_WIDTH ;
if ( right < minColumnRight )
return minColumnRight ;
}
return right ;
} else
return finalX ( ) + minWidth ( ) ;
}
void Note : : setX ( int x )
{
if ( m_x = = x )
return ;
if ( isBufferized ( ) & & basket ( ) - > hasBackgroundImage ( ) ) {
// Unbufferize only if the background change:
if ( basket ( ) - > isTiledBackground ( ) )
unbufferize ( ) ;
else {
int bgw = basket ( ) - > backgroundPixmap ( ) - > width ( ) ;
if ( m_x > = bgw & & x < bgw ) // Was not in the background image and is now inside it:
unbufferize ( ) ;
else if ( m_x < bgw ) // Was in the background image and is now at another position of the background image or is now outside:
unbufferize ( ) ;
}
}
m_x = x ;
}
void Note : : setY ( int y )
{
if ( m_y = = y )
return ;
if ( isBufferized ( ) & & basket ( ) - > hasBackgroundImage ( ) ) {
// Unbufferize only if the background change:
if ( basket ( ) - > isTiledBackground ( ) )
unbufferize ( ) ;
else {
int bgh = basket ( ) - > backgroundPixmap ( ) - > height ( ) ;
if ( m_y > = bgh & & y < bgh ) // Was not in the background image and is now inside it:
unbufferize ( ) ;
else if ( m_y < bgh ) // Was in the background image and is now at another position of the background image or is now outside:
unbufferize ( ) ;
}
}
m_y = y ;
}
void Note : : toggleFolded ( bool animate )
{
// Close the editor if it was editing a note that we are about to hide after collapsing:
if ( ! m_isFolded & & basket ( ) & & basket ( ) - > isDuringEdit ( ) ) {
if ( contains ( basket ( ) - > editedNote ( ) ) & & firstRealChild ( ) ! = basket ( ) - > editedNote ( ) )
basket ( ) - > closeEditor ( ) ;
}
// Important to close the editor FIRST, because else, the last edited note would not show during folding animation (don't ask me why ;-) ):
m_isFolded = ! m_isFolded ;
unbufferize ( ) ;
if ( animate ) {
// We animate collapsing (so sub-notes fluidly go under the first note)
// We don't animate expanding: we place sub-notes directly under the first note (and the next relayout will animate the expanding)
// But if user quickly collapsed and then expand (while the collapsing animation isn't finished), we animate anyway
bool animateSetUnder = ( m_isFolded | | ! m_collapseFinished ) ;
// std::cout << "fold:" << m_isFolded << " collapseFinished:" << m_collapseFinished << " animateSetUnder:" << animateSetUnder << std::endl;
if ( m_isFolded )
m_collapseFinished = false ;
else
m_expandingFinished = false ;
Note * note = firstChild ( ) ;
if ( note ) {
note - > setOnTop ( true ) ;
while ( ( note = note - > next ( ) ) ) { // Don't process the first child: it is OK
note - > setRecursivelyUnder ( /*firstRealChild*/ firstChild ( ) , animateSetUnder ) ;
note - > setOnTop ( false ) ;
}
}
}
//if (basket()->focusedNote() && !basket()->focusedNote()->isShown()) {
if ( basket ( ) - > isLoaded ( ) ) {
basket ( ) - > setFocusedNote ( firstRealChild ( ) ) ;
basket ( ) - > m_startOfShiftSelectionNote = firstRealChild ( ) ;
}
if ( basket ( ) - > isLoaded ( ) & & ! m_isFolded ) {
//basket()->setFocusedNote(this);
basket ( ) - > relayoutNotes ( true ) ;
basket ( ) - > ensureNoteVisible ( this ) ;
}
basket ( ) - > save ( ) ; // FIXME: SHOULD WE ALWAYS SAVE ????????
}
void Note : : setRecursivelyUnder ( Note * under , bool animate )
{
int y = /*finalHeight() > under->finalHeight() ? under->finalY() :*/ under - > finalBottom ( ) - finalHeight ( ) + 1 ;
if ( animate )
setFinalPosition ( finalX ( ) , y ) ;
else {
setY ( y ) ;
cancelAnimation ( ) ;
}
if ( isGroup ( ) )
FOR_EACH_CHILD ( child )
child - > setRecursivelyUnder ( under , animate ) ;
}
Note * Note : : noteAt ( int x , int y )
{
if ( matching ( ) & & hasResizer ( ) ) {
int right = rightLimit ( ) ;
// TODO: This code is dupliacted 3 times: !!!!
if ( ( x > = right ) & & ( x < right + RESIZER_WIDTH ) & & ( y > = m_y ) & & ( y < m_y + resizerHeight ( ) ) ) {
if ( ! m_computedAreas )
recomputeAreas ( ) ;
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & rect = * it ;
if ( rect . contains ( x , y ) )
return this ;
}
}
}
if ( isGroup ( ) ) {
if ( ( x > = m_x ) & & ( x < m_x + width ( ) ) & & ( y > = m_y ) & & ( y < m_y + m_height ) ) {
if ( ! m_computedAreas )
recomputeAreas ( ) ;
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & rect = * it ;
if ( rect . contains ( x , y ) )
return this ;
}
return NULL ;
}
Note * child = firstChild ( ) ;
Note * found ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) ) {
found = child - > noteAt ( x , y ) ;
if ( found )
return found ;
}
child = child - > next ( ) ;
first = false ;
}
} else if ( matching ( ) & & y > = m_y & & y < m_y + m_height & & x > = m_x & & x < m_x + m_width ) {
if ( ! m_computedAreas )
recomputeAreas ( ) ;
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & rect = * it ;
if ( rect . contains ( x , y ) )
return this ;
}
return NULL ;
}
return NULL ;
}
TQRect Note : : rect ( )
{
return TQRect ( x ( ) , y ( ) , width ( ) , height ( ) ) ;
}
TQRect Note : : resizerRect ( )
{
return TQRect ( rightLimit ( ) , y ( ) , RESIZER_WIDTH , resizerHeight ( ) ) ;
}
bool Note : : showSubNotes ( )
{
return ! m_isFolded | | ! m_collapseFinished | | basket ( ) - > isFiltering ( ) ;
}
void Note : : relayoutAt ( int x , int y , bool animate )
{
if ( ! matching ( ) )
return ;
m_computedAreas = false ;
m_areas . clear ( ) ;
// Don't relayout free notes one under the other, because by definition they are freely positionned!
if ( isFree ( ) ) {
x = finalX ( ) ;
y = finalY ( ) ;
// If it's a column, it always have the same "fixed" position (no animation):
} else if ( isColumn ( ) ) {
x = ( prev ( ) ? prev ( ) - > rightLimit ( ) + RESIZER_WIDTH : 0 ) ;
y = 0 ;
cancelAnimation ( ) ;
setX ( x ) ;
setY ( y ) ;
// But relayout others vertically if they are inside such primary groups or if it is a "normal" basket:
} else {
if ( animate )
setFinalPosition ( x , y ) ;
else {
cancelAnimation ( ) ;
setX ( x ) ;
setY ( y ) ;
}
}
// Then, relayout sub-notes (only the first, if the group is folded) and so, assign an height to the group:
if ( isGroup ( ) ) {
int h = 0 ;
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( child - > matching ( ) & & ( ! m_isFolded | | first | | basket ( ) - > isFiltering ( ) ) ) { // Don't use showSubNotes() but use !m_isFolded because we don't want a relayout for the animated collapsing notes
child - > relayoutAt ( x + width ( ) , y + h , animate ) ;
h + = child - > finalHeight ( ) ;
} else // In case the user collapse a group, then move it and then expand it:
child - > setXRecursivly ( x + width ( ) ) ; // notes SHOULD have a good X coordonate, and not the old one!
// For future animation when re-match, but on bottom of already matched notes!
// Find parent primary note and set the Y to THAT y:
if ( ! child - > matching ( ) )
child - > setY ( parentPrimaryNote ( ) - > y ( ) ) ;
child = child - > next ( ) ;
first = false ;
}
if ( finalHeight ( ) ! = h | | m_height ! = h ) {
unbufferize ( ) ;
if ( animate )
addAnimation ( 0 , 0 , h - finalHeight ( ) ) ;
else {
m_height = h ;
unbufferize ( ) ;
}
}
} else {
setWidth ( finalRightLimit ( ) - x ) ;
// If rightLimit is excedded, set the top-level right limit!!!
// and NEED RELAYOUT
}
// Set the basket area limits (but not for child notes: no need, because they will look for theire parent note):
if ( ! parentNote ( ) ) {
if ( basket ( ) - > tmpWidth < finalRightLimit ( ) + ( hasResizer ( ) ? RESIZER_WIDTH : 0 ) )
basket ( ) - > tmpWidth = finalRightLimit ( ) + ( hasResizer ( ) ? RESIZER_WIDTH : 0 ) ;
if ( basket ( ) - > tmpHeight < finalY ( ) + finalHeight ( ) )
basket ( ) - > tmpHeight = finalY ( ) + finalHeight ( ) ;
// However, if the note exceed the allowed size, let it! :
} else if ( ! isGroup ( ) ) {
if ( basket ( ) - > tmpWidth < finalX ( ) + width ( ) )
basket ( ) - > tmpWidth = finalX ( ) + width ( ) ;
if ( basket ( ) - > tmpHeight < finalY ( ) + finalHeight ( ) )
basket ( ) - > tmpHeight = finalY ( ) + finalHeight ( ) ;
}
}
void Note : : setXRecursivly ( int x )
{
m_deltaX = 0 ;
setX ( x ) ;
FOR_EACH_CHILD ( child )
child - > setXRecursivly ( x + width ( ) ) ;
}
void Note : : setYRecursivly ( int y )
{
m_deltaY = 0 ;
setY ( y ) ;
FOR_EACH_CHILD ( child )
child - > setYRecursivly ( y ) ;
}
void Note : : setGroupWidth ( int width )
{
m_groupWidth = width ;
}
int Note : : groupWidth ( )
{
if ( hasResizer ( ) )
return m_groupWidth ;
else
return rightLimit ( ) - x ( ) ;
}
int Note : : rightLimit ( )
{
if ( isColumn ( ) & & m_next = = 0L ) // The last column
return TQMAX ( x ( ) + minWidth ( ) , basket ( ) - > visibleWidth ( ) ) ;
else if ( parentNote ( ) )
return parentNote ( ) - > rightLimit ( ) ;
else
return m_x + m_groupWidth ;
}
int Note : : finalRightLimit ( )
{
if ( isColumn ( ) & & m_next = = 0L ) // The last column
return TQMAX ( finalX ( ) + minWidth ( ) , basket ( ) - > visibleWidth ( ) ) ;
else if ( parentNote ( ) )
return parentNote ( ) - > finalRightLimit ( ) ;
else
return finalX ( ) + m_groupWidth ;
}
/*
* This code is derivated from drawMetalGradient ( ) from the TQt documentation :
*/
void drawGradient ( TQPainter * p , const TQColor & colorTop , const TQColor & colorBottom ,
int x , int y , int w , int h ,
bool sunken , bool horz , bool flat ) /*const*/
{
TQColor highlight ( colorBottom ) ;
TQColor subh1 ( colorTop ) ;
TQColor subh2 ( colorTop ) ;
TQColor topgrad ( colorTop ) ;
TQColor botgrad ( colorBottom ) ;
if ( flat & & ! sunken )
p - > fillRect ( x , y , w , h , colorTop ) ;
else {
int i = 0 ;
int x1 = x ;
int y1 = y ;
int x2 = x + w - 1 ;
int y2 = y + h - 1 ;
if ( horz )
x2 = x2 ;
else
y2 = y2 ;
# define DRAWLINE if (horz) \
p - > drawLine ( x1 , y1 + i , x2 , y1 + i ) ; \
else \
p - > drawLine ( x1 + i , y1 , x1 + i , y2 ) ; \
i + + ;
// Gradient:
int ng = ( horz ? h : w ) ; // how many lines for the gradient?
int h1 , h2 , s1 , s2 , v1 , v2 ;
if ( ! sunken ) {
topgrad . hsv ( & h1 , & s1 , & v1 ) ;
botgrad . hsv ( & h2 , & s2 , & v2 ) ;
} else {
botgrad . hsv ( & h1 , & s1 , & v1 ) ;
topgrad . hsv ( & h2 , & s2 , & v2 ) ;
}
if ( ng > 1 ) {
for ( int j = 0 ; j < ng ; j + + ) {
p - > setPen ( TQColor ( h1 + ( ( h2 - h1 ) * j ) / ( ng - 1 ) ,
s1 + ( ( s2 - s1 ) * j ) / ( ng - 1 ) ,
v1 + ( ( v2 - v1 ) * j ) / ( ng - 1 ) , TQColor : : Hsv ) ) ;
DRAWLINE ;
}
} else if ( ng = = 1 ) {
p - > setPen ( TQColor ( ( h1 + h2 ) / 2 , ( s1 + s2 ) / 2 , ( v1 + v2 ) / 2 , TQColor : : Hsv ) ) ;
DRAWLINE ;
}
}
}
void Note : : drawExpander ( TQPainter * painter , int x , int y , const TQColor & background , bool expand , Basket * basket )
{
// If the current style is a TDEStyle, use it to draw the expander (plus or minus):
if ( dynamic_cast < TDEStyle * > ( & ( kapp - > style ( ) ) ) ! = NULL ) {
// Set the 4 rounded corners background to background color:
TQColorGroup cg ( basket - > colorGroup ( ) ) ;
cg . setColor ( TQColorGroup : : Base , background ) ;
// Fill the inside of the expander in white, typically:
TQBrush brush ( TDEGlobalSettings : : baseColor ( ) ) ;
painter - > fillRect ( x , y , 9 , 9 , brush ) ;
// Draw it:
( ( TDEStyle & ) ( kapp - > style ( ) ) ) . drawTDEStylePrimitive ( TDEStyle : : KPE_ListViewExpander ,
painter ,
basket - > viewport ( ) ,
TQRect ( x , y , 9 , 9 ) ,
cg ,
( expand ? TQStyle : : Style_On : TQStyle : : Style_Off ) ) ;
// Else, TQStyle does not provide easy way to do so (if it's doable at all...)
// So, I'm drawing it myself my immitating Plastik (pretty style)...
// After all, the note/group handles are all non-TQStyle aware so that doesn't matter if the expander is a custom one too.
} else {
int width = EXPANDER_WIDTH ;
int height = EXPANDER_HEIGHT ;
const TQColorGroup & cg = basket - > colorGroup ( ) ;
// Fill white area:
painter - > fillRect ( x + 1 , y + 1 , width - 2 , height - 2 , cg . base ( ) ) ;
// Draw contour lines:
painter - > setPen ( cg . dark ( ) ) ;
painter - > drawLine ( x + 2 , y , x + width - 3 , y ) ;
painter - > drawLine ( x + 2 , y + height - 1 , x + width - 3 , y + height - 1 ) ;
painter - > drawLine ( x , y + 2 , x , y + height - 3 ) ;
painter - > drawLine ( x + width - 1 , y + 2 , x + width - 1 , y + height - 3 ) ;
// Draw edge points:
painter - > drawPoint ( x + 1 , y + 1 ) ;
painter - > drawPoint ( x + width - 2 , y + 1 ) ;
painter - > drawPoint ( x + 1 , y + height - 2 ) ;
painter - > drawPoint ( x + width - 2 , y + height - 2 ) ;
// Draw anti-aliased points:
painter - > setPen ( Tools : : mixColor ( cg . dark ( ) , background ) ) ;
painter - > drawPoint ( x + 1 , y ) ;
painter - > drawPoint ( x + width - 2 , y ) ;
painter - > drawPoint ( x , y + 1 ) ;
painter - > drawPoint ( x + width - 1 , y + 1 ) ;
painter - > drawPoint ( x , y + height - 2 ) ;
painter - > drawPoint ( x + width - 1 , y + height - 2 ) ;
painter - > drawPoint ( x + 1 , y + height - 1 ) ;
painter - > drawPoint ( x + width - 2 , y + height - 1 ) ;
// Draw plus / minus:
painter - > setPen ( cg . text ( ) ) ;
painter - > drawLine ( x + 2 , y + height / 2 , x + width - 3 , y + height / 2 ) ;
if ( expand )
painter - > drawLine ( x + width / 2 , y + 2 , x + width / 2 , y + height - 3 ) ;
}
}
TQColor expanderBackground ( int height , int y , const TQColor & foreground )
{
// We will divide height per two, substract one and use that below a division bar:
// To avoid division by zero error, height should be bigger than 3.
// And to avoid y errors or if y is on the borders, we return the border color: the background color.
if ( height < = 3 | | y < = 0 | | y > = height - 1 )
return foreground ;
TQColor dark = foreground . dark ( 110 ) ; // 1/1.1 of brightness
TQColor light = foreground . light ( 150 ) ; // 50% brighter
int h1 , h2 , s1 , s2 , v1 , v2 ;
int ng ;
if ( y < = ( height - 2 ) / 2 ) {
light . hsv ( & h1 , & s1 , & v1 ) ;
dark . hsv ( & h2 , & s2 , & v2 ) ;
ng = ( height - 2 ) / 2 ;
y - = 1 ;
} else {
dark . hsv ( & h1 , & s1 , & v1 ) ;
foreground . hsv ( & h2 , & s2 , & v2 ) ;
ng = ( height - 2 ) - ( height - 2 ) / 2 ;
y - = 1 + ( height - 2 ) / 2 ;
}
return TQColor ( h1 + ( ( h2 - h1 ) * y ) / ( ng - 1 ) ,
s1 + ( ( s2 - s1 ) * y ) / ( ng - 1 ) ,
v1 + ( ( v2 - v1 ) * y ) / ( ng - 1 ) , TQColor : : Hsv ) ;
}
void Note : : drawHandle ( TQPainter * painter , int x , int y , int width , int height , const TQColor & background , const TQColor & foreground )
{
TQPen backgroundPen ( background ) ;
TQPen foregroundPen ( foreground ) ;
TQColor dark = foreground . dark ( 110 ) ; // 1/1.1 of brightness
TQColor light = foreground . light ( 150 ) ; // 50% brighter
// Draw the surrounding rectangle:
painter - > setPen ( foregroundPen ) ;
painter - > drawLine ( 0 , 0 , width - 1 , 0 ) ;
painter - > drawLine ( 0 , 0 , 0 , height - 1 ) ;
painter - > drawLine ( width - 1 , 0 , width - 1 , height - 1 ) ;
painter - > drawLine ( 0 , height - 1 , width - 1 , height - 1 ) ;
// Draw the gradients:
drawGradient ( painter , light , dark , 1 + x , 1 + y , width - 2 , ( height - 2 ) / 2 , /*sunken=*/ false , /*horz=*/ true , /*flat=*/ false ) ;
drawGradient ( painter , dark , foreground , 1 + x , 1 + y + ( height - 2 ) / 2 , width - 2 , ( height - 2 ) - ( height - 2 ) / 2 , /*sunken=*/ false , /*horz=*/ true , /*flat=*/ false ) ;
// Round the top corner with background color:
painter - > setPen ( backgroundPen ) ;
painter - > drawLine ( 0 , 0 , 0 , 3 ) ;
painter - > drawLine ( 1 , 0 , 3 , 0 ) ;
painter - > drawPoint ( 1 , 1 ) ;
// Round the bottom corner with background color:
painter - > drawLine ( 0 , height - 1 , 0 , height - 4 ) ;
painter - > drawLine ( 1 , height - 1 , 3 , height - 1 ) ;
painter - > drawPoint ( 1 , height - 2 ) ;
// Surrounding line of the rounded top-left corner:
painter - > setPen ( foregroundPen ) ;
painter - > drawLine ( 1 , 2 , 1 , 3 ) ;
painter - > drawLine ( 2 , 1 , 3 , 1 ) ;
// Anti-aliased rounded top corner (1/2):
painter - > setPen ( Tools : : mixColor ( foreground , background ) ) ;
painter - > drawPoint ( 0 , 3 ) ;
painter - > drawPoint ( 3 , 0 ) ;
// Anti-aliased rounded bottom corner:
painter - > drawPoint ( 0 , height - 4 ) ;
painter - > drawPoint ( 3 , height - 1 ) ;
// Anti-aliased rounded top corner (2/2):
painter - > setPen ( Tools : : mixColor ( foreground , light ) ) ;
painter - > drawPoint ( 2 , 2 ) ;
// Draw the grips:
int xGrips = 4 ;
int marginedHeight = ( height * 80 / 100 ) ; // 10% empty on top, and 10% empty on bottom, so 20% of the height should be empty of any grip, and 80% should be in the grips
int nbGrips = ( marginedHeight - 3 ) / 6 ;
if ( nbGrips < 2 )
nbGrips = 2 ;
int yGrips = ( height + 1 - nbGrips * 6 - 3 ) / 2 ; // +1 to avoid rounding errors, -nbGrips*6-3 the size of the grips
TQColor darker = foreground . dark ( 130 ) ;
TQColor lighter = foreground . light ( 130 ) ;
for ( int i = 0 ; i < nbGrips ; + + i ) {
/// Dark color:
painter - > setPen ( darker ) ;
// Top-left point:
painter - > drawPoint ( xGrips , yGrips ) ;
painter - > drawPoint ( xGrips + 1 , yGrips ) ;
painter - > drawPoint ( xGrips , yGrips + 1 ) ;
// Bottom-right point:
painter - > drawPoint ( xGrips + 4 , yGrips + 3 ) ;
painter - > drawPoint ( xGrips + 5 , yGrips + 3 ) ;
painter - > drawPoint ( xGrips + 4 , yGrips + 4 ) ;
/// Light color:
painter - > setPen ( lighter ) ;
// Top-left point:
painter - > drawPoint ( xGrips + 1 , yGrips + 1 ) ;
// Bottom-right point:
painter - > drawPoint ( xGrips + 5 , yGrips + 4 ) ;
yGrips + = 6 ;
}
// The remaining point:
painter - > setPen ( darker ) ;
painter - > drawPoint ( xGrips , yGrips ) ;
painter - > drawPoint ( xGrips + 1 , yGrips ) ;
painter - > drawPoint ( xGrips , yGrips + 1 ) ;
painter - > setPen ( lighter ) ;
painter - > drawPoint ( xGrips + 1 , yGrips + 1 ) ;
}
void Note : : drawResizer ( TQPainter * painter , int x , int y , int width , int height , const TQColor & background , const TQColor & foreground , bool rounded )
{
TQPen backgroundPen ( background ) ;
TQPen foregroundPen ( foreground ) ;
TQColor dark = foreground . dark ( 110 ) ; // 1/1.1 of brightness
TQColor light = foreground . light ( 150 ) ; // 50% brighter
TQColor midLight = foreground . light ( 105 ) ; // 5% brighter
// Draw the surrounding rectangle:
painter - > setPen ( foregroundPen ) ;
painter - > drawRect ( 0 , 0 , width , height ) ;
// Draw the gradients:
drawGradient ( painter , light , dark , 1 + x , 1 + y , width - 2 , ( height - 2 ) / 2 , /*sunken=*/ false , /*horz=*/ true , /*flat=*/ false ) ;
drawGradient ( painter , dark , foreground , 1 + x , 1 + y + ( height - 2 ) / 2 , width - 2 , ( height - 2 ) - ( height - 2 ) / 2 , /*sunken=*/ false , /*horz=*/ true , /*flat=*/ false ) ;
if ( rounded ) {
// Round the top corner with background color:
painter - > setPen ( backgroundPen ) ;
painter - > drawLine ( width - 1 , 0 , width - 3 , 0 ) ;
painter - > drawLine ( width - 1 , 1 , width - 1 , 2 ) ;
painter - > drawPoint ( width - 2 , 1 ) ;
// Round the bottom corner with background color:
painter - > drawLine ( width - 1 , height - 1 , width - 1 , height - 4 ) ;
painter - > drawLine ( width - 2 , height - 1 , width - 4 , height - 1 ) ;
painter - > drawPoint ( width - 2 , height - 2 ) ;
// Surrounding line of the rounded top-left corner:
painter - > setPen ( foregroundPen ) ;
painter - > drawLine ( width - 2 , 2 , width - 2 , 3 ) ;
painter - > drawLine ( width - 3 , 1 , width - 4 , 1 ) ;
// Anti-aliased rounded top corner (1/2):
painter - > setPen ( Tools : : mixColor ( foreground , background ) ) ;
painter - > drawPoint ( width - 1 , 3 ) ;
painter - > drawPoint ( width - 4 , 0 ) ;
// Anti-aliased rounded bottom corner:
painter - > drawPoint ( width - 1 , height - 4 ) ;
painter - > drawPoint ( width - 4 , height - 1 ) ;
// Anti-aliased rounded top corner (2/2):
painter - > setPen ( Tools : : mixColor ( foreground , light ) ) ;
painter - > drawPoint ( width - 3 , 2 ) ;
}
// Draw the arows:
int xArrow = 2 ;
int hMargin = 9 ;
int countArrows = ( height > = hMargin * 4 + 6 * 3 ? 3 : ( height > = hMargin * 3 + 6 * 2 ? 2 : 1 ) ) ;
TQColor darker = foreground . dark ( 130 ) ;
TQColor lighter = foreground . light ( 130 ) ;
for ( int i = 0 ; i < countArrows ; + + i ) {
int yArrow ;
switch ( countArrows ) {
default :
case 1 : yArrow = ( height - 6 ) / 2 ; break ;
case 2 : yArrow = ( i = = 1 ? hMargin : height - hMargin - 6 ) ; break ;
case 3 : yArrow = ( i = = 1 ? hMargin : ( i = = 2 ? ( height - 6 ) / 2 : height - hMargin - 6 ) ) ; break ;
}
/// Dark color:
painter - > setPen ( darker ) ;
// Left arrow:
painter - > drawLine ( xArrow , yArrow + 2 , xArrow + 2 , yArrow ) ;
painter - > drawLine ( xArrow , yArrow + 2 , xArrow + 2 , yArrow + 4 ) ;
// Right arrow:
painter - > drawLine ( width - 1 - xArrow , yArrow + 2 , width - 1 - xArrow - 2 , yArrow ) ;
painter - > drawLine ( width - 1 - xArrow , yArrow + 2 , width - 1 - xArrow - 2 , yArrow + 4 ) ;
/// Light color:
painter - > setPen ( lighter ) ;
// Left arrow:
painter - > drawLine ( xArrow , yArrow + 2 + 1 , xArrow + 2 , yArrow + 1 ) ;
painter - > drawLine ( xArrow , yArrow + 2 + 1 , xArrow + 2 , yArrow + 4 + 1 ) ;
// Right arrow:
painter - > drawLine ( width - 1 - xArrow , yArrow + 2 + 1 , width - 1 - xArrow - 2 , yArrow + 1 ) ;
painter - > drawLine ( width - 1 - xArrow , yArrow + 2 + 1 , width - 1 - xArrow - 2 , yArrow + 4 + 1 ) ;
}
}
void Note : : drawInactiveResizer ( TQPainter * painter , int x , int y , int height , const TQColor & background , bool column )
{
// If background color is too dark, we compute a lighter color instead of a darker:
TQColor darkBgColor = ( Tools : : tooDark ( background ) ? background . light ( 120 ) : background . dark ( 105 ) ) ;
if ( column ) {
int halfWidth = RESIZER_WIDTH / 2 ;
drawGradient ( painter , darkBgColor , background , x , y , halfWidth , height , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
drawGradient ( painter , background , darkBgColor , halfWidth , y , RESIZER_WIDTH - halfWidth , height , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
} else
drawGradient ( painter , darkBgColor , background , x , y , RESIZER_WIDTH , height , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
}
# include <tqimage.h>
# include <kimageeffect.h>
/* type: 1: topLeft
* 2 : bottomLeft
* 3 : topRight
* 4 : bottomRight
* 5 : fourCorners
* 6 : noteInsideAndOutsideCorners
* ( x , y ) relate to the painter origin
* ( width , height ) only used for 5 : fourCorners type
*/
void Note : : drawRoundings ( TQPainter * painter , int x , int y , int type , int width , int height )
{
int right ;
switch ( type ) {
case 1 :
x + = this - > x ( ) ;
y + = this - > y ( ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y , 4 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + 1 , 2 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + 2 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + 3 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
break ;
case 2 :
x + = this - > x ( ) ;
y + = this - > y ( ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y - 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + 1 , 2 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + 2 , 4 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
break ;
case 3 :
right = rightLimit ( ) ;
x + = right ;
y + = this - > y ( ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x - 1 , y , 4 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 1 , y + 1 , 2 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 2 , y + 2 , 1 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 2 , y + 3 , 1 , 1 ) , right , this - > y ( ) ) ;
break ;
case 4 :
right = rightLimit ( ) ;
x + = right ;
y + = this - > y ( ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 2 , y - 1 , 1 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 2 , y , 1 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + 1 , y + 1 , 2 , 1 ) , right , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x - 1 , y + 2 , 4 , 1 ) , right , this - > y ( ) ) ;
break ;
case 5 :
// First make sure the corners are white (depending on the widget style):
painter - > setPen ( basket ( ) - > backgroundColor ( ) ) ;
painter - > drawPoint ( x , y ) ;
painter - > drawPoint ( x + width - 1 , y ) ;
painter - > drawPoint ( x + width - 1 , y + height - 1 ) ;
painter - > drawPoint ( x , y + height - 1 ) ;
// And then blend corners:
x + = this - > x ( ) ;
y + = this - > y ( ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 1 , y , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 1 , y + height - 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x , y + height - 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
break ;
case 6 :
x + = this - > x ( ) ;
y + = this - > y ( ) ;
//if (!isSelected()) {
// Inside left corners:
basket ( ) - > blendBackground ( * painter , TQRect ( x + HANDLE_WIDTH + 1 , y + 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + HANDLE_WIDTH , y + 2 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + HANDLE_WIDTH + 1 , y + height - 2 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + HANDLE_WIDTH , y + height - 3 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
// Inside right corners:
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 4 , y + 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 3 , y + 2 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 4 , y + height - 2 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 3 , y + height - 3 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
//}
// Outside right corners:
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 1 , y , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
basket ( ) - > blendBackground ( * painter , TQRect ( x + width - 1 , y + height - 1 , 1 , 1 ) , this - > x ( ) , this - > y ( ) ) ;
break ;
}
}
/// Blank Spaces Drawing:
void Note : : setOnTop ( bool onTop )
{
m_onTop = onTop ;
Note * note = firstChild ( ) ;
while ( note ) {
note - > setOnTop ( onTop ) ;
note = note - > next ( ) ;
}
}
void substractRectOnAreas ( const TQRect & rectToSubstract , TQValueList < TQRect > & areas , bool andRemove )
{
for ( TQValueList < TQRect > : : iterator it = areas . begin ( ) ; it ! = areas . end ( ) ; ) {
TQRect & rect = * it ;
// Split the rectangle if it intersects with rectToSubstract:
if ( rect . intersects ( rectToSubstract ) ) {
// Create the top rectangle:
if ( rectToSubstract . top ( ) > rect . top ( ) ) {
areas . insert ( it , TQRect ( rect . left ( ) , rect . top ( ) , rect . width ( ) , rectToSubstract . top ( ) - rect . top ( ) ) ) ;
rect . setTop ( rectToSubstract . top ( ) ) ;
}
// Create the bottom rectangle:
if ( rectToSubstract . bottom ( ) < rect . bottom ( ) ) {
areas . insert ( it , TQRect ( rect . left ( ) , rectToSubstract . bottom ( ) + 1 , rect . width ( ) , rect . bottom ( ) - rectToSubstract . bottom ( ) ) ) ;
rect . setBottom ( rectToSubstract . bottom ( ) ) ;
}
// Create the left rectangle:
if ( rectToSubstract . left ( ) > rect . left ( ) ) {
areas . insert ( it , TQRect ( rect . left ( ) , rect . top ( ) , rectToSubstract . left ( ) - rect . left ( ) , rect . height ( ) ) ) ;
rect . setLeft ( rectToSubstract . left ( ) ) ;
}
// Create the right rectangle:
if ( rectToSubstract . right ( ) < rect . right ( ) ) {
areas . insert ( it , TQRect ( rectToSubstract . right ( ) + 1 , rect . top ( ) , rect . right ( ) - rectToSubstract . right ( ) , rect . height ( ) ) ) ;
rect . setRight ( rectToSubstract . right ( ) ) ;
}
// Remove the rectangle if it's entirely contained:
if ( andRemove & & rectToSubstract . contains ( rect ) )
it = areas . remove ( it ) ;
else
+ + it ;
} else
+ + it ;
}
}
void Note : : recomputeAreas ( )
{
// Initialize the areas with the note rectangle(s):
m_areas . clear ( ) ;
m_areas . append ( visibleRect ( ) ) ;
if ( hasResizer ( ) )
m_areas . append ( resizerRect ( ) ) ;
// Cut the areas where other notes are on top of this note:
Note * note = basket ( ) - > firstNote ( ) ;
bool noteIsAfterThis = false ;
while ( note ) {
noteIsAfterThis = recomputeAreas ( note , noteIsAfterThis ) ;
note = note - > next ( ) ;
}
}
bool Note : : recomputeAreas ( Note * note , bool noteIsAfterThis )
{
if ( note = = this )
noteIsAfterThis = true ;
// Only compute overlapping of notes AFTER this, or ON TOP this:
//else if ( note->matching() && noteIsAfterThis && (!isOnTop() || (isOnTop() && note->isOnTop())) || (!isOnTop() && note->isOnTop()) ) {
else if ( note - > matching ( ) & & noteIsAfterThis & & ( ! ( isOnTop ( ) | | isEditing ( ) ) | | ( ( isOnTop ( ) | | isEditing ( ) ) & & ( note - > isOnTop ( ) | | note - > isEditing ( ) ) ) ) | |
( ! ( isOnTop ( ) | | isEditing ( ) ) & & ( note - > isOnTop ( ) | | note - > isEditing ( ) ) ) ) {
//if (!(isSelected() && !note->isSelected())) { // FIXME: FIXME: FIXME: FIXME: This last condition was added LATE, so we should look if it's ALWAYS good:
substractRectOnAreas ( note - > visibleRect ( ) , m_areas , true ) ;
if ( note - > hasResizer ( ) )
substractRectOnAreas ( note - > resizerRect ( ) , m_areas , true ) ;
//}
}
if ( note - > isGroup ( ) ) {
Note * child = note - > firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( note - > showSubNotes ( ) | | first ) & & note - > matching ( ) )
noteIsAfterThis = recomputeAreas ( child , noteIsAfterThis ) ;
child = child - > next ( ) ;
first = false ;
}
}
return noteIsAfterThis ;
}
bool Note : : isEditing ( )
{
return basket ( ) - > editedNote ( ) = = this ;
}
void Note : : getGradientColors ( const TQColor & originalBackground , TQColor * colorTop , TQColor * colorBottom )
{
bool wasTooDark = Tools : : tooDark ( originalBackground ) ;
if ( wasTooDark ) {
* colorTop = originalBackground ;
* colorBottom = originalBackground . light ( 120 ) ;
} else {
* colorTop = originalBackground . dark ( 105 ) ;
* colorBottom = originalBackground ;
}
}
/* Drawing policy:
* = = = = = = = = = = = = = =
* - Draw the note on a pixmap and then draw the pixmap on screen is faster and flicker - free , rather than drawing directly on screen
* - The next time the pixmap can be directly redrawn on screen without ( relatively low , for small texts ) time - consuming text - drawing
* - To keep memory footprint low , we can destruct the bufferPixmap because redrawing it offscreen and applying it onscreen is nearly as fast as just drawing the pixmap onscreen
* - But as drawing the pixmap offscreen is little time consuming we can keep last visible notes buffered and then the redraw of the entire window is INSTANTANEOUS
* - We keep bufferized note / group draws BUT NOT the resizer : such objects are small and fast to draw , so we don ' t complexify code for that
*/
void Note : : draw ( TQPainter * painter , const TQRect & clipRect )
{
if ( ! matching ( ) )
return ;
/** Paint childs: */
if ( isGroup ( ) ) {
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > draw ( painter , clipRect ) ;
child = child - > next ( ) ;
first = false ;
}
}
TQRect myRect ( x ( ) , y ( ) , width ( ) , height ( ) ) ;
/** Paint the resizer if needed: */
if ( hasResizer ( ) ) {
int right = rightLimit ( ) ;
TQRect resizerRect ( right , y ( ) , RESIZER_WIDTH , resizerHeight ( ) ) ;
if ( resizerRect . intersects ( clipRect ) ) {
// Prepare to draw the resizer:
TQPixmap pixmap ( RESIZER_WIDTH , resizerHeight ( ) ) ;
TQPainter painter2 ( & pixmap ) ;
// Draw gradient or resizer:
if ( m_hovered & & m_hoveredZone = = Resizer ) {
TQColor baseColor ( basket ( ) - > backgroundColor ( ) ) ;
TQColor highColor ( TDEGlobalSettings : : highlightColor ( ) ) ;
drawResizer ( & painter2 , 0 , 0 , RESIZER_WIDTH , resizerHeight ( ) , baseColor , highColor , /*rounded=*/ ! isColumn ( ) ) ;
if ( ! isColumn ( ) ) {
drawRoundings ( & painter2 , RESIZER_WIDTH - 3 , 0 , /*type=*/ 3 ) ;
drawRoundings ( & painter2 , RESIZER_WIDTH - 3 , resizerHeight ( ) - 3 , /*type=*/ 4 ) ;
}
} else {
drawInactiveResizer ( & painter2 , /*x=*/ 0 , /*y=*/ 0 , /*height=*/ resizerHeight ( ) , basket ( ) - > backgroundColor ( ) , isColumn ( ) ) ;
basket ( ) - > blendBackground ( painter2 , resizerRect ) ;
}
// Draw inserter:
if ( basket ( ) - > inserterShown ( ) & & resizerRect . intersects ( basket ( ) - > inserterRect ( ) ) )
basket ( ) - > drawInserter ( painter2 , right , y ( ) ) ;
// Draw selection rect:
if ( basket ( ) - > isSelecting ( ) & & resizerRect . intersects ( basket ( ) - > selectionRect ( ) ) ) {
TQRect selectionRect = basket ( ) - > selectionRect ( ) ;
selectionRect . moveBy ( - right , - y ( ) ) ;
TQRect selectionRectInside ( selectionRect . x ( ) + 1 , selectionRect . y ( ) + 1 , selectionRect . width ( ) - 2 , selectionRect . height ( ) - 2 ) ;
if ( selectionRectInside . width ( ) > 0 & & selectionRectInside . height ( ) > 0 ) {
TQColor insideColor = basket ( ) - > selectionRectInsideColor ( ) ;
TQColor darkInsideColor ( insideColor . dark ( 105 ) ) ;
painter2 . setClipRect ( selectionRectInside ) ;
if ( isColumn ( ) ) {
int halfWidth = RESIZER_WIDTH / 2 ;
drawGradient ( & painter2 , darkInsideColor , insideColor , 0 , 0 , halfWidth , resizerHeight ( ) , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
drawGradient ( & painter2 , insideColor , darkInsideColor , halfWidth , 0 , RESIZER_WIDTH - halfWidth , resizerHeight ( ) , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
} else
drawGradient ( & painter2 , darkInsideColor , insideColor , 0 , 0 , RESIZER_WIDTH , resizerHeight ( ) , /*sunken=*/ false , /*horz=*/ false , /*flat=*/ false ) ;
painter2 . setClipping ( false ) ;
selectionRectInside . moveBy ( right , y ( ) ) ;
basket ( ) - > blendBackground ( painter2 , selectionRectInside , right , y ( ) , false ) ;
}
painter2 . setPen ( TDEGlobalSettings : : highlightColor ( ) . dark ( ) ) ;
painter2 . drawRect ( selectionRect ) ;
painter2 . setPen ( Tools : : mixColor ( TDEGlobalSettings : : highlightColor ( ) . dark ( ) , basket ( ) - > backgroundColor ( ) ) ) ;
painter2 . drawPoint ( selectionRect . topLeft ( ) ) ;
painter2 . drawPoint ( selectionRect . topRight ( ) ) ;
painter2 . drawPoint ( selectionRect . bottomLeft ( ) ) ;
painter2 . drawPoint ( selectionRect . bottomRight ( ) ) ;
}
// Draw on screen:
painter2 . end ( ) ;
/** Compute visible areas: */
if ( ! m_computedAreas )
recomputeAreas ( ) ;
if ( m_areas . isEmpty ( ) )
return ;
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & rect = * it ;
painter - > drawPixmap ( rect . x ( ) , rect . y ( ) , pixmap , rect . x ( ) - right , rect . y ( ) - y ( ) , rect . width ( ) , rect . height ( ) ) ;
}
}
}
/** Then, draw the note/group ONLY if needed: */
if ( ! myRect . intersects ( clipRect ) )
return ;
/** Compute visible areas: */
if ( ! m_computedAreas )
recomputeAreas ( ) ;
if ( m_areas . isEmpty ( ) )
return ;
/** Directly draw pixmap on screen if it is already buffered: */
if ( isBufferized ( ) ) {
drawBufferOnScreen ( painter , m_bufferedPixmap ) ;
return ;
}
/** Initialise buffer painter: */
m_bufferedPixmap . resize ( width ( ) , height ( ) ) ;
TQPainter painter2 ( & m_bufferedPixmap ) ;
/** Initialise colors: */
TQColor baseColor ( basket ( ) - > backgroundColor ( ) ) ;
TQColor highColor ( TDEGlobalSettings : : highlightColor ( ) ) ;
TQColor midColor = Tools : : mixColor ( baseColor , highColor ) ;
/** Initialise brushs and pens: */
TQBrush baseBrush ( baseColor ) ;
TQBrush highBrush ( highColor ) ;
TQPen basePen ( baseColor ) ;
TQPen highPen ( highColor ) ;
TQPen midPen ( midColor ) ;
/** Figure out the state of the note: */
bool hovered = m_hovered & & m_hoveredZone ! = TopInsert & & m_hoveredZone ! = BottomInsert & & m_hoveredZone ! = Resizer ;
/** And then draw the group: */
if ( isGroup ( ) ) {
// Draw background or handle:
if ( hovered ) {
drawHandle ( & painter2 , 0 , 0 , width ( ) , height ( ) , baseColor , highColor ) ;
drawRoundings ( & painter2 , 0 , 0 , /*type=*/ 1 ) ;
drawRoundings ( & painter2 , 0 , height ( ) - 3 , /*type=*/ 2 ) ;
} else {
painter2 . fillRect ( 0 , 0 , width ( ) , height ( ) , baseBrush ) ;
basket ( ) - > blendBackground ( painter2 , myRect , - 1 , - 1 , /*opaque=*/ true ) ;
}
// Draw expander:
int yExp = yExpander ( ) ;
drawExpander ( & painter2 , NOTE_MARGIN , yExp , ( hovered ? expanderBackground ( height ( ) , yExp + EXPANDER_HEIGHT / 2 , highColor ) : baseColor ) , m_isFolded , basket ( ) ) ;
// Draw expander rounded edges:
if ( hovered ) {
TQColor color1 = expanderBackground ( height ( ) , yExp , highColor ) ;
TQColor color2 = expanderBackground ( height ( ) , yExp + EXPANDER_HEIGHT - 1 , highColor ) ;
painter2 . setPen ( color1 ) ;
painter2 . drawPoint ( NOTE_MARGIN , yExp ) ;
painter2 . drawPoint ( NOTE_MARGIN + 9 - 1 , yExp ) ;
painter2 . setPen ( color2 ) ;
painter2 . drawPoint ( NOTE_MARGIN , yExp + 9 - 1 ) ;
painter2 . drawPoint ( NOTE_MARGIN + 9 - 1 , yExp + 9 - 1 ) ;
} else
drawRoundings ( & painter2 , NOTE_MARGIN , yExp , /*type=*/ 5 , 9 , 9 ) ;
// Draw on screen:
painter2 . end ( ) ;
drawBufferOnScreen ( painter , m_bufferedPixmap ) ;
return ;
}
/** Or draw the note: */
// What are the background colors:
TQColor background = basket ( ) - > backgroundColor ( ) ;
if ( isSelected ( ) )
if ( m_computedState . backgroundColor ( ) . isValid ( ) )
background = Tools : : mixColor ( Tools : : mixColor ( m_computedState . backgroundColor ( ) , TDEGlobalSettings : : highlightColor ( ) ) , TDEGlobalSettings : : highlightColor ( ) ) ;
else
background = TDEGlobalSettings : : highlightColor ( ) ;
else if ( m_computedState . backgroundColor ( ) . isValid ( ) )
background = m_computedState . backgroundColor ( ) ;
TQColor bgColor ;
TQColor darkBgColor ;
getGradientColors ( background , & darkBgColor , & bgColor ) ;
// Draw background (color, gradient and pixmap):
drawGradient ( & painter2 , bgColor , darkBgColor , 0 , 0 , width ( ) , height ( ) , /*sunken=*/ ! hovered , /*horz=*/ true , /*flat=*/ false ) ;
if ( ! hovered ) {
painter2 . setPen ( Tools : : mixColor ( bgColor , darkBgColor ) ) ;
painter2 . drawLine ( 0 , height ( ) - 1 , width ( ) , height ( ) - 1 ) ;
}
basket ( ) - > blendBackground ( painter2 , myRect ) ;
if ( hovered ) {
// Top/Bottom lines:
painter2 . setPen ( highPen ) ;
painter2 . drawLine ( 0 , height ( ) - 1 , width ( ) , height ( ) - 1 ) ;
painter2 . drawLine ( 0 , 0 , width ( ) , 0 ) ;
// The handle:
drawHandle ( & painter2 , 0 , 0 , HANDLE_WIDTH , height ( ) , baseColor , highColor ) ;
drawRoundings ( & painter2 , 0 , 0 , /*type=*/ 1 ) ;
drawRoundings ( & painter2 , 0 , height ( ) - 3 , /*type=*/ 2 ) ;
// Round handle-right-side border:
painter2 . setPen ( highPen ) ;
painter2 . drawPoint ( HANDLE_WIDTH , 1 ) ;
painter2 . drawPoint ( HANDLE_WIDTH , height ( ) - 2 ) ;
// Light handle top-right round corner:
painter2 . setPen ( TQPen ( highColor . light ( 150 ) ) ) ;
painter2 . drawPoint ( HANDLE_WIDTH - 1 , 1 ) ;
// Handle anti-aliased rounded handle-right-side corners:
TQColor insideMidColor = Tools : : mixColor ( bgColor , highColor ) ;
painter2 . setPen ( insideMidColor ) ;
// Left inside round corners:
painter2 . drawPoint ( HANDLE_WIDTH + 1 , 1 ) ;
painter2 . drawPoint ( HANDLE_WIDTH , 2 ) ;
painter2 . drawPoint ( HANDLE_WIDTH + 1 , height ( ) - 2 ) ;
painter2 . drawPoint ( HANDLE_WIDTH , height ( ) - 3 ) ;
// Right inside round corners:
painter2 . drawPoint ( width ( ) - 4 , 1 ) ;
painter2 . drawPoint ( width ( ) - 3 , 2 ) ;
painter2 . drawPoint ( width ( ) - 4 , height ( ) - 2 ) ;
painter2 . drawPoint ( width ( ) - 3 , height ( ) - 3 ) ;
// Right rounded edge:
painter2 . setPen ( highPen ) ;
painter2 . fillRect ( width ( ) - 2 , 0 , 2 , height ( ) , highBrush ) ;
painter2 . drawPoint ( width ( ) - 3 , 1 ) ;
painter2 . drawPoint ( width ( ) - 3 , height ( ) - 2 ) ;
// Right anti-aliased rounded edge:
painter2 . setPen ( midPen ) ;
painter2 . drawPoint ( width ( ) - 1 , 0 ) ;
painter2 . drawPoint ( width ( ) - 1 , height ( ) - 1 ) ;
// Blend background pixmap:
drawRoundings ( & painter2 , 0 , 0 , /*type=*/ 6 , width ( ) , height ( ) ) ;
}
if ( isFocused ( ) ) {
TQRect focusRect ( HANDLE_WIDTH , NOTE_MARGIN - 1 , width ( ) - HANDLE_WIDTH - 2 , height ( ) - 2 * NOTE_MARGIN + 2 ) ;
painter2 . drawWinFocusRect ( focusRect ) ;
}
// Draw the Emblems:
int yIcon = ( height ( ) - EMBLEM_SIZE ) / 2 ;
int xIcon = HANDLE_WIDTH + NOTE_MARGIN ;
for ( State : : List : : Iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it ) {
if ( ! ( * it ) - > emblem ( ) . isEmpty ( ) ) {
TQPixmap stateEmblem = kapp - > iconLoader ( ) - > loadIcon ( ( * it ) - > emblem ( ) , TDEIcon : : NoGroup , 16 , TDEIcon : : DefaultState , 0L , false ) ;
painter2 . drawPixmap ( xIcon , yIcon , stateEmblem ) ;
xIcon + = NOTE_MARGIN + EMBLEM_SIZE ;
}
}
// Determine the colors (for the richText drawing) and the text color (for the tags arrow too):
TQColorGroup cg ( basket ( ) - > colorGroup ( ) ) ;
cg . setColor ( TQColorGroup : : Text , ( m_computedState . textColor ( ) . isValid ( ) ? m_computedState . textColor ( ) : basket ( ) - > textColor ( ) ) ) ;
cg . setColor ( TQColorGroup : : Background , bgColor ) ;
if ( isSelected ( ) )
cg . setColor ( TQColorGroup : : Text , TDEGlobalSettings : : highlightedTextColor ( ) ) ;
// Draw the Tags Arrow:
if ( hovered ) {
TQColor textColor = cg . color ( TQColorGroup : : Text ) ;
TQColor light = Tools : : mixColor ( textColor , bgColor ) ;
TQColor mid = Tools : : mixColor ( textColor , light ) ;
painter2 . setPen ( light ) ; //TQPen(basket()->colorGroup().dark().light(150)));
painter2 . drawLine ( xIcon , yIcon + 6 , xIcon + 4 , yIcon + 6 ) ;
painter2 . setPen ( mid ) ; //TQPen(basket()->colorGroup().dark()));
painter2 . drawLine ( xIcon + 1 , yIcon + 7 , xIcon + 3 , yIcon + 7 ) ;
painter2 . setPen ( textColor ) ; //TQPen(basket()->colorGroup().foreground()));
painter2 . drawPoint ( xIcon + 2 , yIcon + 8 ) ;
} else if ( m_haveInvisibleTags ) {
painter2 . setPen ( cg . color ( TQColorGroup : : Text ) /*TQPen(basket()->colorGroup().foreground())*/ ) ;
painter2 . drawPoint ( xIcon , yIcon + 7 ) ;
painter2 . drawPoint ( xIcon + 2 , yIcon + 7 ) ;
painter2 . drawPoint ( xIcon + 4 , yIcon + 7 ) ;
}
// Draw content:
// Optimization: do not draw text notes because it is time consuming and should be done nearly at each tetx modification.
if ( basket ( ) - > editedNote ( ) ! = this | | basket ( ) - > editedNote ( ) - > content ( ) - > type ( ) ! = NoteType : : Html ) {
painter2 . translate ( contentX ( ) , NOTE_MARGIN ) ;
painter2 . setFont ( m_computedState . font ( painter2 . font ( ) ) ) ;
m_content - > paint ( & painter2 , width ( ) - contentX ( ) - NOTE_MARGIN , height ( ) - 2 * NOTE_MARGIN , cg , ! m_computedState . textColor ( ) . isValid ( ) , isSelected ( ) , hovered ) ;
}
// Draw on screen:
painter2 . end ( ) ;
drawBufferOnScreen ( painter , m_bufferedPixmap ) ;
}
void Note : : drawBufferOnScreen ( TQPainter * painter , const TQPixmap & contentPixmap )
{
for ( TQValueList < TQRect > : : iterator it = m_areas . begin ( ) ; it ! = m_areas . end ( ) ; + + it ) {
TQRect & rect = * it ;
if ( rect . x ( ) > = x ( ) + width ( ) ) // It's a rect of the resizer, don't draw it!
continue ;
// If the inserter is above the note, draw it, BUT NOT in the buffer pixmap,
// we copy the rectangle in a new pixmap, apply the inserter and then draw this new pixmap on screen:
if ( ( basket ( ) - > inserterShown ( ) & & rect . intersects ( basket ( ) - > inserterRect ( ) ) ) | |
( basket ( ) - > isSelecting ( ) & & rect . intersects ( basket ( ) - > selectionRect ( ) ) ) ) {
TQPixmap pixmap3 ( rect . width ( ) , rect . height ( ) ) ;
TQPainter painter3 ( & pixmap3 ) ;
painter3 . drawPixmap ( 0 , 0 , contentPixmap , rect . x ( ) - x ( ) , rect . y ( ) - y ( ) , rect . width ( ) , rect . height ( ) ) ;
// Draw inserter:
if ( basket ( ) - > inserterShown ( ) & & rect . intersects ( basket ( ) - > inserterRect ( ) ) )
basket ( ) - > drawInserter ( painter3 , rect . x ( ) , rect . y ( ) ) ;
// Draw selection rect:
if ( basket ( ) - > isSelecting ( ) & & rect . intersects ( basket ( ) - > selectionRect ( ) ) ) {
TQRect selectionRect = basket ( ) - > 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 ) {
bufferizeSelectionPixmap ( ) ;
selectionRectInside . moveBy ( rect . x ( ) , rect . y ( ) ) ;
TQRect rectToPaint = rect . intersect ( selectionRectInside ) ;
rectToPaint . moveBy ( - x ( ) , - y ( ) ) ;
painter3 . drawPixmap ( rectToPaint . topLeft ( ) + TQPoint ( x ( ) , y ( ) ) - rect . topLeft ( ) , m_bufferedSelectionPixmap , rectToPaint ) ;
//blendBackground(painter2, selectionRectInside, rect.x(), rect.y(), true, &m_selectedBackgroundPixmap);
}
painter3 . setPen ( TDEGlobalSettings : : highlightColor ( ) . dark ( ) ) ;
painter3 . drawRect ( selectionRect ) ;
if ( isGroup ( ) )
painter3 . setPen ( Tools : : mixColor ( TDEGlobalSettings : : highlightColor ( ) . dark ( ) , basket ( ) - > backgroundColor ( ) ) ) ;
else {
// What are the background colors:
TQColor bgColor = basket ( ) - > backgroundColor ( ) ;
if ( isSelected ( ) )
bgColor = ( m_computedState . backgroundColor ( ) . isValid ( ) ? Tools : : mixColor ( Tools : : mixColor ( m_computedState . backgroundColor ( ) , TDEGlobalSettings : : highlightColor ( ) ) , TDEGlobalSettings : : highlightColor ( ) ) : TDEGlobalSettings : : highlightColor ( ) ) ;
else if ( m_computedState . backgroundColor ( ) . isValid ( ) )
bgColor = m_computedState . backgroundColor ( ) ;
painter3 . setPen ( Tools : : mixColor ( TDEGlobalSettings : : highlightColor ( ) . dark ( ) , bgColor ) ) ;
}
painter3 . drawPoint ( selectionRect . topLeft ( ) ) ;
painter3 . drawPoint ( selectionRect . topRight ( ) ) ;
painter3 . drawPoint ( selectionRect . bottomLeft ( ) ) ;
painter3 . drawPoint ( selectionRect . bottomRight ( ) ) ;
}
painter3 . end ( ) ;
painter - > drawPixmap ( rect . x ( ) , rect . y ( ) , pixmap3 ) ;
// Else, draw the rect pixmap directly on screen:
} else
painter - > drawPixmap ( rect . x ( ) , rect . y ( ) , contentPixmap , rect . x ( ) - x ( ) , rect . y ( ) - y ( ) , rect . width ( ) , rect . height ( ) ) ;
}
}
void Note : : setContent ( NoteContent * content )
{
m_content = content ;
}
/*const */ State : : List & Note : : states ( ) const
{
return ( State : : List & ) m_states ;
}
void Note : : addState ( State * state , bool orReplace )
{
if ( ! content ( ) )
return ;
Tag * tag = state - > parentTag ( ) ;
State : : List : : iterator itStates = m_states . begin ( ) ;
// Browse all tags, see if the note has it, increment itSates if yes, and then insert the state at this position...
// For each existing tags:
for ( Tag : : List : : iterator it = Tag : : all . begin ( ) ; it ! = Tag : : all . end ( ) ; + + it ) {
// If the current tag isn't the one to assign or the current one on the note, go to the next tag:
if ( * it ! = tag & & itStates ! = m_states . end ( ) & & * it ! = ( * itStates ) - > parentTag ( ) )
continue ;
// We found the tag to insert:
if ( * it = = tag ) {
// And the note already have the tag:
if ( itStates ! = m_states . end ( ) & & * it = = ( * itStates ) - > parentTag ( ) ) {
// We replace the state if wanted:
if ( orReplace ) {
itStates = m_states . insert ( itStates , state ) ;
+ + itStates ;
m_states . remove ( itStates ) ;
recomputeStyle ( ) ;
}
} else {
m_states . insert ( itStates , state ) ;
recomputeStyle ( ) ;
}
return ;
}
// The note has this tag:
if ( itStates ! = m_states . end ( ) & & * it = = ( * itStates ) - > parentTag ( ) )
+ + itStates ;
}
}
TQFont Note : : font ( )
{
return m_computedState . font ( basket ( ) - > TQScrollView : : font ( ) ) ;
}
TQColor Note : : backgroundColor ( )
{
if ( m_computedState . backgroundColor ( ) . isValid ( ) )
return m_computedState . backgroundColor ( ) ;
else
return basket ( ) - > backgroundColor ( ) ;
}
TQColor Note : : textColor ( )
{
if ( m_computedState . textColor ( ) . isValid ( ) )
return m_computedState . textColor ( ) ;
else
return basket ( ) - > textColor ( ) ;
}
void Note : : recomputeStyle ( )
{
State : : merge ( m_states , & m_computedState , & m_emblemsCount , & m_haveInvisibleTags , basket ( ) - > backgroundColor ( ) ) ;
// unsetWidth();
if ( content ( ) )
content ( ) - > fontChanged ( ) ;
// requestRelayout(); // TODO!
}
void Note : : recomputeAllStyles ( )
{
if ( content ( ) ) // We do the merge ourself, without calling recomputeStyle(), so there is no infinite recursion:
//State::merge(m_states, &m_computedState, &m_emblemsCount, &m_haveInvisibleTags, basket()->backgroundColor());
recomputeStyle ( ) ;
else if ( isGroup ( ) )
FOR_EACH_CHILD ( child )
child - > recomputeAllStyles ( ) ;
}
bool Note : : removedStates ( const TQValueList < State * > & deletedStates )
{
bool modifiedBasket = false ;
if ( ! states ( ) . isEmpty ( ) ) {
for ( TQValueList < State * > : : const_iterator it = deletedStates . begin ( ) ; it ! = deletedStates . end ( ) ; + + it )
if ( hasState ( * it ) ) {
removeState ( * it ) ;
modifiedBasket = true ;
}
}
FOR_EACH_CHILD ( child )
if ( child - > removedStates ( deletedStates ) )
modifiedBasket = true ;
return modifiedBasket ;
}
void Note : : addTag ( Tag * tag )
{
addState ( tag - > states ( ) . first ( ) , /*but do not replace:*/ false ) ;
}
void Note : : removeState ( State * state )
{
for ( State : : List : : iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( * it = = state ) {
m_states . remove ( it ) ;
recomputeStyle ( ) ;
return ;
}
}
void Note : : removeTag ( Tag * tag )
{
for ( State : : List : : iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( ( * it ) - > parentTag ( ) = = tag ) {
m_states . remove ( it ) ;
recomputeStyle ( ) ;
return ;
}
}
void Note : : removeAllTags ( )
{
m_states . clear ( ) ;
recomputeStyle ( ) ;
}
void Note : : addTagToSelectedNotes ( Tag * tag )
{
if ( content ( ) & & isSelected ( ) )
addTag ( tag ) ;
FOR_EACH_CHILD ( child )
child - > addTagToSelectedNotes ( tag ) ;
}
void Note : : removeTagFromSelectedNotes ( Tag * tag )
{
if ( content ( ) & & isSelected ( ) ) {
if ( hasTag ( tag ) )
setWidth ( 0 ) ;
removeTag ( tag ) ;
}
FOR_EACH_CHILD ( child )
child - > removeTagFromSelectedNotes ( tag ) ;
}
void Note : : removeAllTagsFromSelectedNotes ( )
{
if ( content ( ) & & isSelected ( ) ) {
if ( m_states . count ( ) > 0 )
setWidth ( 0 ) ;
removeAllTags ( ) ;
}
FOR_EACH_CHILD ( child )
child - > removeAllTagsFromSelectedNotes ( ) ;
}
void Note : : addStateToSelectedNotes ( State * state , bool orReplace )
{
if ( content ( ) & & isSelected ( ) )
addState ( state , orReplace ) ;
FOR_EACH_CHILD ( child )
child - > addStateToSelectedNotes ( state , orReplace ) ; // TODO: Basket::addStateToSelectedNotes() does not have orReplace
}
void Note : : changeStateOfSelectedNotes ( State * state )
{
if ( content ( ) & & isSelected ( ) & & hasTag ( state - > parentTag ( ) ) )
addState ( state ) ;
FOR_EACH_CHILD ( child )
child - > changeStateOfSelectedNotes ( state ) ;
}
bool Note : : selectedNotesHaveTags ( )
{
if ( content ( ) & & isSelected ( ) & & m_states . count ( ) > 0 )
return true ;
FOR_EACH_CHILD ( child )
if ( child - > selectedNotesHaveTags ( ) )
return true ;
return false ;
}
bool Note : : hasState ( State * state )
{
for ( State : : List : : iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( * it = = state )
return true ;
return false ;
}
bool Note : : hasTag ( Tag * tag )
{
for ( State : : List : : iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( ( * it ) - > parentTag ( ) = = tag )
return true ;
return false ;
}
State * Note : : stateOfTag ( Tag * tag )
{
for ( State : : List : : iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( ( * it ) - > parentTag ( ) = = tag )
return * it ;
return 0 ;
}
State * Note : : stateForEmblemNumber ( int number )
{
int i = - 1 ;
for ( State : : List : : Iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( ! ( * it ) - > emblem ( ) . isEmpty ( ) ) {
+ + i ;
if ( i = = number )
return * it ;
}
return 0 ;
}
bool Note : : stateForTagFromSelectedNotes ( Tag * tag , State * * state )
{
if ( content ( ) & & isSelected ( ) ) {
// What state is the tag on this note?
State * stateOfTag = this - > stateOfTag ( tag ) ;
// This tag is not assigned to this note, the action will assign it, then:
if ( stateOfTag = = 0 )
* state = 0 ;
else {
// Take the LOWEST state of all the selected notes:
// Say the two selected notes have the state "Done" and "To Do".
// The first note set *state to "Done".
// When reaching the second note, we should recognize "To Do" is first in the tag states, then take it
// Because pressing the tag shortcut key should first change state before removing the tag!
if ( * state = = 0 )
* state = stateOfTag ;
else {
bool stateIsFirst = true ;
for ( State * nextState = stateOfTag - > nextState ( ) ; nextState ; nextState = nextState - > nextState ( /*cycle=*/ false ) )
if ( nextState = = * state )
stateIsFirst = false ;
if ( ! stateIsFirst )
* state = stateOfTag ;
}
}
return true ; // We encountered a selected note
}
bool encounteredSelectedNote = false ;
FOR_EACH_CHILD ( child ) {
bool encountered = child - > stateForTagFromSelectedNotes ( tag , state ) ;
if ( encountered & & * state = = 0 )
return true ;
if ( encountered )
encounteredSelectedNote = true ;
}
return encounteredSelectedNote ;
}
void Note : : inheritTagsOf ( Note * note )
{
if ( ! note | | ! content ( ) )
return ;
for ( State : : List : : iterator it = note - > states ( ) . begin ( ) ; it ! = note - > states ( ) . end ( ) ; + + it )
if ( ( * it ) - > parentTag ( ) & & ( * it ) - > parentTag ( ) - > inheritedBySiblings ( ) )
addTag ( ( * it ) - > parentTag ( ) ) ;
}
void Note : : unbufferizeAll ( )
{
unbufferize ( ) ;
if ( isGroup ( ) ) {
Note * child = firstChild ( ) ;
while ( child ) {
child - > unbufferizeAll ( ) ;
child = child - > next ( ) ;
}
}
}
void Note : : bufferizeSelectionPixmap ( )
{
if ( m_bufferedSelectionPixmap . isNull ( ) ) {
TQColor insideColor = TDEGlobalSettings : : highlightColor ( ) ;
KPixmap kpixmap ( m_bufferedPixmap ) ;
m_bufferedSelectionPixmap = KPixmapEffect : : fade ( kpixmap , 0.25 , insideColor ) ;
}
}
TQRect Note : : visibleRect ( )
{
TQValueList < TQRect > areas ;
areas . append ( rect ( ) ) ;
// When we are folding a parent group, if this note is bigger than the first real note of the group, cut the top of this:
Note * parent = parentNote ( ) ;
while ( parent ) {
if ( parent - > expandingOrCollapsing ( ) )
substractRectOnAreas ( TQRect ( x ( ) , parent - > y ( ) - height ( ) , width ( ) , height ( ) ) , areas , true ) ;
parent = parent - > parentNote ( ) ;
}
if ( areas . count ( ) > 0 )
return areas [ 0 ] ;
else
return TQRect ( ) ;
}
void Note : : recomputeBlankRects ( TQValueList < TQRect > & blankAreas )
{
if ( ! matching ( ) )
return ;
// visibleRect() instead of rect() because if we are folding/expanding a smaller parent group, then some part is hidden!
// But anyway, a resizer is always a primary note and is never hidden by a parent group, so no visibleResizerRect() method!
substractRectOnAreas ( visibleRect ( ) , blankAreas , true ) ;
if ( hasResizer ( ) )
substractRectOnAreas ( resizerRect ( ) , blankAreas , true ) ;
if ( isGroup ( ) ) {
Note * child = firstChild ( ) ;
bool first = true ;
while ( child ) {
if ( ( showSubNotes ( ) | | first ) & & child - > matching ( ) )
child - > recomputeBlankRects ( blankAreas ) ;
child = child - > next ( ) ;
first = false ;
}
}
}
void Note : : linkLookChanged ( )
{
if ( isGroup ( ) ) {
Note * child = firstChild ( ) ;
while ( child ) {
child - > linkLookChanged ( ) ;
child = child - > next ( ) ;
}
} else
content ( ) - > linkLookChanged ( ) ;
}
Note * Note : : noteForFullPath ( const TQString & path )
{
if ( content ( ) & & fullPath ( ) = = path )
return this ;
Note * child = firstChild ( ) ;
Note * found ;
while ( child ) {
found = child - > noteForFullPath ( path ) ;
if ( found )
return found ;
child = child - > next ( ) ;
}
return 0 ;
}
void Note : : listUsedTags ( TQValueList < Tag * > & list )
{
for ( State : : List : : Iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it ) {
Tag * tag = ( * it ) - > parentTag ( ) ;
if ( ! list . contains ( tag ) )
list . append ( tag ) ;
}
FOR_EACH_CHILD ( child )
child - > listUsedTags ( list ) ;
}
void Note : : usedStates ( TQValueList < State * > & states )
{
if ( content ( ) )
for ( State : : List : : Iterator it = m_states . begin ( ) ; it ! = m_states . end ( ) ; + + it )
if ( ! states . contains ( * it ) )
states . append ( * it ) ;
FOR_EACH_CHILD ( child )
child - > usedStates ( states ) ;
}
Note * Note : : nextInStack ( )
{
// First, search in the childs:
if ( firstChild ( ) )
if ( firstChild ( ) - > content ( ) )
return firstChild ( ) ;
else
return firstChild ( ) - > nextInStack ( ) ;
// Then, in the next:
if ( next ( ) )
if ( next ( ) - > content ( ) )
return next ( ) ;
else
return next ( ) - > nextInStack ( ) ;
// And finally, in the parent:
Note * note = parentNote ( ) ;
while ( note )
if ( note - > next ( ) )
if ( note - > next ( ) - > content ( ) )
return note - > next ( ) ;
else
return note - > next ( ) - > nextInStack ( ) ;
else
note = note - > parentNote ( ) ;
// Not found:
return 0 ;
}
Note * Note : : prevInStack ( )
{
// First, search in the previous:
if ( prev ( ) & & prev ( ) - > content ( ) )
return prev ( ) ;
// Else, it's a group, get the last item in that group:
if ( prev ( ) ) {
Note * note = prev ( ) - > lastRealChild ( ) ;
if ( note )
return note ;
}
if ( parentNote ( ) )
return parentNote ( ) - > prevInStack ( ) ;
else
return 0 ;
}
Note * Note : : nextShownInStack ( )
{
Note * next = nextInStack ( ) ;
while ( next & & ! next - > isShown ( ) )
next = next - > nextInStack ( ) ;
return next ;
}
Note * Note : : prevShownInStack ( )
{
Note * prev = prevInStack ( ) ;
while ( prev & & ! prev - > isShown ( ) )
prev = prev - > prevInStack ( ) ;
return prev ;
}
bool Note : : isShown ( )
{
// First, the easy one: groups are always shown:
if ( isGroup ( ) )
return true ;
// And another easy part: non-matching notes are hidden:
if ( ! matching ( ) )
return false ;
if ( basket ( ) - > isFiltering ( ) ) // And isMatching() because of the line above!
return true ;
// So, here we go to the complexe case: if the note is inside a collapsed group:
Note * group = parentNote ( ) ;
Note * child = this ;
while ( group ) {
if ( group - > isFolded ( ) & & group - > firstChild ( ) ! = child )
return false ;
child = group ;
group = group - > parentNote ( ) ;
}
return true ;
}
void Note : : debug ( )
{
std : : cout < < " Note@ " < < ( TQ_UINT64 ) this ;
if ( ! this ) {
std : : cout < < std : : endl ;
return ;
}
if ( isColumn ( ) )
std : : cout < < " : Column " ;
else if ( isGroup ( ) )
std : : cout < < " : Group " ;
else
std : : cout < < " : Content[ " < < content ( ) - > lowerTypeName ( ) . local8Bit ( ) < < " ]: " < < toText ( " " ) . local8Bit ( ) ;
std : : cout < < std : : endl ;
}
Note * Note : : firstSelected ( )
{
if ( isSelected ( ) )
return this ;
Note * first = 0 ;
FOR_EACH_CHILD ( child ) {
first = child - > firstSelected ( ) ;
if ( first )
break ;
}
return first ;
}
Note * Note : : lastSelected ( )
{
if ( isSelected ( ) )
return this ;
Note * last = 0 , * tmp = 0 ;
FOR_EACH_CHILD ( child ) {
tmp = child - > lastSelected ( ) ;
if ( tmp )
last = tmp ;
}
return last ;
}
Note * Note : : selectedGroup ( )
{
if ( isGroup ( ) & & allSelected ( ) & & count ( ) = = basket ( ) - > countSelecteds ( ) )
return this ;
FOR_EACH_CHILD ( child ) {
Note * selectedGroup = child - > selectedGroup ( ) ;
if ( selectedGroup )
return selectedGroup ;
}
return 0 ;
}
void Note : : groupIn ( Note * group )
{
if ( this = = group )
return ;
if ( allSelected ( ) & & ! isColumn ( ) ) {
basket ( ) - > unplugNote ( this ) ;
basket ( ) - > insertNote ( this , group , Note : : BottomColumn , TQPoint ( ) , /*animateNewPosition=*/ true ) ;
} else {
Note * next ;
Note * child = firstChild ( ) ;
while ( child ) {
next = child - > next ( ) ;
child - > groupIn ( group ) ;
child = next ;
}
}
}
bool Note : : tryExpandParent ( )
{
Note * parent = parentNote ( ) ;
Note * child = this ;
while ( parent ) {
if ( parent - > firstChild ( ) ! = child )
return false ;
if ( parent - > isColumn ( ) )
return false ;
if ( parent - > isFolded ( ) ) {
parent - > toggleFolded ( true ) ;
basket ( ) - > relayoutNotes ( true ) ;
return true ;
}
child = parent ;
parent = parent - > parentNote ( ) ;
}
return false ;
}
bool Note : : tryFoldParent ( ) // TODO: withCtrl ? withShift ?
{
Note * parent = parentNote ( ) ;
Note * child = this ;
while ( parent ) {
if ( parent - > firstChild ( ) ! = child )
return false ;
if ( parent - > isColumn ( ) )
return false ;
if ( ! parent - > isFolded ( ) ) {
parent - > toggleFolded ( true ) ;
basket ( ) - > relayoutNotes ( true ) ;
return true ;
}
child = parent ;
parent = parent - > parentNote ( ) ;
}
return false ;
}
int Note : : distanceOnLeftRight ( Note * note , int side )
{
if ( side = = Basket : : RIGHT_SIDE ) {
// If 'note' is on left of 'this': cannot switch from this to note by pressing Right key:
if ( finalX ( ) > note - > finalX ( ) | | finalRightLimit ( ) > note - > finalRightLimit ( ) )
return - 1 ;
} else /*LEFT_SIDE:*/ {
// If 'note' is on left of 'this': cannot switch from this to note by pressing Right key:
if ( finalX ( ) < note - > finalX ( ) | | finalRightLimit ( ) < note - > finalRightLimit ( ) )
return - 1 ;
}
if ( finalX ( ) = = note - > finalX ( ) & & finalRightLimit ( ) = = note - > finalRightLimit ( ) )
return - 1 ;
float thisCenterX = finalX ( ) + ( side = = Basket : : LEFT_SIDE ? width ( ) : /*RIGHT_SIDE:*/ 0 ) ;
float thisCenterY = finalY ( ) + finalHeight ( ) / 2 ;
float noteCenterX = note - > finalX ( ) + note - > width ( ) / 2 ;
float noteCenterY = note - > finalY ( ) + note - > finalHeight ( ) / 2 ;
if ( thisCenterY > note - > finalBottom ( ) )
noteCenterY = note - > finalBottom ( ) ;
else if ( thisCenterY < note - > finalY ( ) )
noteCenterY = note - > finalY ( ) ;
else
noteCenterY = thisCenterY ;
float angle = 0 ;
if ( noteCenterX - thisCenterX ! = 0 )
angle = 1000 * ( ( noteCenterY - thisCenterY ) / ( noteCenterX - thisCenterX ) ) ;
if ( angle < 0 )
angle = - angle ;
return int ( sqrt ( pow ( noteCenterX - thisCenterX , 2 ) + pow ( noteCenterY - thisCenterY , 2 ) ) + angle ) ;
}
int Note : : distanceOnTopBottom ( Note * note , int side )
{
if ( side = = Basket : : BOTTOM_SIDE ) {
// If 'note' is on left of 'this': cannot switch from this to note by pressing Right key:
if ( finalY ( ) > note - > finalY ( ) | | finalBottom ( ) > note - > finalBottom ( ) )
return - 1 ;
} else /*TOP_SIDE:*/ {
// If 'note' is on left of 'this': cannot switch from this to note by pressing Right key:
if ( finalY ( ) < note - > finalY ( ) | | finalBottom ( ) < note - > finalBottom ( ) )
return - 1 ;
}
if ( finalY ( ) = = note - > finalY ( ) & & finalBottom ( ) = = note - > finalBottom ( ) )
return - 1 ;
float thisCenterX = finalX ( ) + width ( ) / 2 ;
float thisCenterY = finalY ( ) + ( side = = Basket : : TOP_SIDE ? finalHeight ( ) : /*BOTTOM_SIDE:*/ 0 ) ;
float noteCenterX = note - > finalX ( ) + note - > width ( ) / 2 ;
float noteCenterY = note - > finalY ( ) + note - > finalHeight ( ) / 2 ;
if ( thisCenterX > note - > finalRightLimit ( ) )
noteCenterX = note - > finalRightLimit ( ) ;
else if ( thisCenterX < note - > finalX ( ) )
noteCenterX = note - > finalX ( ) ;
else
noteCenterX = thisCenterX ;
float angle = 0 ;
if ( noteCenterX - thisCenterX ! = 0 )
angle = 1000 * ( ( noteCenterY - thisCenterY ) / ( noteCenterX - thisCenterX ) ) ;
if ( angle < 0 )
angle = - angle ;
return int ( sqrt ( pow ( noteCenterX - thisCenterX , 2 ) + pow ( noteCenterY - thisCenterY , 2 ) ) + angle ) ;
}
Note * Note : : parentPrimaryNote ( )
{
Note * primary = this ;
while ( primary - > parentNote ( ) )
primary = primary - > parentNote ( ) ;
return primary ;
}
void Note : : deleteChilds ( )
{
Note * child = firstChild ( ) ;
while ( child )
{
Note * tmp = child - > next ( ) ;
delete child ;
child = tmp ;
}
}
bool Note : : saveAgain ( )
{
if ( content ( ) )
{
if ( ! content ( ) - > saveToFile ( ) )
return false ;
}
FOR_EACH_CHILD ( child )
{
if ( ! child - > saveAgain ( ) )
return false ;
}
return true ;
}
bool Note : : convertTexts ( )
{
bool convertedNotes = false ;
if ( content ( ) & & content ( ) - > lowerTypeName ( ) = = " text " ) {
TQString text = ( ( TextContent * ) content ( ) ) - > text ( ) ;
TQString html = " <html><head><meta name= \" qrichtext \" content= \" 1 \" /></head><body> " + Tools : : textToHTMLWithoutP ( text ) + " </body></html> " ;
basket ( ) - > saveToFile ( fullPath ( ) , html , /*isLocalEncoding=*/ true ) ;
setContent ( new HtmlContent ( this , content ( ) - > fileName ( ) ) ) ;
convertedNotes = true ;
}
FOR_EACH_CHILD ( child )
if ( child - > convertTexts ( ) )
convertedNotes = true ;
return convertedNotes ;
}
#if 0
/** Note */
TQString Note : : toHtml ( const TQString & imageName )
{
switch ( m_type ) {
case Text :
/*return "<font color=" + backgroundColor().name() + + font().name() + font + ">" +
Tools : : textToHTMLWithoutP ( text ( ) ) + " </font> " ; */
return Tools : : textToHTMLWithoutP ( text ( ) ) ;
case Html :
return Tools : : htmlToParagraph ( html ( ) ) ;
case Image :
case Animation :
{
if ( ( m_type = = Image & & pixmap ( ) = = 0L ) | |
( m_type = = Animation & & movie ( ) = = 0L ) ) {
TQMimeSourceFactory : : defaultFactory ( ) - > setData ( imageName , 0L ) ;
return i18n ( " (Image) " ) ; // Image or animation not yet loaded!!
}
TQImage image ;
if ( m_type = = Image )
image = pixmap ( ) - > convertToImage ( ) ;
else
image = movie ( ) - > framePixmap ( ) . convertToImage ( ) ;
image = image . smoothScale ( 200 , 150 , TQImage : : ScaleMin ) ;
TQPixmap pixmap = TQPixmap ( image ) ;
TQMimeSourceFactory : : defaultFactory ( ) - > setPixmap ( imageName , pixmap ) ;
return " <img src= " + imageName + " > " ; ///
/* // FIXME: movie isn't loaded yet: CRASH!
return i18n ( " (Image) " ) ;
// Not executed, because don't work:
TQImage image ;
if ( m_type = = Image )
image = pixmap ( ) - > convertToImage ( ) ;
else
image = movie ( ) - > framePixmap ( ) . convertToImage ( ) ;
image = image . smoothScale ( 200 , 150 , TQImage : : ScaleMin ) ;
TQPixmap pixmap = TQPixmap ( image ) ;
TQMimeSourceFactory : : defaultFactory ( ) - > setPixmap ( imageName , pixmap ) ;
return " <img src= " + imageName + " > " ; ///
*/ //TODO?: TQMimeSourceFactory::defaultFactory()->setData(imageName, 0L);
}
case Sound :
case File :
{
/// FIXME: Since fullPath() doesn't exist yet, the icon rely on the extension.
/// Bad if there isn't one or if it's a wrong one.
/*TQPixmap icon = DesktopIcon(
NoteFactory : : iconForURL ( fullPath ( ) ) ,
( m_type = = Sound ? LinkLook : : soundLook : LinkLook : : fileLook ) - > iconSize ( ) ) ;
TQMimeSourceFactory : : defaultFactory ( ) - > setPixmap ( imageName , icon ) ;
return " <img src= " + imageName + " > " + fileName ( ) ; */ ///
return m_linkLabel - > toHtml ( imageName ) ;
}
case Link :
{
TQString link = m_linkLabel - > toHtml ( imageName ) ;
if ( ! autoTitle ( ) & & title ( ) ! = NoteFactory : : titleForURL ( url ( ) . prettyURL ( ) ) )
link + = " <br><i> " + url ( ) . prettyURL ( ) + " </i> " ; ///
return link ;
}
case Launcher :
{
return m_linkLabel - > toHtml ( imageName ) ;
//KService service(fullPath()); // service.icon()
//return service.name() + "<br><i>" + service.exec() + "</i>"; ///
}
case Color :
return " <b><font color= " + color ( ) . name ( ) + " > " + color ( ) . name ( ) + " </font></b> " ;
case Unknown :
return text ( ) ;
}
return TQString ( ) ;
}
# endif // #if 0