summaryrefslogtreecommitdiff
authorchicken <chicken>2004-03-01 19:44:43 (UTC)
committer chicken <chicken>2004-03-01 19:44:43 (UTC)
commit18ea562480a63f504f4dc8e3f46c1db9d2cd6276 (patch) (side-by-side diff)
treede22b70f1da5adeb072f0c30517bd92e9c7a839b
parent8ac7ec5e055dacd8c92d5a28336257cfe3e716e5 (diff)
downloadopie-18ea562480a63f504f4dc8e3f46c1db9d2cd6276.zip
opie-18ea562480a63f504f4dc8e3f46c1db9d2cd6276.tar.gz
opie-18ea562480a63f504f4dc8e3f46c1db9d2cd6276.tar.bz2
fix includes
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-write/qcomplextext.cpp3
-rw-r--r--noncore/apps/opie-write/qrichtext.cpp15
-rw-r--r--noncore/apps/opie-write/qstylesheet.cpp2
-rw-r--r--noncore/apps/opie-write/qtextedit.cpp20
-rw-r--r--noncore/apps/oxygen/calcdlgui.cpp1
-rw-r--r--noncore/apps/oxygen/dataTable.cpp3
-rw-r--r--noncore/apps/oxygen/datawidgetui.cpp5
-rw-r--r--noncore/apps/oxygen/kmolcalc.cpp3
-rw-r--r--noncore/apps/oxygen/oxyframe.cpp2
-rw-r--r--noncore/apps/oxygen/oxygen.cpp2
-rw-r--r--noncore/apps/oxygen/psewidget.cpp2
-rwxr-xr-xnoncore/apps/qashmoney/account.cpp2
-rwxr-xr-xnoncore/apps/qashmoney/accountdisplay.cpp2
-rwxr-xr-xnoncore/apps/qashmoney/budgetdisplay.cpp3
-rwxr-xr-xnoncore/apps/qashmoney/newaccount.cpp3
-rwxr-xr-xnoncore/apps/qashmoney/newtransaction.cpp2
-rwxr-xr-xnoncore/apps/qashmoney/preferencedialogs.cpp1
-rwxr-xr-xnoncore/apps/qashmoney/transactiondisplay.cpp3
-rwxr-xr-xnoncore/apps/qashmoney/transferdialog.cpp2
-rw-r--r--noncore/apps/tableviewer/tableviewer.cpp1
20 files changed, 0 insertions, 77 deletions
diff --git a/noncore/apps/opie-write/qcomplextext.cpp b/noncore/apps/opie-write/qcomplextext.cpp
index e8b94da..473f184 100644
--- a/noncore/apps/opie-write/qcomplextext.cpp
+++ b/noncore/apps/opie-write/qcomplextext.cpp
@@ -1,149 +1,146 @@
/****************************************************************************
** $Id$
**
** Implementation of some internal classes
**
** Created :
**
** Copyright (C) 2001 Trolltech AS. All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
-#include "qcomplextext_p.h"
#include "qrichtext_p.h"
-#include "qfontmetrics.h"
-#include "qrect.h"
#include <stdlib.h>
using namespace Qt3;
// -----------------------------------------------------
/* a small helper class used internally to resolve Bidi embedding levels.
Each line of text caches the embedding level at the start of the line for faster
relayouting
*/
QBidiContext::QBidiContext( uchar l, QChar::Direction e, QBidiContext *p, bool o )
: level(l) , override(o), dir(e)
{
if ( p )
p->ref();
parent = p;
count = 0;
}
QBidiContext::~QBidiContext()
{
if( parent && parent->deref() )
delete parent;
}
/*
Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on
arabic).
Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent).
transparent joining is not encoded in QChar::joining(), but applies to all combining marks and format marks.
Right join-causing: dual + center
Left join-causing: dual + right + center
Rules are as follows (for a string already in visual order, as we have it here):
R1 Transparent characters do not affect joining behaviour.
R2 A right joining character, that has a right join-causing char on the right will get form XRight
(R3 A left joining character, that has a left join-causing char on the left will get form XLeft)
Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode
R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on
the right will get form XMedial
R5 A dual joining character, that has a right join causing char on the right, and no left join causing char on the left
will get form XRight
R6 A dual joining character, that has a left join causing char on the left, and no right join causing char on the right
will get form XLeft
R7 Otherwise the character will get form XIsolated
Additionally we have to do the minimal ligature support for lam-alef ligatures:
L1 Transparent characters do not affect ligature behaviour.
L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft)
L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated)
The two functions defined in this class do shaping in visual and logical order. For logical order just replace right with
previous and left with next in the above rules ;-)
*/
/*
Two small helper functions for arabic shaping. They get the next shape causing character on either
side of the char in question. Implements rule R1.
leftChar() returns true if the char to the left is a left join-causing char
rightChar() returns true if the char to the right is a right join-causing char
*/
static inline const QChar *prevChar( const QString &str, int pos )
{
//qDebug("leftChar: pos=%d", pos);
pos--;
const QChar *ch = str.unicode() + pos;
while( pos > -1 ) {
if( !ch->isMark() )
return ch;
pos--;
ch--;
}
return &QChar::replacement;
}
static inline const QChar *nextChar( const QString &str, int pos)
{
pos++;
int len = str.length();
const QChar *ch = str.unicode() + pos;
while( pos < len ) {
//qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining());
if( !ch->isMark() )
return ch;
// assume it's a transparent char, this might not be 100% correct
pos++;
ch++;
}
return &QChar::replacement;
}
static inline bool prevVisualCharJoins( const QString &str, int pos)
{
return ( prevChar( str, pos )->joining() != QChar::OtherJoining );
}
static inline bool nextVisualCharJoins( const QString &str, int pos)
{
QChar::Joining join = nextChar( str, pos )->joining();
return ( join == QChar::Dual || join == QChar::Center );
}
diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp
index 3b044c3..b77a0fc 100644
--- a/noncore/apps/opie-write/qrichtext.cpp
+++ b/noncore/apps/opie-write/qrichtext.cpp
@@ -1,3129 +1,3114 @@
/****************************************************************************
** $Id$
**
** Implementation of the internal Qt classes dealing with rich text
**
** Created : 990101
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qrichtext_p.h"
-#include "qstringlist.h"
-#include "qfont.h"
-#include "qtextstream.h"
-#include "qfile.h"
-#include "qapplication.h"
-#include "qmap.h"
-#include "qfileinfo.h"
-#include "qstylesheet.h"
-#include "qmime.h"
-#include "qimage.h"
#include "qdragobject.h"
#include "qpaintdevicemetrics.h"
-#include "qpainter.h"
#include "qdrawutil.h"
-#include "qcursor.h"
-#include "qstack.h"
-#include "qstyle.h"
-#include "qcomplextext_p.h"
#include "qcleanuphandler.h"
#include <stdlib.h>
using namespace Qt3;
static QTextCursor* richTextExportStart = 0;
static QTextCursor* richTextExportEnd = 0;
static QTextFormatCollection *qFormatCollection = 0;
const int border_tolerance = 2;
#ifdef Q_WS_WIN
#include "qt_windows.h"
#endif
#define QChar_linesep QChar(0x2028U)
static inline bool is_printer( QPainter *p )
{
if ( !p || !p->device() )
return FALSE;
return p->device()->devType() == QInternal::Printer;
}
static inline int scale( int value, QPainter *painter )
{
if ( is_printer( painter ) ) {
QPaintDeviceMetrics metrics( painter->device() );
#if defined(Q_WS_X11)
value = value * metrics.logicalDpiY() / QPaintDevice::x11AppDpiY();
#elif defined (Q_WS_WIN)
HDC hdc = GetDC( 0 );
int gdc = GetDeviceCaps( hdc, LOGPIXELSY );
if ( gdc )
value = value * metrics.logicalDpiY() / gdc;
ReleaseDC( 0, hdc );
#elif defined (Q_WS_MAC)
value = value * metrics.logicalDpiY() / 75; // ##### FIXME
#elif defined (Q_WS_QWS)
value = value * metrics.logicalDpiY() / 75;
#endif
}
return value;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void QTextCommandHistory::addCommand( QTextCommand *cmd )
{
if ( current < (int)history.count() - 1 ) {
QPtrList<QTextCommand> commands;
commands.setAutoDelete( FALSE );
for( int i = 0; i <= current; ++i ) {
commands.insert( i, history.at( 0 ) );
history.take( 0 );
}
commands.append( cmd );
history.clear();
history = commands;
history.setAutoDelete( TRUE );
} else {
history.append( cmd );
}
if ( (int)history.count() > steps )
history.removeFirst();
else
++current;
}
QTextCursor *QTextCommandHistory::undo( QTextCursor *c )
{
if ( current > -1 ) {
QTextCursor *c2 = history.at( current )->unexecute( c );
--current;
return c2;
}
return 0;
}
QTextCursor *QTextCommandHistory::redo( QTextCursor *c )
{
if ( current > -1 ) {
if ( current < (int)history.count() - 1 ) {
++current;
return history.at( current )->execute( c );
}
} else {
if ( history.count() > 0 ) {
++current;
return history.at( current )->execute( c );
}
}
return 0;
}
bool QTextCommandHistory::isUndoAvailable()
{
return current > -1;
}
bool QTextCommandHistory::isRedoAvailable()
{
return current > -1 && current < (int)history.count() - 1 || current == -1 && history.count() > 0;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
QTextDeleteCommand::QTextDeleteCommand( QTextDocument *d, int i, int idx, const QMemArray<QTextStringChar> &str,
const QByteArray& oldStyleInfo )
: QTextCommand( d ), id( i ), index( idx ), parag( 0 ), text( str ), styleInformation( oldStyleInfo )
{
for ( int j = 0; j < (int)text.size(); ++j ) {
if ( text[ j ].format() )
text[ j ].format()->addRef();
}
}
QTextDeleteCommand::QTextDeleteCommand( QTextParagraph *p, int idx, const QMemArray<QTextStringChar> &str )
: QTextCommand( 0 ), id( -1 ), index( idx ), parag( p ), text( str )
{
for ( int i = 0; i < (int)text.size(); ++i ) {
if ( text[ i ].format() )
text[ i ].format()->addRef();
}
}
QTextDeleteCommand::~QTextDeleteCommand()
{
for ( int i = 0; i < (int)text.size(); ++i ) {
if ( text[ i ].format() )
text[ i ].format()->removeRef();
}
text.resize( 0 );
}
QTextCursor *QTextDeleteCommand::execute( QTextCursor *c )
{
QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
if ( !s ) {
qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
return 0;
}
cursor.setParagraph( s );
cursor.setIndex( index );
int len = text.size();
if ( c )
*c = cursor;
if ( doc ) {
doc->setSelectionStart( QTextDocument::Temp, cursor );
for ( int i = 0; i < len; ++i )
cursor.gotoNextLetter();
doc->setSelectionEnd( QTextDocument::Temp, cursor );
doc->removeSelectedText( QTextDocument::Temp, &cursor );
if ( c )
*c = cursor;
} else {
s->remove( index, len );
}
return c;
}
QTextCursor *QTextDeleteCommand::unexecute( QTextCursor *c )
{
QTextParagraph *s = doc ? doc->paragAt( id ) : parag;
if ( !s ) {
qWarning( "can't locate parag at %d, last parag: %d", id, doc->lastParagraph()->paragId() );
return 0;
}
cursor.setParagraph( s );
cursor.setIndex( index );
QString str = QTextString::toString( text );
cursor.insert( str, TRUE, &text );
cursor.setParagraph( s );
cursor.setIndex( index );
if ( c ) {
c->setParagraph( s );
c->setIndex( index );
for ( int i = 0; i < (int)text.size(); ++i )
c->gotoNextLetter();
}
if ( !styleInformation.isEmpty() ) {
QDataStream styleStream( styleInformation, IO_ReadOnly );
int num;
styleStream >> num;
QTextParagraph *p = s;
while ( num-- && p ) {
p->readStyleInformation( styleStream );
p = p->next();
}
}
s = cursor.paragraph();
while ( s ) {
s->format();
s->setChanged( TRUE );
if ( s == c->paragraph() )
break;
s = s->next();
}
return &cursor;
}
QTextFormatCommand::QTextFormatCommand( QTextDocument *d, int sid, int sidx, int eid, int eidx,
const QMemArray<QTextStringChar> &old, QTextFormat *f, int fl )
: QTextCommand( d ), startId( sid ), startIndex( sidx ), endId( eid ), endIndex( eidx ), format( f ), oldFormats( old ), flags( fl )
{
format = d->formatCollection()->format( f );
for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
if ( oldFormats[ j ].format() )
oldFormats[ j ].format()->addRef();
}
}
QTextFormatCommand::~QTextFormatCommand()
{
format->removeRef();
for ( int j = 0; j < (int)oldFormats.size(); ++j ) {
if ( oldFormats[ j ].format() )
oldFormats[ j ].format()->removeRef();
}
}
QTextCursor *QTextFormatCommand::execute( QTextCursor *c )
{
QTextParagraph *sp = doc->paragAt( startId );
QTextParagraph *ep = doc->paragAt( endId );
if ( !sp || !ep )
return c;
QTextCursor start( doc );
start.setParagraph( sp );
start.setIndex( startIndex );
QTextCursor end( doc );
end.setParagraph( ep );
end.setIndex( endIndex );
doc->setSelectionStart( QTextDocument::Temp, start );
doc->setSelectionEnd( QTextDocument::Temp, end );
doc->setFormat( QTextDocument::Temp, format, flags );
doc->removeSelection( QTextDocument::Temp );
if ( endIndex == ep->length() )
end.gotoLeft();
*c = end;
return c;
}
QTextCursor *QTextFormatCommand::unexecute( QTextCursor *c )
{
QTextParagraph *sp = doc->paragAt( startId );
QTextParagraph *ep = doc->paragAt( endId );
if ( !sp || !ep )
return 0;
int idx = startIndex;
int fIndex = 0;
for ( ;; ) {
if ( oldFormats.at( fIndex ).c == '\n' ) {
if ( idx > 0 ) {
if ( idx < sp->length() && fIndex > 0 )
sp->setFormat( idx, 1, oldFormats.at( fIndex - 1 ).format() );
if ( sp == ep )
break;
sp = sp->next();
idx = 0;
}
fIndex++;
}
if ( oldFormats.at( fIndex ).format() )
sp->setFormat( idx, 1, oldFormats.at( fIndex ).format() );
idx++;
fIndex++;
if ( fIndex >= (int)oldFormats.size() )
break;
if ( idx >= sp->length() ) {
if ( sp == ep )
break;
sp = sp->next();
idx = 0;
}
}
QTextCursor end( doc );
end.setParagraph( ep );
end.setIndex( endIndex );
if ( endIndex == ep->length() )
end.gotoLeft();
*c = end;
return c;
}
QTextStyleCommand::QTextStyleCommand( QTextDocument *d, int fParag, int lParag, const QByteArray& beforeChange )
: QTextCommand( d ), firstParag( fParag ), lastParag( lParag ), before( beforeChange )
{
after = readStyleInformation( d, fParag, lParag );
}
QByteArray QTextStyleCommand::readStyleInformation( QTextDocument* doc, int fParag, int lParag )
{
QByteArray style;
QTextParagraph *p = doc->paragAt( fParag );
if ( !p )
return style;
QDataStream styleStream( style, IO_WriteOnly );
int num = lParag - fParag + 1;
styleStream << num;
while ( num -- && p ) {
p->writeStyleInformation( styleStream );
p = p->next();
}
return style;
}
void QTextStyleCommand::writeStyleInformation( QTextDocument* doc, int fParag, const QByteArray& style )
{
QTextParagraph *p = doc->paragAt( fParag );
if ( !p )
return;
QDataStream styleStream( style, IO_ReadOnly );
int num;
styleStream >> num;
while ( num-- && p ) {
p->readStyleInformation( styleStream );
p = p->next();
}
}
QTextCursor *QTextStyleCommand::execute( QTextCursor *c )
{
writeStyleInformation( doc, firstParag, after );
return c;
}
QTextCursor *QTextStyleCommand::unexecute( QTextCursor *c )
{
writeStyleInformation( doc, firstParag, before );
return c;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
QTextCursor::QTextCursor( QTextDocument *d )
: idx( 0 ), tmpIndex( -1 ), ox( 0 ), oy( 0 ),
valid( TRUE )
{
para = d ? d->firstParagraph() : 0;
}
QTextCursor::QTextCursor( const QTextCursor &c )
{
ox = c.ox;
oy = c.oy;
idx = c.idx;
para = c.para;
tmpIndex = c.tmpIndex;
indices = c.indices;
paras = c.paras;
xOffsets = c.xOffsets;
yOffsets = c.yOffsets;
valid = c.valid;
}
QTextCursor &QTextCursor::operator=( const QTextCursor &c )
{
ox = c.ox;
oy = c.oy;
idx = c.idx;
para = c.para;
tmpIndex = c.tmpIndex;
indices = c.indices;
paras = c.paras;
xOffsets = c.xOffsets;
yOffsets = c.yOffsets;
valid = c.valid;
return *this;
}
bool QTextCursor::operator==( const QTextCursor &c ) const
{
return para == c.para && idx == c.idx;
}
int QTextCursor::totalOffsetX() const
{
int xoff = ox;
for ( QValueStack<int>::ConstIterator xit = xOffsets.begin(); xit != xOffsets.end(); ++xit )
xoff += *xit;
return xoff;
}
int QTextCursor::totalOffsetY() const
{
int yoff = oy;
for ( QValueStack<int>::ConstIterator yit = yOffsets.begin(); yit != yOffsets.end(); ++yit )
yoff += *yit;
return yoff;
}
void QTextCursor::gotoIntoNested( const QPoint &globalPos )
{
if ( !para )
return;
push();
ox = 0;
int bl, y;
para->lineHeightOfChar( idx, &bl, &y );
oy = y + para->rect().y();
QPoint p( globalPos.x() - offsetX(), globalPos.y() - offsetY() );
Q_ASSERT( para->at( idx )->isCustom() );
ox = para->at( idx )->x;
QTextDocument* doc = document();
para->at( idx )->customItem()->enterAt( this, doc, para, idx, ox, oy, p );
}
void QTextCursor::invalidateNested()
{
QValueStack<QTextParagraph*>::Iterator it = paras.begin();
QValueStack<int>::Iterator it2 = indices.begin();
for ( ; it != paras.end(); ++it, ++it2 ) {
if ( *it == para )
continue;
(*it)->invalidate( 0 );
if ( (*it)->at( *it2 )->isCustom() )
(*it)->at( *it2 )->customItem()->invalidate();
}
}
void QTextCursor::insert( const QString &str, bool checkNewLine, QMemArray<QTextStringChar> *formatting )
{
tmpIndex = -1;
bool justInsert = TRUE;
QString s( str );
#if defined(Q_WS_WIN)
if ( checkNewLine ) {
int i = 0;
while ( ( i = s.find( '\r', i ) ) != -1 )
s.remove( i ,1 );
}
#endif
if ( checkNewLine )
justInsert = s.find( '\n' ) == -1;
if ( justInsert ) { // we ignore new lines and insert all in the current para at the current index
para->insert( idx, s.unicode(), s.length() );
if ( formatting ) {
for ( int i = 0; i < (int)s.length(); ++i ) {
if ( formatting->at( i ).format() ) {
formatting->at( i ).format()->addRef();
para->string()->setFormat( idx + i, formatting->at( i ).format(), TRUE );
}
}
}
idx += s.length();
} else { // we split at new lines
int start = -1;
int end;
int y = para->rect().y() + para->rect().height();
int lastIndex = 0;
do {
end = s.find( '\n', start + 1 ); // find line break
if ( end == -1 ) // didn't find one, so end of line is end of string
end = s.length();
int len = (start == -1 ? end : end - start - 1);
if ( len > 0 ) // insert the line
para->insert( idx, s.unicode() + start + 1, len );
else
para->invalidate( 0 );
if ( formatting ) { // set formats to the chars of the line
for ( int i = 0; i < len; ++i ) {
if ( formatting->at( i + lastIndex ).format() ) {
formatting->at( i + lastIndex ).format()->addRef();
para->string()->setFormat( i + idx, formatting->at( i + lastIndex ).format(), TRUE );
}
}
lastIndex += len;
}
start = end; // next start is at the end of this line
idx += len; // increase the index of the cursor to the end of the inserted text
if ( s[end] == '\n' ) { // if at the end was a line break, break the line
splitAndInsertEmptyParagraph( FALSE, TRUE );
para->setEndState( -1 );
para->prev()->format( -1, FALSE );
lastIndex++;
}
} while ( end < (int)s.length() );
para->format( -1, FALSE );
int dy = para->rect().y() + para->rect().height() - y;
QTextParagraph *p = para;
p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
p = p->next();
while ( p ) {
p->setParagId( p->prev()->paragId() + 1 );
p->move( dy );
p->invalidate( 0 );
p->setEndState( -1 );
p = p->next();
}
}
int h = para->rect().height();
para->format( -1, TRUE );
if ( h != para->rect().height() )
invalidateNested();
else if ( para->document() && para->document()->parent() )
para->document()->nextDoubleBuffered = TRUE;
}
void QTextCursor::gotoLeft()
{
if ( para->string()->isRightToLeft() )
gotoNextLetter();
else
gotoPreviousLetter();
}
void QTextCursor::gotoPreviousLetter()
{
tmpIndex = -1;
if ( idx > 0 ) {
idx--;
const QTextStringChar *tsc = para->at( idx );
if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() )
processNesting( EnterEnd );
} else if ( para->prev() ) {
para = para->prev();
while ( !para->isVisible() && para->prev() )
para = para->prev();
idx = para->length() - 1;
} else if ( nestedDepth() ) {
pop();
processNesting( Prev );
if ( idx == -1 ) {
pop();
if ( idx > 0 ) {
idx--;
} else if ( para->prev() ) {
para = para->prev();
idx = para->length() - 1;
}
}
}
}
void QTextCursor::push()
{
indices.push( idx );
paras.push( para );
xOffsets.push( ox );
yOffsets.push( oy );
}
void QTextCursor::pop()
{
if ( indices.isEmpty() )
return;
idx = indices.pop();
para = paras.pop();
ox = xOffsets.pop();
oy = yOffsets.pop();
}
void QTextCursor::restoreState()
{
while ( !indices.isEmpty() )
pop();
}
bool QTextCursor::place( const QPoint &p, QTextParagraph *s, bool link )
{
QPoint pos( p );
QRect r;
QTextParagraph *str = s;
if ( pos.y() < s->rect().y() )
pos.setY( s->rect().y() );
while ( s ) {
r = s->rect();
r.setWidth( document() ? document()->width() : QWIDGETSIZE_MAX );
if ( s->isVisible() )
str = s;
if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() || !s->next() )
break;
s = s->next();
}
if ( !s || !str )
return FALSE;
s = str;
setParagraph( s );
int y = s->rect().y();
int lines = s->lines();
QTextStringChar *chr = 0;
int index = 0;
int i = 0;
int cy = 0;
int ch = 0;
for ( ; i < lines; ++i ) {
chr = s->lineStartOfLine( i, &index );
cy = s->lineY( i );
ch = s->lineHeight( i );
if ( !chr )
return FALSE;
if ( pos.y() <= y + cy + ch )
break;
}
int nextLine;
if ( i < lines - 1 )
s->lineStartOfLine( i+1, &nextLine );
else
nextLine = s->length();
i = index;
int x = s->rect().x();
if ( pos.x() < x )
pos.setX( x + 1 );
int cw;
int curpos = s->length()-1;
int dist = 10000000;
bool inCustom = FALSE;
while ( i < nextLine ) {
chr = s->at(i);
int cpos = x + chr->x;
cw = s->string()->width( i );
if ( chr->isCustom() && chr->customItem()->isNested() ) {
if ( pos.x() >= cpos && pos.x() <= cpos + cw &&
pos.y() >= y + cy && pos.y() <= y + cy + chr->height() ) {
inCustom = TRUE;
curpos = i;
break;
}
} else {
if( chr->rightToLeft )
cpos += cw;
int d = cpos - pos.x();
bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft;
if ( QABS( d ) < dist || (dist == d && dm == TRUE ) ) {
dist = QABS( d );
if ( !link || pos.x() >= x + chr->x )
curpos = i;
}
}
i++;
}
setIndex( curpos );
if ( inCustom && para->document() && para->at( curpos )->isCustom() && para->at( curpos )->customItem()->isNested() ) {
QTextDocument *oldDoc = para->document();
gotoIntoNested( pos );
if ( oldDoc == para->document() )
return TRUE;
QPoint p( pos.x() - offsetX(), pos.y() - offsetY() );
if ( !place( p, document()->firstParagraph(), link ) )
pop();
}
return TRUE;
}
void QTextCursor::processNesting( Operation op )
{
if ( !para->document() )
return;
QTextDocument* doc = para->document();
push();
ox = para->at( idx )->x;
int bl, y;
para->lineHeightOfChar( idx, &bl, &y );
oy = y + para->rect().y();
bool ok = FALSE;
switch ( op ) {
case EnterBegin:
ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy );
break;
case EnterEnd:
ok = para->at( idx )->customItem()->enter( this, doc, para, idx, ox, oy, TRUE );
break;
case Next:
ok = para->at( idx )->customItem()->next( this, doc, para, idx, ox, oy );
break;
case Prev:
ok = para->at( idx )->customItem()->prev( this, doc, para, idx, ox, oy );
break;
case Down:
ok = para->at( idx )->customItem()->down( this, doc, para, idx, ox, oy );
break;
case Up:
ok = para->at( idx )->customItem()->up( this, doc, para, idx, ox, oy );
break;
}
if ( !ok )
pop();
}
void QTextCursor::gotoRight()
{
if ( para->string()->isRightToLeft() )
gotoPreviousLetter();
else
gotoNextLetter();
}
void QTextCursor::gotoNextLetter()
{
tmpIndex = -1;
const QTextStringChar *tsc = para->at( idx );
if ( tsc && tsc->isCustom() && tsc->customItem()->isNested() ) {
processNesting( EnterBegin );
return;
}
if ( idx < para->length() - 1 ) {
idx++;
} else if ( para->next() ) {
para = para->next();
while ( !para->isVisible() && para->next() )
para = para->next();
idx = 0;
} else if ( nestedDepth() ) {
pop();
processNesting( Next );
if ( idx == -1 ) {
pop();
if ( idx < para->length() - 1 ) {
idx++;
} else if ( para->next() ) {
para = para->next();
idx = 0;
}
}
}
}
void QTextCursor::gotoUp()
{
int indexOfLineStart;
int line;
QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
if ( !c )
return;
tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
if ( indexOfLineStart == 0 ) {
if ( !para->prev() ) {
if ( !nestedDepth() )
return;
pop();
processNesting( Up );
if ( idx == -1 ) {
pop();
if ( !para->prev() )
return;
idx = tmpIndex = 0;
} else {
tmpIndex = -1;
return;
}
}
QTextParagraph *p = para->prev();
while ( p && !p->isVisible() )
p = p->prev();
if ( p )
para = p;
int lastLine = para->lines() - 1;
if ( !para->lineStartOfLine( lastLine, &indexOfLineStart ) )
return;
if ( indexOfLineStart + tmpIndex < para->length() )
idx = indexOfLineStart + tmpIndex;
else
idx = para->length() - 1;
} else {
--line;
int oldIndexOfLineStart = indexOfLineStart;
if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
return;
if ( indexOfLineStart + tmpIndex < oldIndexOfLineStart )
idx = indexOfLineStart + tmpIndex;
else
idx = oldIndexOfLineStart - 1;
}
}
void QTextCursor::gotoDown()
{
int indexOfLineStart;
int line;
QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
if ( !c )
return;
tmpIndex = QMAX( tmpIndex, idx - indexOfLineStart );
if ( line == para->lines() - 1 ) {
if ( !para->next() ) {
if ( !nestedDepth() )
return;
pop();
processNesting( Down );
if ( idx == -1 ) {
pop();
if ( !para->next() )
return;
idx = tmpIndex = 0;
} else {
tmpIndex = -1;
return;
}
}
QTextParagraph *s = para->next();
while ( s && !s->isVisible() )
s = s->next();
if ( s )
para = s;
if ( !para->lineStartOfLine( 0, &indexOfLineStart ) )
return;
int end;
if ( para->lines() == 1 )
end = para->length();
else
para->lineStartOfLine( 1, &end );
if ( indexOfLineStart + tmpIndex < end )
idx = indexOfLineStart + tmpIndex;
else
idx = end - 1;
} else {
++line;
int end;
if ( line == para->lines() - 1 )
end = para->length();
else
para->lineStartOfLine( line + 1, &end );
if ( !para->lineStartOfLine( line, &indexOfLineStart ) )
return;
if ( indexOfLineStart + tmpIndex < end )
idx = indexOfLineStart + tmpIndex;
else
idx = end - 1;
}
}
void QTextCursor::gotoLineEnd()
{
tmpIndex = -1;
int indexOfLineStart;
int line;
QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
if ( !c )
return;
if ( line == para->lines() - 1 ) {
idx = para->length() - 1;
} else {
c = para->lineStartOfLine( ++line, &indexOfLineStart );
indexOfLineStart--;
idx = indexOfLineStart;
}
}
void QTextCursor::gotoLineStart()
{
tmpIndex = -1;
int indexOfLineStart;
int line;
QTextStringChar *c = para->lineStartOfChar( idx, &indexOfLineStart, &line );
if ( !c )
return;
idx = indexOfLineStart;
}
void QTextCursor::gotoHome()
{
if ( topParagraph()->document() )
gotoPosition( topParagraph()->document()->firstParagraph() );
else
gotoLineStart();
}
void QTextCursor::gotoEnd()
{
if ( topParagraph()->document() && topParagraph()->document()->lastParagraph()->isValid() )
gotoPosition( topParagraph()->document()->lastParagraph(),
topParagraph()->document()->lastParagraph()->length() - 1);
else
gotoLineEnd();
}
void QTextCursor::gotoPageUp( int visibleHeight )
{
int targetY = globalY() - visibleHeight;
QTextParagraph* old; int index;
do {
old = para; index = idx;
gotoUp();
} while ( (old != para || index != idx) && globalY() > targetY );
}
void QTextCursor::gotoPageDown( int visibleHeight )
{
int targetY = globalY() + visibleHeight;
QTextParagraph* old; int index;
do {
old = para; index = idx;
gotoDown();
} while ( (old != para || index != idx) && globalY() < targetY );
}
void QTextCursor::gotoWordRight()
{
if ( para->string()->isRightToLeft() )
gotoPreviousWord();
else
gotoNextWord();
}
void QTextCursor::gotoWordLeft()
{
if ( para->string()->isRightToLeft() )
gotoNextWord();
else
gotoPreviousWord();
}
void QTextCursor::gotoPreviousWord()
{
gotoPreviousLetter();
tmpIndex = -1;
QTextString *s = para->string();
bool allowSame = FALSE;
if ( idx == ((int)s->length()-1) )
return;
for ( int i = idx; i >= 0; --i ) {
if ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) {
if ( !allowSame )
continue;
idx = i + 1;
return;
}
if ( !allowSame && !( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) )
allowSame = TRUE;
}
idx = 0;
}
void QTextCursor::gotoNextWord()
{
tmpIndex = -1;
QTextString *s = para->string();
bool allowSame = FALSE;
for ( int i = idx; i < (int)s->length(); ++i ) {
if ( ! (s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';') ) {
if ( !allowSame )
continue;
idx = i;
return;
}
if ( !allowSame && ( s->at( i ).c.isSpace() || s->at( i ).c == '\t' || s->at( i ).c == '.' ||
s->at( i ).c == ',' || s->at( i ).c == ':' || s->at( i ).c == ';' ) )
allowSame = TRUE;
}
if ( idx < ((int)s->length()-1) ) {
gotoLineEnd();
} else if ( para->next() ) {
QTextParagraph *p = para->next();
while ( p && !p->isVisible() )
p = p->next();
if ( s ) {
para = p;
idx = 0;
}
} else {
gotoLineEnd();
}
}
bool QTextCursor::atParagStart()
{
return idx == 0;
}
bool QTextCursor::atParagEnd()
{
return idx == para->length() - 1;
}
void QTextCursor::splitAndInsertEmptyParagraph( bool ind, bool updateIds )
{
if ( !para->document() )
return;
tmpIndex = -1;
QTextFormat *f = 0;
if ( para->document()->useFormatCollection() ) {
f = para->at( idx )->format();
if ( idx == para->length() - 1 && idx > 0 )
f = para->at( idx - 1 )->format();
if ( f->isMisspelled() ) {
f->removeRef();
f = para->document()->formatCollection()->format( f->font(), f->color() );
}
}
if ( atParagEnd() ) {
QTextParagraph *n = para->next();
QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
if ( f )
s->setFormat( 0, 1, f, TRUE );
s->copyParagData( para );
if ( ind ) {
int oi, ni;
s->indent( &oi, &ni );
para = s;
idx = ni;
} else {
para = s;
idx = 0;
}
} else if ( atParagStart() ) {
QTextParagraph *p = para->prev();
QTextParagraph *s = para->document()->createParagraph( para->document(), p, para, updateIds );
if ( f )
s->setFormat( 0, 1, f, TRUE );
s->copyParagData( para );
if ( ind ) {
s->indent();
s->format();
indent();
para->format();
}
} else {
QString str = para->string()->toString().mid( idx, 0xFFFFFF );
QTextParagraph *n = para->next();
QTextParagraph *s = para->document()->createParagraph( para->document(), para, n, updateIds );
s->copyParagData( para );
s->remove( 0, 1 );
s->append( str, TRUE );
for ( uint i = 0; i < str.length(); ++i ) {
QTextStringChar* tsc = para->at( idx + i );
s->setFormat( i, 1, tsc->format(), TRUE );
if ( tsc->isCustom() ) {
QTextCustomItem * item = tsc->customItem();
s->at( i )->setCustomItem( item );
tsc->loseCustomItem();
}
if ( tsc->isAnchor() )
s->at( i )->setAnchor( tsc->anchorName(),
tsc->anchorHref() );
}
para->truncate( idx );
if ( ind ) {
int oi, ni;
s->indent( &oi, &ni );
para = s;
idx = ni;
} else {
para = s;
idx = 0;
}
}
invalidateNested();
}
bool QTextCursor::remove()
{
tmpIndex = -1;
if ( !atParagEnd() ) {
para->remove( idx, 1 );
int h = para->rect().height();
para->format( -1, TRUE );
if ( h != para->rect().height() )
invalidateNested();
else if ( para->document() && para->document()->parent() )
para->document()->nextDoubleBuffered = TRUE;
return FALSE;
} else if ( para->next() ) {
para->join( para->next() );
invalidateNested();
return TRUE;
}
return FALSE;
}
void QTextCursor::indent()
{
int oi = 0, ni = 0;
para->indent( &oi, &ni );
if ( oi == ni )
return;
if ( idx >= oi )
idx += ni - oi;
else
idx = ni;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
QTextDocument::QTextDocument( QTextDocument *p )
: par( p ), parentPar( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
{
fCollection = new QTextFormatCollection;
init();
}
QTextDocument::QTextDocument( QTextDocument *p, QTextFormatCollection *f )
: par( p ), parentPar( 0 ), tc( 0 ), tArray( 0 ), tStopWidth( 0 )
{
fCollection = f;
init();
}
void QTextDocument::init()
{
oTextValid = TRUE;
mightHaveCustomItems = FALSE;
if ( par )
par->insertChild( this );
pProcessor = 0;
useFC = TRUE;
pFormatter = 0;
indenter = 0;
fParag = 0;
txtFormat = Qt::AutoText;
preferRichText = FALSE;
pages = FALSE;
focusIndicator.parag = 0;
minw = 0;
wused = 0;
minwParag = curParag = 0;
align = AlignAuto;
nSelections = 1;
setStyleSheet( QStyleSheet::defaultSheet() );
factory_ = QMimeSourceFactory::defaultFactory();
contxt = QString::null;
underlLinks = par ? par->underlLinks : TRUE;
backBrush = 0;
buf_pixmap = 0;
nextDoubleBuffered = FALSE;
if ( par )
withoutDoubleBuffer = par->withoutDoubleBuffer;
else
withoutDoubleBuffer = FALSE;
lParag = fParag = createParagraph( this, 0, 0 );
cx = 0;
cy = 2;
if ( par )
cx = cy = 0;
cw = 600;
vw = 0;
flow_ = new QTextFlow;
flow_->setWidth( cw );
leftmargin = rightmargin = 4;
scaleFontsFactor = 1;
selectionColors[ Standard ] = QApplication::palette().color( QPalette::Active, QColorGroup::Highlight );
selectionText[ Standard ] = TRUE;
commandHistory = new QTextCommandHistory( 100 );
tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
}
QTextDocument::~QTextDocument()
{
if ( par )
par->removeChild( this );
clear();
delete commandHistory;
delete flow_;
if ( !par )
delete pFormatter;
delete fCollection;
delete pProcessor;
delete buf_pixmap;
delete indenter;
delete backBrush;
if ( tArray )
delete [] tArray;
}
void QTextDocument::clear( bool createEmptyParag )
{
if ( flow_ )
flow_->clear();
while ( fParag ) {
QTextParagraph *p = fParag->next();
delete fParag;
fParag = p;
}
fParag = lParag = 0;
if ( createEmptyParag )
fParag = lParag = createParagraph( this );
selections.clear();
oText = QString::null;
oTextValid = TRUE;
}
int QTextDocument::widthUsed() const
{
return wused + border_tolerance;
}
int QTextDocument::height() const
{
int h = 0;
if ( lParag )
h = lParag->rect().top() + lParag->rect().height() + 1;
int fh = flow_->boundingRect().bottom();
return QMAX( h, fh );
}
QTextParagraph *QTextDocument::createParagraph( QTextDocument *d, QTextParagraph *pr, QTextParagraph *nx, bool updateIds )
{
return new QTextParagraph( d, pr, nx, updateIds );
}
bool QTextDocument::setMinimumWidth( int needed, int used, QTextParagraph *p )
{
if ( needed == -1 ) {
minw = 0;
wused = 0;
p = 0;
}
if ( p == minwParag ) {
minw = needed;
emit minimumWidthChanged( minw );
} else if ( needed > minw ) {
minw = needed;
minwParag = p;
emit minimumWidthChanged( minw );
}
wused = QMAX( wused, used );
wused = QMAX( wused, minw );
cw = QMAX( minw, cw );
return TRUE;
}
void QTextDocument::setPlainText( const QString &text )
{
clear();
preferRichText = FALSE;
oTextValid = TRUE;
oText = text;
int lastNl = 0;
int nl = text.find( '\n' );
if ( nl == -1 ) {
lParag = createParagraph( this, lParag, 0 );
if ( !fParag )
fParag = lParag;
QString s = text;
if ( !s.isEmpty() ) {
if ( s[ (int)s.length() - 1 ] == '\r' )
s.remove( s.length() - 1, 1 );
lParag->append( s );
}
} else {
for (;;) {
lParag = createParagraph( this, lParag, 0 );
if ( !fParag )
fParag = lParag;
QString s = text.mid( lastNl, nl - lastNl );
if ( !s.isEmpty() ) {
if ( s[ (int)s.length() - 1 ] == '\r' )
s.remove( s.length() - 1, 1 );
lParag->append( s );
}
if ( nl == 0xffffff )
break;
lastNl = nl + 1;
nl = text.find( '\n', nl + 1 );
if ( nl == -1 )
nl = 0xffffff;
}
}
if ( !lParag )
lParag = fParag = createParagraph( this, 0, 0 );
}
struct Q_EXPORT QTextDocumentTag {
QTextDocumentTag(){}
QTextDocumentTag( const QString&n, const QStyleSheetItem* s, const QTextFormat& f )
:name(n),style(s), format(f), alignment(Qt3::AlignAuto), direction(QChar::DirON),liststyle(QStyleSheetItem::ListDisc) {
wsm = QStyleSheetItem::WhiteSpaceNormal;
}
QString name;
const QStyleSheetItem* style;
QString anchorHref;
QStyleSheetItem::WhiteSpaceMode wsm;
QTextFormat format;
int alignment : 16;
int direction : 5;
QStyleSheetItem::ListStyle liststyle;
QTextDocumentTag( const QTextDocumentTag& t ) {
name = t.name;
style = t.style;
anchorHref = t.anchorHref;
wsm = t.wsm;
format = t.format;
alignment = t.alignment;
direction = t.direction;
liststyle = t.liststyle;
}
QTextDocumentTag& operator=(const QTextDocumentTag& t) {
name = t.name;
style = t.style;
anchorHref = t.anchorHref;
wsm = t.wsm;
format = t.format;
alignment = t.alignment;
direction = t.direction;
liststyle = t.liststyle;
return *this;
}
#if defined(Q_FULL_TEMPLATE_INSTANTIATION)
bool operator==( const QTextDocumentTag& ) const { return FALSE; }
#endif
};
#define NEWPAR do{ if ( !hasNewPar) { \
if ( !textEditMode && curpar && curpar->length()>1 && curpar->at( curpar->length()-2)->c == QChar_linesep ) \
curpar->remove( curpar->length()-2, 1 ); \
curpar = createParagraph( this, curpar, curpar->next() ); styles.append( vec ); vec = 0;} \
hasNewPar = TRUE; \
curpar->rtext = TRUE; \
curpar->align = curtag.alignment; \
curpar->lstyle = curtag.liststyle; \
curpar->litem = ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ); \
curpar->str->setDirection( (QChar::Direction)curtag.direction ); \
space = TRUE; \
delete vec; vec = new QPtrVector<QStyleSheetItem>( (uint)tags.count() + 1); \
int i = 0; \
for ( QValueStack<QTextDocumentTag>::Iterator it = tags.begin(); it != tags.end(); ++it ) \
vec->insert( i++, (*it).style ); \
vec->insert( i, curtag.style ); \
}while(FALSE)
void QTextDocument::setRichText( const QString &text, const QString &context )
{
if ( !context.isEmpty() )
setContext( context );
clear();
fParag = lParag = createParagraph( this );
oTextValid = TRUE;
oText = text;
setRichTextInternal( text );
fParag->rtext = TRUE;
}
void QTextDocument::setRichTextInternal( const QString &text, QTextCursor* cursor )
{
QTextParagraph* curpar = lParag;
int pos = 0;
QValueStack<QTextDocumentTag> tags;
QTextDocumentTag initag( "", sheet_->item(""), *formatCollection()->defaultFormat() );
QTextDocumentTag curtag = initag;
bool space = TRUE;
bool canMergeLi = FALSE;
bool textEditMode = FALSE;
const QChar* doc = text.unicode();
int length = text.length();
bool hasNewPar = curpar->length() <= 1;
QString anchorName;
// style sheet handling for margin and line spacing calculation below
QTextParagraph* stylesPar = curpar;
QPtrVector<QStyleSheetItem>* vec = 0;
QPtrList< QPtrVector<QStyleSheetItem> > styles;
styles.setAutoDelete( TRUE );
if ( cursor ) {
cursor->splitAndInsertEmptyParagraph();
QTextCursor tmp = *cursor;
tmp.gotoPreviousLetter();
stylesPar = curpar = tmp.paragraph();
hasNewPar = TRUE;
textEditMode = TRUE;
} else {
NEWPAR;
}
// set rtext spacing to FALSE for the initial paragraph.
curpar->rtext = FALSE;
QString wellKnownTags = "br hr wsp table qt body meta title";
while ( pos < length ) {
if ( hasPrefix(doc, length, pos, '<' ) ){
if ( !hasPrefix( doc, length, pos+1, QChar('/') ) ) {
// open tag
QMap<QString, QString> attr;
bool emptyTag = FALSE;
QString tagname = parseOpenTag(doc, length, pos, attr, emptyTag);
if ( tagname.isEmpty() )
continue; // nothing we could do with this, probably parse error
const QStyleSheetItem* nstyle = sheet_->item(tagname);
if ( nstyle ) {
// we might have to close some 'forgotten' tags
while ( !nstyle->allowedInContext( curtag.style ) ) {
QString msg;
msg.sprintf( "QText Warning: Document not valid ( '%s' not allowed in '%s' #%d)",
tagname.ascii(), curtag.style->name().ascii(), pos);
sheet_->error( msg );
if ( tags.isEmpty() )
break;
curtag = tags.pop();
}
/* special handling for p and li for HTML
compatibility. We do not want to embed blocks in
p, and we do not want new blocks inside non-empty
lis. Plus we want to merge empty lis sometimes. */
if( nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
canMergeLi = TRUE;
} else if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock ) {
while ( curtag.style->name() == "p" ) {
if ( tags.isEmpty() )
break;
curtag = tags.pop();
}
if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
// we are in a li and a new block comes along
if ( nstyle->name() == "ul" || nstyle->name() == "ol" )
hasNewPar = FALSE; // we want an empty li (like most browsers)
if ( !hasNewPar ) {
/* do not add new blocks inside
non-empty lis */
while ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
if ( tags.isEmpty() )
break;
curtag = tags.pop();
}
} else if ( canMergeLi ) {
/* we have an empty li and a block
comes along, merge them */
nstyle = curtag.style;
}
canMergeLi = FALSE;
}
}
}
QTextCustomItem* custom = 0;
// some well-known tags, some have a nstyle, some not
if ( wellKnownTags.find( tagname ) != -1 ) {
if ( tagname == "br" ) {
emptyTag = space = TRUE;
int index = QMAX( curpar->length(),1) - 1;
QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
curpar->append( QChar_linesep );
curpar->setFormat( index, 1, &format );
} else if ( tagname == "hr" ) {
emptyTag = space = TRUE;
custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
NEWPAR;
} else if ( tagname == "table" ) {
emptyTag = space = TRUE;
QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
curpar->setAlignment( curtag.alignment );
custom = parseTable( attr, format, doc, length, pos, curpar );
} else if ( tagname == "qt" || tagname == "body" ) {
if ( attr.contains( "bgcolor" ) ) {
QBrush *b = new QBrush( QColor( attr["bgcolor"] ) );
setPaper( b );
}
if ( attr.contains( "background" ) ) {
QImage img;
QString bg = attr["background"];
const QMimeSource* m = factory_->data( bg, contxt );
if ( !m ) {
qWarning("QRichText: no mimesource for %s", bg.latin1() );
} else {
if ( !QImageDrag::decode( m, img ) ) {
qWarning("QTextImage: cannot decode %s", bg.latin1() );
}
}
if ( !img.isNull() ) {
QPixmap pm;
pm.convertFromImage( img );
QBrush *b = new QBrush( QColor(), pm );
setPaper( b );
}
}
if ( attr.contains( "text" ) ) {
QColor c( attr["text"] );
if ( formatCollection()->defaultFormat()->color() != c ) {
QDict<QTextFormat> formats = formatCollection()->dict();
QDictIterator<QTextFormat> it( formats );
while ( it.current() ) {
if ( it.current() == formatCollection()->defaultFormat() ) {
++it;
continue;
}
it.current()->setColor( c );
++it;
}
formatCollection()->defaultFormat()->setColor( c );
curtag.format.setColor( c );
}
}
if ( attr.contains( "link" ) )
linkColor = QColor( attr["link"] );
if ( attr.contains( "title" ) )
attribs.replace( "title", attr["title"] );
if ( textEditMode ) {
if ( attr.contains("style" ) ) {
QString a = attr["style"];
for ( int s = 0; s < a.contains(';')+1; s++ ) {
QString style = QTextDocument::section( a, ";", s, s );
if ( style.startsWith("font-size:" ) && QTextDocument::endsWith(style, "pt") ) {
scaleFontsFactor = double( formatCollection()->defaultFormat()->fn.pointSize() ) /
style.mid( 10, style.length() - 12 ).toInt();
}
}
}
nstyle = 0; // ignore body in textEditMode
}
// end qt- and body-tag handling
} else if ( tagname == "meta" ) {
if ( attr["name"] == "qrichtext" && attr["content"] == "1" )
textEditMode = TRUE;
} else if ( tagname == "title" ) {
QString title;
while ( pos < length ) {
if ( hasPrefix( doc, length, pos, QChar('<') ) && hasPrefix( doc, length, pos+1, QChar('/') ) &&
parseCloseTag( doc, length, pos ) == "title" )
break;
title += doc[ pos ];
++pos;
}
attribs.replace( "title", title );
}
} // end of well-known tag handling
if ( !custom ) // try generic custom item
custom = sheet_->tag( tagname, attr, contxt, *factory_ , emptyTag, this );
if ( !nstyle && !custom ) // we have no clue what this tag could be, ignore it
continue;
if ( custom ) {
int index = QMAX( curpar->length(),1) - 1;
QTextFormat format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
curpar->append( QChar('*') );
curpar->setFormat( index, 1, &format );
curpar->at( index )->setCustomItem( custom );
if ( !curtag.anchorHref.isEmpty() )
curpar->at(index)->setAnchor( QString::null, curtag.anchorHref );
if ( !anchorName.isEmpty() ) {
curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
anchorName = QString::null;
}
registerCustomItem( custom, curpar );
hasNewPar = FALSE;
} else if ( !emptyTag ) {
/* if we do nesting, push curtag on the stack,
otherwise reinint curag. */
if ( curtag.style->name() != tagname || nstyle->selfNesting() ) {
tags.push( curtag );
} else {
if ( !tags.isEmpty() )
curtag = tags.top();
else
curtag = initag;
}
curtag.name = tagname;
curtag.style = nstyle;
curtag.name = tagname;
curtag.style = nstyle;
if ( int(nstyle->whiteSpaceMode()) != QStyleSheetItem::Undefined )
curtag.wsm = nstyle->whiteSpaceMode();
/* ignore whitespace for inline elements if there
was already one*/
if ( !textEditMode && curtag.wsm == QStyleSheetItem::WhiteSpaceNormal
&& ( space || nstyle->displayMode() != QStyleSheetItem::DisplayInline ) )
eatSpace( doc, length, pos );
curtag.format = curtag.format.makeTextFormat( nstyle, attr, scaleFontsFactor );
if ( nstyle->isAnchor() ) {
if ( !anchorName.isEmpty() )
anchorName += "#" + attr["name"];
else
anchorName = attr["name"];
curtag.anchorHref = attr["href"];
}
if ( nstyle->alignment() != QStyleSheetItem::Undefined )
curtag.alignment = nstyle->alignment();
if ( (int) nstyle->listStyle() != QStyleSheetItem::Undefined )
curtag.liststyle = nstyle->listStyle();
if ( nstyle->displayMode() == QStyleSheetItem::DisplayBlock
|| nstyle->displayMode() == QStyleSheetItem::DisplayListItem ) {
if ( nstyle->name() == "ol" || nstyle->name() == "ul" || nstyle->name() == "li") {
QString type = attr["type"];
if ( !type.isEmpty() ) {
if ( type == "1" ) {
curtag.liststyle = QStyleSheetItem::ListDecimal;
} else if ( type == "a" ) {
curtag.liststyle = QStyleSheetItem::ListLowerAlpha;
} else if ( type == "A" ) {
curtag.liststyle = QStyleSheetItem::ListUpperAlpha;
} else {
type = type.lower();
if ( type == "square" )
curtag.liststyle = QStyleSheetItem::ListSquare;
else if ( type == "disc" )
curtag.liststyle = QStyleSheetItem::ListDisc;
else if ( type == "circle" )
curtag.liststyle = QStyleSheetItem::ListCircle;
}
}
}
/* Internally we treat ordered and bullet
lists the same for margin calculations. In
order to have fast pointer compares in the
xMargin() functions we restrict ourselves to
<ol>. Once we calculate the margins in the
parser rathern than later, the unelegance of
this approach goes awy
*/
if ( nstyle->name() == "ul" )
curtag.style = sheet_->item( "ol" );
if ( attr.contains( "align" ) ) {
QString align = attr["align"];
if ( align == "center" )
curtag.alignment = Qt::AlignCenter;
else if ( align == "right" )
curtag.alignment = Qt::AlignRight;
else if ( align == "justify" )
curtag.alignment = Qt3::AlignJustify;
}
if ( attr.contains( "dir" ) ) {
QString dir = attr["dir"];
if ( dir == "rtl" )
curtag.direction = QChar::DirR;
else if ( dir == "ltr" )
curtag.direction = QChar::DirL;
}
NEWPAR;
if ( curtag.style->displayMode() == QStyleSheetItem::DisplayListItem ) {
if ( attr.contains( "value " ) )
curpar->setListValue( attr["value"].toInt() );
}
if ( attr.contains( "style" ) ) {
QString a = attr["style"];
bool ok = TRUE;
for ( int s = 0; ok && s < a.contains(';')+1; s++ ) {
QString style = QTextDocument::section( a, ";", s, s );
if ( style.startsWith("margin-top:" ) && QTextDocument::endsWith(style, "px") )
curpar->utm = 1+style.mid(11, style.length() - 13).toInt(&ok);
else if ( style.startsWith("margin-bottom:" ) && QTextDocument::endsWith(style, "px") )
curpar->ubm = 1+style.mid(14, style.length() - 16).toInt(&ok);
else if ( style.startsWith("margin-left:" ) && QTextDocument::endsWith(style, "px") )
curpar->ulm = 1+style.mid(12, style.length() - 14).toInt(&ok);
else if ( style.startsWith("margin-right:" ) && QTextDocument::endsWith(style, "px") )
curpar->urm = 1+style.mid(13, style.length() - 15).toInt(&ok);
else if ( style.startsWith("text-indent:" ) && QTextDocument::endsWith(style, "px") )
curpar->uflm = 1+style.mid(12, style.length() - 14).toInt(&ok);
}
if ( !ok ) // be pressmistic
curpar->utm = curpar->ubm = curpar->urm = curpar->ulm = 0;
}
}
}
} else {
QString tagname = parseCloseTag( doc, length, pos );
if ( tagname.isEmpty() )
continue; // nothing we could do with this, probably parse error
if ( !sheet_->item( tagname ) ) // ignore unknown tags
continue;
// we close a block item. Since the text may continue, we need to have a new paragraph
bool needNewPar = curtag.style->displayMode() == QStyleSheetItem::DisplayBlock
|| curtag.style->displayMode() == QStyleSheetItem::DisplayListItem;
// html slopiness: handle unbalanched tag closing
while ( curtag.name != tagname ) {
QString msg;
msg.sprintf( "QText Warning: Document not valid ( '%s' not closed before '%s' #%d)",
curtag.name.ascii(), tagname.ascii(), pos);
sheet_->error( msg );
if ( tags.isEmpty() )
break;
curtag = tags.pop();
}
// close the tag
if ( !tags.isEmpty() )
curtag = tags.pop();
else
curtag = initag;
if ( needNewPar ) {
if ( textEditMode && tagname == "p" ) // preserve empty paragraphs
hasNewPar = FALSE;
NEWPAR;
}
}
} else {
// normal contents
QString s;
QChar c;
while ( pos < length && !hasPrefix(doc, length, pos, QChar('<') ) ){
if ( textEditMode ) {
// text edit mode: we handle all white space but ignore newlines
c = parseChar( doc, length, pos, QStyleSheetItem::WhiteSpacePre );
if ( c == QChar_linesep )
break;
} else {
int l = pos;
c = parseChar( doc, length, pos, curtag.wsm );
// in white space pre mode: treat any space as non breakable
if ( c == ' ' && curtag.wsm == QStyleSheetItem::WhiteSpacePre )
c = QChar::nbsp;
if ( c == ' ' || c == QChar_linesep ) {
/* avoid overlong paragraphs by forcing a new
paragraph after 4096 characters. This case can
occur when loading undiscovered plain text
documents in rich text mode. Instead of hanging
forever, we do the trick.
*/
if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && s.length() > 4096 ) do {
if ( doc[l] == '\n' ) {
hasNewPar = FALSE; // for a new paragraph ...
NEWPAR;
hasNewPar = FALSE; // ... and make it non-reusable
c = '\n'; // make sure we break below
break;
}
} while ( ++l < pos );
}
}
if ( c == '\n' )
break; // break on newlines, pre delievers a QChar_linesep
bool c_isSpace = c.isSpace() && c.unicode() != 0x00a0U && !textEditMode;
if ( curtag.wsm == QStyleSheetItem::WhiteSpaceNormal && c_isSpace && space )
continue;
if ( c == '\r' )
continue;
space = c_isSpace;
s += c;
}
if ( !s.isEmpty() && curtag.style->displayMode() != QStyleSheetItem::DisplayNone ) {
hasNewPar = FALSE;
int index = QMAX( curpar->length(),1) - 1;
curpar->append( s );
QTextFormat* f = formatCollection()->format( &curtag.format );
curpar->setFormat( index, s.length(), f, FALSE ); // do not use collection because we have done that already
f->ref += s.length() -1; // that what friends are for...
if ( !curtag.anchorHref.isEmpty() ) {
for ( int i = 0; i < int(s.length()); i++ )
curpar->at(index + i)->setAnchor( QString::null, curtag.anchorHref );
}
if ( !anchorName.isEmpty() ) {
curpar->at(index)->setAnchor( anchorName, curpar->at(index)->anchorHref() );
anchorName = QString::null;
}
}
}
}
if ( hasNewPar && curpar != fParag && !cursor ) {
// cleanup unused last paragraphs
curpar = curpar->p;
delete curpar->n;
}
if ( !anchorName.isEmpty() ) {
curpar->at(curpar->length() - 1)->setAnchor( anchorName, curpar->at( curpar->length() - 1 )->anchorHref() );
anchorName = QString::null;
}
setRichTextMarginsInternal( styles, stylesPar );
if ( cursor ) {
cursor->gotoPreviousLetter();
cursor->remove();
}
}
void QTextDocument::setRichTextMarginsInternal( QPtrList< QPtrVector<QStyleSheetItem> >& styles, QTextParagraph* stylesPar )
{
// margin and line spacing calculation
QPtrVector<QStyleSheetItem>* prevStyle = 0;
QPtrVector<QStyleSheetItem>* curStyle = styles.first();
QPtrVector<QStyleSheetItem>* nextStyle = styles.next();
while ( stylesPar ) {
if ( !curStyle ) {
stylesPar = stylesPar->next();
prevStyle = curStyle;
curStyle = nextStyle;
nextStyle = styles.next();
continue;
}
int i, mar;
QStyleSheetItem* mainStyle = curStyle->size() ? (*curStyle)[curStyle->size()-1] : 0;
if ( mainStyle && mainStyle->displayMode() == QStyleSheetItem::DisplayListItem )
stylesPar->setListItem( TRUE );
int numLists = 0;
for ( i = 0; i < (int)curStyle->size(); ++i ) {
if ( (*curStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
&& int((*curStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined )
numLists++;
}
stylesPar->ldepth = numLists;
if ( stylesPar->next() && nextStyle ) {
// also set the depth of the next paragraph, required for the margin calculation
numLists = 0;
for ( i = 0; i < (int)nextStyle->size(); ++i ) {
if ( (*nextStyle)[ i ]->displayMode() == QStyleSheetItem::DisplayBlock
&& int((*nextStyle)[ i ]->listStyle()) != QStyleSheetItem::Undefined )
numLists++;
}
stylesPar->next()->ldepth = numLists;
}
// do the top margin
QStyleSheetItem* item = mainStyle;
int m;
if (stylesPar->utm > 0 ) {
m = stylesPar->utm-1;
stylesPar->utm = 0;
} else {
m = QMAX(0, item->margin( QStyleSheetItem::MarginTop ) );
if ( item->displayMode() == QStyleSheetItem::DisplayListItem
&& stylesPar->ldepth )
m /= stylesPar->ldepth;
}
for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
if ( prevStyle && i < (int) prevStyle->size() &&
( item->displayMode() == QStyleSheetItem::DisplayBlock &&
(*prevStyle)[ i ] == item ) )
break;
// emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
if ( int(item->listStyle()) != QStyleSheetItem::Undefined &&
( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
continue;
mar = QMAX( 0, item->margin( QStyleSheetItem::MarginTop ) );
m = QMAX( m, mar );
}
stylesPar->utm = m - stylesPar->topMargin();
// do the bottom margin
item = mainStyle;
if (stylesPar->ubm > 0 ) {
m = stylesPar->ubm-1;
stylesPar->ubm = 0;
} else {
m = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
if ( item->displayMode() == QStyleSheetItem::DisplayListItem
&& stylesPar->ldepth )
m /= stylesPar->ldepth;
}
for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
if ( nextStyle && i < (int) nextStyle->size() &&
( item->displayMode() == QStyleSheetItem::DisplayBlock &&
(*nextStyle)[ i ] == item ) )
break;
// emulate CSS2' standard 0 vertical margin for multiple ul or ol tags
if ( int(item->listStyle()) != QStyleSheetItem::Undefined &&
( ( i> 0 && (*curStyle)[ i-1 ] == item ) || (*curStyle)[i+1] == item ) )
continue;
mar = QMAX(0, item->margin( QStyleSheetItem::MarginBottom ) );
m = QMAX( m, mar );
}
stylesPar->ubm = m - stylesPar->bottomMargin();
// do the left margin, simplyfied
item = mainStyle;
if (stylesPar->ulm > 0 ) {
m = stylesPar->ulm-1;
stylesPar->ulm = 0;
} else {
m = QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
}
for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
m += QMAX( 0, item->margin( QStyleSheetItem::MarginLeft ) );
}
stylesPar->ulm = m - stylesPar->leftMargin();
// do the right margin, simplyfied
item = mainStyle;
if (stylesPar->urm > 0 ) {
m = stylesPar->urm-1;
stylesPar->urm = 0;
} else {
m = QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
}
for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
m += QMAX( 0, item->margin( QStyleSheetItem::MarginRight ) );
}
stylesPar->urm = m - stylesPar->rightMargin();
// do the first line margin, which really should be called text-indent
item = mainStyle;
if (stylesPar->uflm > 0 ) {
m = stylesPar->uflm-1;
stylesPar->uflm = 0;
} else {
m = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
}
for ( i = (int)curStyle->size() - 2 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
mar = QMAX( 0, item->margin( QStyleSheetItem::MarginFirstLine ) );
m = QMAX( m, mar );
}
stylesPar->uflm =m - stylesPar->firstLineMargin();
// do the bogus line "spacing", which really is just an extra margin
item = mainStyle;
for ( i = (int)curStyle->size() - 1 ; i >= 0; --i ) {
item = (*curStyle)[ i ];
if ( item->lineSpacing() != QStyleSheetItem::Undefined ) {
stylesPar->ulinespacing = item->lineSpacing();
if ( formatCollection() &&
stylesPar->ulinespacing < formatCollection()->defaultFormat()->height() )
stylesPar->ulinespacing += formatCollection()->defaultFormat()->height();
break;
}
}
stylesPar = stylesPar->next();
prevStyle = curStyle;
curStyle = nextStyle;
nextStyle = styles.next();
}
}
void QTextDocument::setText( const QString &text, const QString &context )
{
focusIndicator.parag = 0;
selections.clear();
if ( txtFormat == Qt::AutoText && QStyleSheet::mightBeRichText( text ) ||
txtFormat == Qt::RichText )
setRichText( text, context );
else
setPlainText( text );
}
QString QTextDocument::plainText() const
{
QString buffer;
QString s;
QTextParagraph *p = fParag;
while ( p ) {
if ( !p->mightHaveCustomItems ) {
s = p->string()->toString();
} else {
for ( int i = 0; i < p->length() - 1; ++i ) {
if ( p->at( i )->isCustom() ) {
if ( p->at( i )->customItem()->isNested() ) {
s += "\n";
QTextTable *t = (QTextTable*)p->at( i )->customItem();
QPtrList<QTextTableCell> cells = t->tableCells();
for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
s += c->richText()->plainText() + "\n";
s += "\n";
}
} else {
s += p->at( i )->c;
}
}
}
s.remove( s.length() - 1, 1 );
if ( p->next() )
s += "\n";
buffer += s;
p = p->next();
}
return buffer;
}
static QString align_to_string( int a )
{
if ( a & Qt::AlignRight )
return " align=\"right\"";
if ( a & Qt::AlignHCenter )
return " align=\"center\"";
if ( a & Qt3::AlignJustify )
return " align=\"justify\"";
return QString::null;
}
static QString direction_to_string( int d )
{
if ( d != QChar::DirON )
return ( d == QChar::DirL? " dir=\"ltr\"" : " dir=\"rtl\"" );
return QString::null;
}
static QString list_value_to_string( int v )
{
if ( v != -1 )
return " listvalue=\"" + QString::number( v ) + "\"";
return QString::null;
}
static QString list_style_to_string( int v )
{
switch( v ) {
case QStyleSheetItem::ListDecimal: return "\"1\"";
case QStyleSheetItem::ListLowerAlpha: return "\"a\"";
case QStyleSheetItem::ListUpperAlpha: return "\"A\"";
case QStyleSheetItem::ListDisc: return "\"disc\"";
case QStyleSheetItem::ListSquare: return "\"square\"";
case QStyleSheetItem::ListCircle: return "\"circle\"";
default:
return QString::null;
}
}
static inline bool list_is_ordered( int v )
{
return v == QStyleSheetItem::ListDecimal ||
v == QStyleSheetItem::ListLowerAlpha ||
v == QStyleSheetItem::ListUpperAlpha;
}
static QString margin_to_string( QStyleSheetItem* style, int t, int b, int l, int r, int fl )
{
QString s;
if ( l > 0 )
s += QString(!!s?";":"") + "margin-left:" + QString::number(l+QMAX(0,style->margin(QStyleSheetItem::MarginLeft))) + "px";
if ( r > 0 )
s += QString(!!s?";":"") + "margin-right:" + QString::number(r+QMAX(0,style->margin(QStyleSheetItem::MarginRight))) + "px";
if ( t > 0 )
s += QString(!!s?";":"") + "margin-top:" + QString::number(t+QMAX(0,style->margin(QStyleSheetItem::MarginTop))) + "px";
if ( b > 0 )
s += QString(!!s?";":"") + "margin-bottom:" + QString::number(b+QMAX(0,style->margin(QStyleSheetItem::MarginBottom))) + "px";
if ( fl > 0 )
s += QString(!!s?";":"") + "text-indent:" + QString::number(fl+QMAX(0,style->margin(QStyleSheetItem::MarginFirstLine))) + "px";
if ( !!s )
return " style=\"" + s + "\"";
return QString::null;
}
QString QTextDocument::richText() const
{
QString s = "";
if ( !par ) {
s += "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:" ;
s += QString::number( formatCollection()->defaultFormat()->font().pointSize() );
s += "pt;font-family:";
s += formatCollection()->defaultFormat()->font().family();
s +="\">";
}
QTextParagraph* p = fParag;
QStyleSheetItem* item_p = styleSheet()->item("p");
QStyleSheetItem* item_ul = styleSheet()->item("ul");
QStyleSheetItem* item_ol = styleSheet()->item("ol");
QStyleSheetItem* item_li = styleSheet()->item("li");
if ( !item_p || !item_ul || !item_ol || !item_li ) {
qWarning( "QTextEdit: cannot export HTML due to insufficient stylesheet (lack of p, ul, ol, or li)" );
return QString::null;
}
int pastListDepth = 0;
int listDepth = 0;
int futureListDepth = 0;
QMemArray<int> listStyles(10);
while ( p ) {
listDepth = p->listDepth();
if ( listDepth < pastListDepth ) {
for ( int i = listDepth+1; i <= pastListDepth; i++ )
s += list_is_ordered( listStyles[i] ) ? "</ol>" : "</ul>";
s += '\n';
} else if ( listDepth > pastListDepth ) {
s += '\n';
listStyles.resize( QMAX( (int)listStyles.size(), listDepth+1 ) );
QString list_type;
listStyles[listDepth] = p->listStyle();
if ( !list_is_ordered( p->listStyle() ) || item_ol->listStyle() != p->listStyle() )
list_type = " type=" + list_style_to_string( p->listStyle() );
for ( int i = pastListDepth; i < listDepth; i++ ) {
s += list_is_ordered( p->listStyle() ) ? "<ol" : "<ul" ;
s += list_type + ">";
}
} else {
s += '\n';
}
QString ps = p->richText();
// for the bottom margin we need to know whether we are at the end of a list
futureListDepth = 0;
if ( listDepth > 0 && p->next() )
futureListDepth = p->next()->listDepth();
if ( richTextExportStart && richTextExportStart->paragraph() ==p &&
richTextExportStart->index() == 0 )
s += "<selstart/>";
if ( p->isListItem() ) {
s += "<li";
if ( p->listStyle() != listStyles[listDepth] )
s += " type=" + list_style_to_string( p->listStyle() );
s +=align_to_string( p->alignment() );
s += margin_to_string( item_li, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
s += list_value_to_string( p->listValue() );
s += direction_to_string( p->direction() );
s +=">";
s += ps;
s += "</li>";
} else {
// normal paragraph item
s += "<p";
s += align_to_string( p->alignment() );
s += margin_to_string( item_p, p->utm, p->ubm, p->ulm, p->urm, p->uflm );
s +=direction_to_string( p->direction() );
s += ">";
s += ps;
s += "</p>";
}
pastListDepth = listDepth;
p = p->next();
}
while ( listDepth > 0 ) {
s += list_is_ordered( listStyles[listDepth] ) ? "</ol>" : "</ul>";
listDepth--;
}
if ( !par )
s += "\n</body></html>\n";
return s;
}
QString QTextDocument::text() const
{
if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
return richText();
return plainText();
}
QString QTextDocument::text( int parag ) const
{
QTextParagraph *p = paragAt( parag );
if ( !p )
return QString::null;
if ( txtFormat == Qt::AutoText && preferRichText || txtFormat == Qt::RichText )
return p->richText();
else
return p->string()->toString();
}
void QTextDocument::invalidate()
{
QTextParagraph *s = fParag;
while ( s ) {
s->invalidate( 0 );
s = s->next();
}
}
void QTextDocument::selectionStart( int id, int &paragId, int &index )
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return;
QTextDocumentSelection &sel = *it;
paragId = !sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
index = !sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
}
QTextCursor QTextDocument::selectionStartCursor( int id)
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return QTextCursor( this );
QTextDocumentSelection &sel = *it;
if ( sel.swapped )
return sel.endCursor;
return sel.startCursor;
}
QTextCursor QTextDocument::selectionEndCursor( int id)
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return QTextCursor( this );
QTextDocumentSelection &sel = *it;
if ( !sel.swapped )
return sel.endCursor;
return sel.startCursor;
}
void QTextDocument::selectionEnd( int id, int &paragId, int &index )
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return;
QTextDocumentSelection &sel = *it;
paragId = sel.swapped ? sel.startCursor.paragraph()->paragId() : sel.endCursor.paragraph()->paragId();
index = sel.swapped ? sel.startCursor.index() : sel.endCursor.index();
}
void QTextDocument::addSelection( int id )
{
nSelections = QMAX( nSelections, id + 1 );
}
static void setSelectionEndHelper( int id, QTextDocumentSelection &sel, QTextCursor &start, QTextCursor &end )
{
QTextCursor c1 = start;
QTextCursor c2 = end;
if ( sel.swapped ) {
c1 = end;
c2 = start;
}
c1.paragraph()->removeSelection( id );
c2.paragraph()->removeSelection( id );
if ( c1.paragraph() != c2.paragraph() ) {
c1.paragraph()->setSelection( id, c1.index(), c1.paragraph()->length() - 1 );
c2.paragraph()->setSelection( id, 0, c2.index() );
} else {
c1.paragraph()->setSelection( id, QMIN( c1.index(), c2.index() ), QMAX( c1.index(), c2.index() ) );
}
sel.startCursor = start;
sel.endCursor = end;
if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
sel.swapped = sel.startCursor.index() > sel.endCursor.index();
}
bool QTextDocument::setSelectionEnd( int id, const QTextCursor &cursor )
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return FALSE;
QTextDocumentSelection &sel = *it;
QTextCursor start = sel.startCursor;
QTextCursor end = cursor;
if ( start == end ) {
removeSelection( id );
setSelectionStart( id, cursor );
return TRUE;
}
if ( sel.endCursor.paragraph() == end.paragraph() ) {
setSelectionEndHelper( id, sel, start, end );
return TRUE;
}
bool inSelection = FALSE;
QTextCursor c( this );
QTextCursor tmp = sel.startCursor;
if ( sel.swapped )
tmp = sel.endCursor;
tmp.restoreState();
QTextCursor tmp2 = cursor;
tmp2.restoreState();
c.setParagraph( tmp.paragraph()->paragId() < tmp2.paragraph()->paragId() ? tmp.paragraph() : tmp2.paragraph() );
bool hadStart = FALSE;
bool hadEnd = FALSE;
bool hadStartParag = FALSE;
bool hadEndParag = FALSE;
bool hadOldStart = FALSE;
bool hadOldEnd = FALSE;
bool leftSelection = FALSE;
sel.swapped = FALSE;
for ( ;; ) {
if ( c == start )
hadStart = TRUE;
if ( c == end )
hadEnd = TRUE;
if ( c.paragraph() == start.paragraph() )
hadStartParag = TRUE;
if ( c.paragraph() == end.paragraph() )
hadEndParag = TRUE;
if ( c == sel.startCursor )
hadOldStart = TRUE;
if ( c == sel.endCursor )
hadOldEnd = TRUE;
if ( !sel.swapped &&
( hadEnd && !hadStart ||
hadEnd && hadStart && start.paragraph() == end.paragraph() && start.index() > end.index() ) )
sel.swapped = TRUE;
if ( c == end && hadStartParag ||
c == start && hadEndParag ) {
QTextCursor tmp = c;
tmp.restoreState();
if ( tmp.paragraph() != c.paragraph() ) {
int sstart = tmp.paragraph()->selectionStart( id );
tmp.paragraph()->removeSelection( id );
tmp.paragraph()->setSelection( id, sstart, tmp.index() );
}
}
if ( inSelection &&
( c == end && hadStart || c == start && hadEnd ) )
leftSelection = TRUE;
else if ( !leftSelection && !inSelection && ( hadStart || hadEnd ) )
inSelection = TRUE;
bool noSelectionAnymore = hadOldStart && hadOldEnd && leftSelection && !inSelection && !c.paragraph()->hasSelection( id ) && c.atParagEnd();
c.paragraph()->removeSelection( id );
if ( inSelection ) {
if ( c.paragraph() == start.paragraph() && start.paragraph() == end.paragraph() ) {
c.paragraph()->setSelection( id, QMIN( start.index(), end.index() ), QMAX( start.index(), end.index() ) );
} else if ( c.paragraph() == start.paragraph() && !hadEndParag ) {
c.paragraph()->setSelection( id, start.index(), c.paragraph()->length() - 1 );
} else if ( c.paragraph() == end.paragraph() && !hadStartParag ) {
c.paragraph()->setSelection( id, end.index(), c.paragraph()->length() - 1 );
} else if ( c.paragraph() == end.paragraph() && hadEndParag ) {
c.paragraph()->setSelection( id, 0, end.index() );
} else if ( c.paragraph() == start.paragraph() && hadStartParag ) {
c.paragraph()->setSelection( id, 0, start.index() );
} else {
c.paragraph()->setSelection( id, 0, c.paragraph()->length() - 1 );
}
}
if ( leftSelection )
inSelection = FALSE;
if ( noSelectionAnymore )
break;
// *ugle*hack optimization
QTextParagraph *p = c.paragraph();
if ( p->mightHaveCustomItems || p == start.paragraph() || p == end.paragraph() || p == lastParagraph() ) {
c.gotoNextLetter();
if ( p == lastParagraph() && c.atParagEnd() )
break;
} else {
if ( p->document()->parent() )
do {
c.gotoNextLetter();
} while ( c.paragraph() == p );
else
c.setParagraph( p->next() );
}
}
if ( !sel.swapped )
sel.startCursor.paragraph()->setSelection( id, sel.startCursor.index(), sel.startCursor.paragraph()->length() - 1 );
sel.startCursor = start;
sel.endCursor = end;
if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() )
sel.swapped = sel.startCursor.index() > sel.endCursor.index();
setSelectionEndHelper( id, sel, start, end );
return TRUE;
}
void QTextDocument::selectAll( int id )
{
removeSelection( id );
QTextDocumentSelection sel;
sel.swapped = FALSE;
QTextCursor c( this );
c.setParagraph( fParag );
c.setIndex( 0 );
sel.startCursor = c;
c.setParagraph( lParag );
c.setIndex( lParag->length() - 1 );
sel.endCursor = c;
selections.insert( id, sel );
QTextParagraph *p = fParag;
while ( p ) {
p->setSelection( id, 0, p->length() - 1 );
p = p->next();
}
for ( QTextDocument *d = childList.first(); d; d = childList.next() )
d->selectAll( id );
}
bool QTextDocument::removeSelection( int id )
{
if ( !selections.contains( id ) )
return FALSE;
QTextDocumentSelection &sel = selections[ id ];
QTextCursor start = sel.swapped ? sel.endCursor : sel.startCursor;
QTextCursor end = sel.swapped ? sel.startCursor : sel.endCursor;
QTextParagraph* p = 0;
while ( start != end ) {
if ( p != start.paragraph() ) {
p = start.paragraph();
p->removeSelection( id );
}
start.gotoNextLetter();
}
selections.remove( id );
return TRUE;
}
QString QTextDocument::selectedText( int id, bool asRichText ) const
{
QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
if ( it == selections.end() )
return QString::null;
QTextDocumentSelection sel = *it;
QTextCursor c1 = sel.startCursor;
QTextCursor c2 = sel.endCursor;
if ( sel.swapped ) {
c2 = sel.startCursor;
c1 = sel.endCursor;
}
/* 3.0.3 improvement: Make it possible to get a reasonable
selection inside a table. This approach is very conservative:
make sure that both cursors have the same depth level and point
to paragraphs within the same text document.
Meaning if you select text in two table cells, you will get the
entire table. This is still far better than the 3.0.2, where
you always got the entire table.
### Fix this properly when refactoring
*/
while ( c2.nestedDepth() > c1.nestedDepth() )
c2.oneUp();
while ( c1.nestedDepth() > c2.nestedDepth() )
c1.oneUp();
while ( c1.nestedDepth() && c2.nestedDepth() &&
c1.paragraph()->document() != c2.paragraph()->document() ) {
c1.oneUp();
c2.oneUp();
}
// do not trust sel_swapped with tables. Fix this properly when refactoring as well
if ( c1.paragraph()->paragId() > c2.paragraph()->paragId() ||
(c1.paragraph() == c2.paragraph() && c1.index() > c2.index() ) ) {
QTextCursor tmp = c1;
c2 = c1;
c1 = tmp;
}
// end selection 3.0.3 improvement
if ( asRichText && !parent() ) {
richTextExportStart = &c1;
richTextExportEnd = &c2;
QString sel = richText();
int from = sel.find( "<selstart/>" );
int to = sel.findRev( "<selend/>" );
if ( from >= 0 && from <= to )
sel = sel.mid( from, to - from );
richTextExportStart = richTextExportEnd = 0;
return sel;
}
QString s;
if ( c1.paragraph() == c2.paragraph() ) {
QTextParagraph *p = c1.paragraph();
int end = c2.index();
if ( p->at( QMAX( 0, end - 1 ) )->isCustom() )
++end;
if ( !p->mightHaveCustomItems ) {
s += p->string()->toString().mid( c1.index(), end - c1.index() );
} else {
for ( int i = c1.index(); i < end; ++i ) {
if ( p->at( i )->isCustom() ) {
if ( p->at( i )->customItem()->isNested() ) {
s += "\n";
QTextTable *t = (QTextTable*)p->at( i )->customItem();
QPtrList<QTextTableCell> cells = t->tableCells();
for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
s += c->richText()->plainText() + "\n";
s += "\n";
}
} else {
s += p->at( i )->c;
}
}
}
} else {
QTextParagraph *p = c1.paragraph();
int start = c1.index();
while ( p ) {
int end = p == c2.paragraph() ? c2.index() : p->length() - 1;
if ( p == c2.paragraph() && p->at( QMAX( 0, end - 1 ) )->isCustom() )
++end;
if ( !p->mightHaveCustomItems ) {
s += p->string()->toString().mid( start, end - start );
if ( p != c2.paragraph() )
s += "\n";
} else {
for ( int i = start; i < end; ++i ) {
if ( p->at( i )->isCustom() ) {
if ( p->at( i )->customItem()->isNested() ) {
s += "\n";
QTextTable *t = (QTextTable*)p->at( i )->customItem();
QPtrList<QTextTableCell> cells = t->tableCells();
for ( QTextTableCell *c = cells.first(); c; c = cells.next() )
s += c->richText()->plainText() + "\n";
s += "\n";
}
} else {
s += p->at( i )->c;
}
}
}
start = 0;
if ( p == c2.paragraph() )
break;
p = p->next();
}
}
// ### workaround for plain text export until we get proper
// mime types: turn unicode line seperators into the more
// widely understood \n. Makes copy and pasting code snipplets
// from within Assistent possible
QChar* uc = (QChar*) s.unicode();
for ( uint ii = 0; ii < s.length(); ii++ )
if ( uc[(int)ii] == QChar_linesep )
uc[(int)ii] = QChar('\n');
return s;
}
void QTextDocument::setFormat( int id, QTextFormat *f, int flags )
{
QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( id );
if ( it == selections.end() )
return;
QTextDocumentSelection sel = *it;
QTextCursor c1 = sel.startCursor;
QTextCursor c2 = sel.endCursor;
if ( sel.swapped ) {
c2 = sel.startCursor;
c1 = sel.endCursor;
}
c2.restoreState();
c1.restoreState();
if ( c1.paragraph() == c2.paragraph() ) {
c1.paragraph()->setFormat( c1.index(), c2.index() - c1.index(), f, TRUE, flags );
return;
}
c1.paragraph()->setFormat( c1.index(), c1.paragraph()->length() - c1.index(), f, TRUE, flags );
QTextParagraph *p = c1.paragraph()->next();
while ( p && p != c2.paragraph() ) {
p->setFormat( 0, p->length(), f, TRUE, flags );
p = p->next();
}
c2.paragraph()->setFormat( 0, c2.index(), f, TRUE, flags );
}
void QTextDocument::removeSelectedText( int id, QTextCursor *cursor )
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return;
QTextDocumentSelection sel = *it;
QTextCursor c1 = sel.startCursor;
QTextCursor c2 = sel.endCursor;
if ( sel.swapped ) {
c2 = sel.startCursor;
c1 = sel.endCursor;
}
// ### no support for editing tables yet
if ( c1.nestedDepth() || c2.nestedDepth() )
return;
c2.restoreState();
c1.restoreState();
*cursor = c1;
removeSelection( id );
if ( c1.paragraph() == c2.paragraph() ) {
c1.paragraph()->remove( c1.index(), c2.index() - c1.index() );
return;
}
if ( c1.paragraph() == fParag && c1.index() == 0 &&
c2.paragraph() == lParag && c2.index() == lParag->length() - 1 )
cursor->setValid( FALSE );
bool didGoLeft = FALSE;
if ( c1.index() == 0 && c1.paragraph() != fParag ) {
cursor->gotoPreviousLetter();
if ( cursor->isValid() )
didGoLeft = TRUE;
}
c1.paragraph()->remove( c1.index(), c1.paragraph()->length() - 1 - c1.index() );
QTextParagraph *p = c1.paragraph()->next();
int dy = 0;
QTextParagraph *tmp;
while ( p && p != c2.paragraph() ) {
tmp = p->next();
dy -= p->rect().height();
delete p;
p = tmp;
}
c2.paragraph()->remove( 0, c2.index() );
while ( p ) {
p->move( dy );
p->invalidate( 0 );
p->setEndState( -1 );
p = p->next();
}
c1.paragraph()->join( c2.paragraph() );
if ( didGoLeft )
cursor->gotoNextLetter();
}
void QTextDocument::indentSelection( int id )
{
QMap<int, QTextDocumentSelection>::Iterator it = selections.find( id );
if ( it == selections.end() )
return;
QTextDocumentSelection sel = *it;
QTextParagraph *startParag = sel.startCursor.paragraph();
QTextParagraph *endParag = sel.endCursor.paragraph();
if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
endParag = sel.startCursor.paragraph();
startParag = sel.endCursor.paragraph();
}
QTextParagraph *p = startParag;
while ( p && p != endParag ) {
p->indent();
p = p->next();
}
}
void QTextDocument::addCommand( QTextCommand *cmd )
{
commandHistory->addCommand( cmd );
}
QTextCursor *QTextDocument::undo( QTextCursor *c )
{
return commandHistory->undo( c );
}
QTextCursor *QTextDocument::redo( QTextCursor *c )
{
return commandHistory->redo( c );
}
bool QTextDocument::find( QTextCursor& cursor, const QString &e, bool cs, bool wo, bool forward )
{
removeSelection( Standard );
QTextParagraph *p = 0;
QString expr = e;
// if we search for 'word only' than we have to be sure that
// the expression contains no space or punct character at the
// beginning or in the end. Otherwise we would run into a
// endlessloop.
if ( wo ) {
for ( ;; ) {
if ( expr[ 0 ].isSpace() || expr[ 0 ].isPunct() )
expr = expr.right( expr.length() - 1 );
else
break;
}
for ( ;; ) {
if ( expr.at( expr.length() - 1 ).isSpace() || expr.at( expr.length() - 1 ).isPunct() )
expr = expr.left( expr.length() - 1 );
else
break;
}
}
for (;;) {
if ( p != cursor.paragraph() ) {
p = cursor.paragraph();
QString s = cursor.paragraph()->string()->toString();
int start = cursor.index();
for ( ;; ) {
int res = forward ? s.find( expr, start, cs ) : s.findRev( expr, start, cs );
int end = res + expr.length();
if ( res == -1 || ( !forward && start < end ) )
break;
if ( !wo || ( ( res == 0 || s[ res - 1 ].isSpace() || s[ res - 1 ].isPunct() ) &&
( end == (int)s.length() || s[ end ].isSpace() || s[ end ].isPunct() ) ) ) {
removeSelection( Standard );
cursor.setIndex( forward ? end : res );
setSelectionStart( Standard, cursor );
cursor.setIndex( forward ? res : end );
setSelectionEnd( Standard, cursor );
return TRUE;
}
start = res + (forward ? 1 : -1);
}
}
if ( forward ) {
if ( cursor.paragraph() == lastParagraph() && cursor.atParagEnd () )
break;
cursor.gotoNextLetter();
} else {
if ( cursor.paragraph() == firstParagraph() && cursor.atParagStart() )
break;
cursor.gotoPreviousLetter();
}
}
return FALSE;
}
void QTextDocument::setTextFormat( Qt::TextFormat f )
{
txtFormat = f;
if ( fParag == lParag && fParag->length() <= 1 )
fParag->rtext = ( f == Qt::RichText );
}
Qt::TextFormat QTextDocument::textFormat() const
{
return txtFormat;
}
bool QTextDocument::inSelection( int selId, const QPoint &pos ) const
{
QMap<int, QTextDocumentSelection>::ConstIterator it = selections.find( selId );
if ( it == selections.end() )
return FALSE;
QTextDocumentSelection sel = *it;
QTextParagraph *startParag = sel.startCursor.paragraph();
QTextParagraph *endParag = sel.endCursor.paragraph();
if ( sel.startCursor.paragraph() == sel.endCursor.paragraph() &&
sel.startCursor.paragraph()->selectionStart( selId ) == sel.endCursor.paragraph()->selectionEnd( selId ) )
return FALSE;
if ( sel.endCursor.paragraph()->paragId() < sel.startCursor.paragraph()->paragId() ) {
endParag = sel.startCursor.paragraph();
startParag = sel.endCursor.paragraph();
}
QTextParagraph *p = startParag;
while ( p ) {
if ( p->rect().contains( pos ) ) {
bool inSel = FALSE;
int selStart = p->selectionStart( selId );
int selEnd = p->selectionEnd( selId );
int y = 0;
int h = 0;
for ( int i = 0; i < p->length(); ++i ) {
if ( i == selStart )
inSel = TRUE;
if ( i == selEnd )
break;
if ( p->at( i )->lineStart ) {
y = (*p->lineStarts.find( i ))->y;
h = (*p->lineStarts.find( i ))->h;
}
if ( pos.y() - p->rect().y() >= y && pos.y() - p->rect().y() <= y + h ) {
if ( inSel && pos.x() >= p->at( i )->x &&
pos.x() <= p->at( i )->x + p->at( i )->format()->width( p->at( i )->c ) )
return TRUE;
}
}
}
if ( pos.y() < p->rect().y() )
break;
if ( p == endParag )
break;
p = p->next();
}
return FALSE;
}
void QTextDocument::doLayout( QPainter *p, int w )
{
minw = wused = 0;
if ( !is_printer( p ) )
p = 0;
withoutDoubleBuffer = ( p != 0 );
QPainter * oldPainter = QTextFormat::painter();
QTextFormat::setPainter( p );
flow_->setWidth( w );
cw = w;
vw = w;
QTextParagraph *parag = fParag;
while ( parag ) {
parag->invalidate( 0 );
if ( p )
parag->adjustToPainter( p );
parag->format();
parag = parag->next();
}
QTextFormat::setPainter( oldPainter );
}
QPixmap *QTextDocument::bufferPixmap( const QSize &s )
{
if ( !buf_pixmap )
buf_pixmap = new QPixmap( s.expandedTo( QSize(1,1) ) );
else if ( buf_pixmap->size() != s )
buf_pixmap->resize( s.expandedTo( buf_pixmap->size() ) );
return buf_pixmap;
}
void QTextDocument::draw( QPainter *p, const QRect &rect, const QColorGroup &cg, const QBrush *paper )
{
if ( !firstParagraph() )
return;
if ( paper ) {
p->setBrushOrigin( 0, 0 );
p->fillRect( rect, *paper );
}
if ( formatCollection()->defaultFormat()->color() != cg.text() )
setDefaultFormat( formatCollection()->defaultFormat()->font(), cg.text() );
QTextParagraph *parag = firstParagraph();
while ( parag ) {
if ( !parag->isValid() )
parag->format();
int y = parag->rect().y();
QRect pr( parag->rect() );
pr.setX( 0 );
pr.setWidth( QWIDGETSIZE_MAX );
if ( !rect.isNull() && !rect.intersects( pr ) ) {
parag = parag->next();
continue;
}
p->translate( 0, y );
if ( rect.isValid() )
parag->paint( *p, cg, 0, FALSE, rect.x(), rect.y(), rect.width(), rect.height() );
else
parag->paint( *p, cg, 0, FALSE );
p->translate( 0, -y );
parag = parag->next();
if ( !flow()->isEmpty() )
flow()->drawFloatingItems( p, rect.x(), rect.y(), rect.width(), rect.height(), cg, FALSE );
}
}
void QTextDocument::drawParagraph( QPainter *p, QTextParagraph *parag, int cx, int cy, int cw, int ch,
QPixmap *&doubleBuffer, const QColorGroup &cg,
bool drawCursor, QTextCursor *cursor, bool resetChanged )
{
QPainter *painter = 0;
if ( resetChanged )
parag->setChanged( FALSE );
QRect ir( parag->rect() );
bool useDoubleBuffer = !parag->document()->parent();
if ( !useDoubleBuffer && parag->document()->nextDoubleBuffered )
useDoubleBuffer = TRUE;
if ( is_printer( p ) )
useDoubleBuffer = FALSE;
if ( useDoubleBuffer ) {
painter = new QPainter;
if ( cx >= 0 && cy >= 0 )
ir = ir.intersect( QRect( cx, cy, cw, ch ) );
if ( !doubleBuffer ||
ir.width() > doubleBuffer->width() ||
ir.height() > doubleBuffer->height() ) {
doubleBuffer = bufferPixmap( ir.size() );
painter->begin( doubleBuffer );
} else {
painter->begin( doubleBuffer );
}
} else {
painter = p;
painter->translate( ir.x(), ir.y() );
}
painter->setBrushOrigin( -ir.x(), -ir.y() );
if ( useDoubleBuffer || is_printer( painter ) )
painter->fillRect( QRect( 0, 0, ir.width(), ir.height() ), parag->backgroundBrush( cg ) );
else if ( cursor && cursor->paragraph() == parag )
painter->fillRect( QRect( parag->at( cursor->index() )->x, 0, 2, ir.height() ),
parag->backgroundBrush( cg ) );
painter->translate( -( ir.x() - parag->rect().x() ),
-( ir.y() - parag->rect().y() ) );
parag->paint( *painter, cg, drawCursor ? cursor : 0, TRUE, cx, cy, cw, ch );
if ( useDoubleBuffer ) {
delete painter;
painter = 0;
p->drawPixmap( ir.topLeft(), *doubleBuffer, QRect( QPoint( 0, 0 ), ir.size() ) );
} else {
painter->translate( -ir.x(), -ir.y() );
}
if ( useDoubleBuffer ) {
if ( parag->rect().x() + parag->rect().width() < parag->document()->x() + parag->document()->width() ) {
p->fillRect( parag->rect().x() + parag->rect().width(), parag->rect().y(),
( parag->document()->x() + parag->document()->width() ) -
( parag->rect().x() + parag->rect().width() ),
parag->rect().height(), cg.brush( QColorGroup::Base ) );
}
}
parag->document()->nextDoubleBuffered = FALSE;
}
QTextParagraph *QTextDocument::draw( QPainter *p, int cx, int cy, int cw, int ch, const QColorGroup &cg,
bool onlyChanged, bool drawCursor, QTextCursor *cursor, bool resetChanged )
{
if ( withoutDoubleBuffer || par && par->withoutDoubleBuffer ) {
withoutDoubleBuffer = TRUE;
QRect r;
draw( p, r, cg );
return 0;
}
withoutDoubleBuffer = FALSE;
if ( !firstParagraph() )
return 0;
if ( cx < 0 && cy < 0 ) {
cx = 0;
cy = 0;
cw = width();
ch = height();
}
QTextParagraph *lastFormatted = 0;
QTextParagraph *parag = firstParagraph();
QPixmap *doubleBuffer = 0;
QPainter painter;
bool fullWidthSelection = FALSE;
while ( parag ) {
lastFormatted = parag;
if ( !parag->isValid() )
parag->format();
QRect pr = parag->rect();
if ( fullWidthSelection )
pr.setWidth( parag->document()->width() );
if ( pr.y() > cy + ch )
goto floating;
if ( !pr.intersects( QRect( cx, cy, cw, ch ) ) || ( onlyChanged && !parag->hasChanged() ) ) {
parag = parag->next();
continue;
}
drawParagraph( p, parag, cx, cy, cw, ch, doubleBuffer, cg, drawCursor, cursor, resetChanged );
parag = parag->next();
}
parag = lastParagraph();
floating:
if ( parag->rect().y() + parag->rect().height() < parag->document()->height() ) {
if ( !parag->document()->parent() ) {
p->fillRect( 0, parag->rect().y() + parag->rect().height(), parag->document()->width(),
parag->document()->height() - ( parag->rect().y() + parag->rect().height() ),
cg.brush( QColorGroup::Base ) );
}
if ( !flow()->isEmpty() ) {
QRect cr( cx, cy, cw, ch );
flow()->drawFloatingItems( p, cr.x(), cr.y(), cr.width(), cr.height(), cg, FALSE );
}
}
if ( buf_pixmap && buf_pixmap->height() > 300 ) {
delete buf_pixmap;
buf_pixmap = 0;
}
return lastFormatted;
}
/*
#### this function only sets the default font size in the format collection
*/
void QTextDocument::setDefaultFormat( const QFont &font, const QColor &color )
{
bool reformat = font != fCollection->defaultFormat()->font();
for ( QTextDocument *d = childList.first(); d; d = childList.next() )
d->setDefaultFormat( font, color );
fCollection->updateDefaultFormat( font, color, sheet_ );
if ( !reformat )
return;
tStopWidth = formatCollection()->defaultFormat()->width( 'x' ) * 8;
// invalidate paragraphs and custom items
QTextParagraph *p = fParag;
while ( p ) {
p->invalidate( 0 );
for ( int i = 0; i < p->length() - 1; ++i )
if ( p->at( i )->isCustom() )
p->at( i )->customItem()->invalidate();
p = p->next();
}
}
void QTextDocument::registerCustomItem( QTextCustomItem *i, QTextParagraph *p )
{
if ( i && i->placement() != QTextCustomItem::PlaceInline ) {
diff --git a/noncore/apps/opie-write/qstylesheet.cpp b/noncore/apps/opie-write/qstylesheet.cpp
index 67cd828..ca634f7 100644
--- a/noncore/apps/opie-write/qstylesheet.cpp
+++ b/noncore/apps/opie-write/qstylesheet.cpp
@@ -1,1572 +1,1570 @@
/****************************************************************************
** $Id$
**
** Implementation of the QStyleSheet class
**
** Created : 990101
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qstylesheet.h"
#include "qrichtext_p.h"
-#include "qlayout.h"
-#include "qpainter.h"
#include "qcleanuphandler.h"
#include <stdio.h>
using namespace Qt3;
namespace Qt3 {
class QStyleSheetItemData
{
public:
QStyleSheetItem::DisplayMode disp;
int fontitalic;
int fontunderline;
int fontstrikeout;
int fontweight;
int fontsize;
int fontsizelog;
int fontsizestep;
int lineSpacing;
QString fontfamily;
QStyleSheetItem *parentstyle;
QString stylename;
int ncolumns;
QColor col;
bool anchor;
int align;
QStyleSheetItem::VerticalAlignment valign;
int margin[5];
QStyleSheetItem::ListStyle list;
QStyleSheetItem::WhiteSpaceMode whitespacemode;
QString contxt;
bool selfnest;
QStyleSheet* sheet;
};
}
/*!
\class QStyleSheetItem qstylesheet.h
\brief The QStyleSheetItem class provides an encapsulation of a set of text styles.
\ingroup text
A style sheet item consists of a name and a set of attributes that
specifiy its font, color, etc. When used in a \link QStyleSheet
style sheet\endlink (see styleSheet()), items define the name() of
a rich text tag and the display property changes associated with
it.
The \link QStyleSheetItem::DisplayMode display mode\endlink
attribute indicates whether the item is a block, an inline element
or a list element; see setDisplayMode(). The treatment of
whitespace is controlled by the \link
QStyleSheetItem::WhiteSpaceMode white space mode\endlink; see
setWhiteSpaceMode(). An item's margins are set with setMargin(),
In the case of list items, the list style is set with
setListStyle(). An item may be a hypertext link anchor; see
setAnchor(). Other attributes are set with setAlignment(),
setVerticalAlignment(), setFontFamily(), setFontSize(),
setFontWeight(), setFontItalic(), setFontUnderline(),
setFontStrikeOut and setColor().
*/
/*! \enum QStyleSheetItem::AdditionalStyleValues
\internal
*/
/*!
\enum QStyleSheetItem::WhiteSpaceMode
This enum defines the ways in which QStyleSheet can treat
whitespace.
\value WhiteSpaceNormal any sequence of whitespace (including
line-breaks) is equivalent to a single space.
\value WhiteSpacePre whitespace must be output exactly as given
in the input.
\value WhiteSpaceNoWrap multiple spaces are collapsed as with
WhiteSpaceNormal, but no automatic line-breaks occur. To break
lines manually, use the \c{<br>} tag.
*/
/*!
\enum QStyleSheetItem::Margin
\value MarginLeft left margin
\value MarginRight right margin
\value MarginTop top margin
\value MarginBottom bottom margin
\value MarginAll all margins (left, right, top and bottom)
\value MarginVertical top and bottom margins
\value MarginHorizontal left and right margins
\value MarginFirstLine margin (indentation) of the first line of
a paragarph (in addition to the MarginLeft of the paragraph)
*/
/*!
Constructs a new style called \a name for the stylesheet \a
parent.
All properties in QStyleSheetItem are initially in the "do not
change" state, except \link QStyleSheetItem::DisplayMode display
mode\endlink, which defaults to \c DisplayInline.
*/
QStyleSheetItem::QStyleSheetItem( QStyleSheet* parent, const QString& name )
{
d = new QStyleSheetItemData;
d->stylename = name.lower();
d->sheet = parent;
init();
if (parent)
parent->insert( this );
}
/*!
Copy constructor. Constructs a copy of \a other that is not bound
to any style sheet.
*/
QStyleSheetItem::QStyleSheetItem( const QStyleSheetItem & other )
{
d = new QStyleSheetItemData;
*d = *other.d;
}
/*!
Destroys the style. Note that QStyleSheetItem objects become
owned by QStyleSheet when they are created.
*/
QStyleSheetItem::~QStyleSheetItem()
{
delete d;
}
/*!
Returns the style sheet this item is in.
*/
QStyleSheet* QStyleSheetItem::styleSheet()
{
return d->sheet;
}
/*!
\overload
Returns the style sheet this item is in.
*/
const QStyleSheet* QStyleSheetItem::styleSheet() const
{
return d->sheet;
}
/*!
\internal
Internal initialization
*/
void QStyleSheetItem::init()
{
d->disp = DisplayInline;
d->fontitalic = Undefined;
d->fontunderline = Undefined;
d->fontstrikeout = Undefined;
d->fontweight = Undefined;
d->fontsize = Undefined;
d->fontsizelog = Undefined;
d->fontsizestep = 0;
d->ncolumns = Undefined;
d->col = QColor(); // !isValid()
d->anchor = FALSE;
d->align = Undefined;
d->valign = VAlignBaseline;
d->margin[0] = Undefined;
d->margin[1] = Undefined;
d->margin[2] = Undefined;
d->margin[3] = Undefined;
d->margin[4] = Undefined;
d->list = (ListStyle) Undefined;
d->whitespacemode = (WhiteSpaceMode) Undefined;
d->selfnest = TRUE;
d->lineSpacing = Undefined;
}
/*!
Returns the name of the style item.
*/
QString QStyleSheetItem::name() const
{
return d->stylename;
}
/*!
Returns the \link QStyleSheetItem::DisplayMode display
mode\endlink of the style.
\sa setDisplayMode()
*/
QStyleSheetItem::DisplayMode QStyleSheetItem::displayMode() const
{
return d->disp;
}
/*!
\enum QStyleSheetItem::DisplayMode
This enum type defines the way adjacent elements are displayed.
\value DisplayBlock elements are displayed as a rectangular block
(e.g. \c{<p>...</p>}).
\value DisplayInline elements are displayed in a horizontally
flowing sequence (e.g. \c{<em>...</em>}).
\value DisplayListItem elements are displayed in a vertical
sequence (e.g. \c{<li>...</li>}).
\value DisplayNone elements are not displayed at all.
*/
/*!
Sets the display mode of the style to \a m.
\sa displayMode()
*/
void QStyleSheetItem::setDisplayMode(DisplayMode m)
{
d->disp=m;
}
/*!
Returns the alignment of this style. Possible values are \c
AlignAuto, \c AlignLeft, \c AlignRight, \c AlignCenter or \c
AlignJustify.
\sa setAlignment(), Qt::AlignmentFlags
*/
int QStyleSheetItem::alignment() const
{
return d->align;
}
/*!
Sets the alignment to \a f. This only makes sense for styles with
a \link QStyleSheetItem::DisplayMode display mode\endlink of
DisplayBlock. Possible values are \c AlignAuto, \c AlignLeft,
\c AlignRight, \c AlignCenter or \c AlignJustify.
\sa alignment(), displayMode(), Qt::AlignmentFlags
*/
void QStyleSheetItem::setAlignment( int f )
{
d->align = f;
}
/*!
Returns the vertical alignment of the style. Possible values are
\c VAlignBaseline, \c VAlignSub or \c VAlignSuper.
\sa setVerticalAlignment()
*/
QStyleSheetItem::VerticalAlignment QStyleSheetItem::verticalAlignment() const
{
return d->valign;
}
/*!
\enum QStyleSheetItem::VerticalAlignment
This enum type defines the way elements are aligned vertically.
This is only supported for text elements.
\value VAlignBaseline align the baseline of the element (or the
bottom, if the element doesn't have a baseline) with the
baseline of the parent
\value VAlignSub subscript the element
\value VAlignSuper superscript the element
*/
/*!
Sets the vertical alignment to \a valign. Possible values are
\c VAlignBaseline, \c VAlignSub or \c VAlignSuper.
The vertical alignment property is not inherited.
\sa verticalAlignment()
*/
void QStyleSheetItem::setVerticalAlignment( VerticalAlignment valign )
{
d->valign = valign;
}
/*!
Returns TRUE if the style sets an italic font; otherwise returns
FALSE.
\sa setFontItalic(), definesFontItalic()
*/
bool QStyleSheetItem::fontItalic() const
{
return d->fontitalic > 0;
}
/*!
If \a italic is TRUE sets italic for the style; otherwise sets
upright.
\sa fontItalic(), definesFontItalic()
*/
void QStyleSheetItem::setFontItalic(bool italic)
{
d->fontitalic = italic?1:0;
}
/*!
Returns TRUE if the style defines a font shape; otherwise returns
FALSE. A style does not define any shape until setFontItalic() is
called.
\sa setFontItalic(), fontItalic()
*/
bool QStyleSheetItem::definesFontItalic() const
{
return d->fontitalic != Undefined;
}
/*!
Returns TRUE if the style sets an underlined font; otherwise
returns FALSE.
\sa setFontUnderline(), definesFontUnderline()
*/
bool QStyleSheetItem::fontUnderline() const
{
return d->fontunderline > 0;
}
/*!
If \a underline is TRUE, sets underline for the style; otherwise
sets no underline.
\sa fontUnderline(), definesFontUnderline()
*/
void QStyleSheetItem::setFontUnderline(bool underline)
{
d->fontunderline = underline?1:0;
}
/*!
Returns TRUE if the style defines a setting for the underline
property of the font; otherwise returns FALSE. A style does not
define this until setFontUnderline() is called.
\sa setFontUnderline(), fontUnderline()
*/
bool QStyleSheetItem::definesFontUnderline() const
{
return d->fontunderline != Undefined;
}
/*!
Returns TRUE if the style sets a strike out font; otherwise
returns FALSE.
\sa setFontStrikeOut(), definesFontStrikeOut()
*/
bool QStyleSheetItem::fontStrikeOut() const
{
return d->fontstrikeout > 0;
}
/*!
If \a strikeOut is TRUE, sets strike out for the style; otherwise
sets no strike out.
\sa fontStrikeOut(), definesFontStrikeOut()
*/
void QStyleSheetItem::setFontStrikeOut(bool strikeOut)
{
d->fontstrikeout = strikeOut?1:0;
}
/*!
Returns TRUE if the style defines a setting for the strikeOut
property of the font; otherwise returns FALSE. A style does not
define this until setFontStrikeOut() is called.
\sa setFontStrikeOut(), fontStrikeOut()
*/
bool QStyleSheetItem::definesFontStrikeOut() const
{
return d->fontstrikeout != Undefined;
}
/*!
Returns the font weight setting of the style. This is either a
valid \c QFont::Weight or the value \c QStyleSheetItem::Undefined.
\sa setFontWeight(), QFont
*/
int QStyleSheetItem::fontWeight() const
{
return d->fontweight;
}
/*!
Sets the font weight setting of the style to \a w. Valid values
are those defined by \c QFont::Weight.
\sa QFont, fontWeight()
*/
void QStyleSheetItem::setFontWeight(int w)
{
d->fontweight = w;
}
/*!
Returns the logical font size setting of the style. This is either
a valid size between 1 and 7 or \c QStyleSheetItem::Undefined.
\sa setLogicalFontSize(), setLogicalFontSizeStep(), QFont::pointSize(), QFont::setPointSize()
*/
int QStyleSheetItem::logicalFontSize() const
{
return d->fontsizelog;
}
/*!
Sets the logical font size setting of the style to \a s. Valid
logical sizes are 1 to 7.
\sa logicalFontSize(), QFont::pointSize(), QFont::setPointSize()
*/
void QStyleSheetItem::setLogicalFontSize(int s)
{
d->fontsizelog = s;
}
/*!
Returns the logical font size step of this style.
The default is 0. Tags such as \c big define \c +1; \c small
defines \c -1.
\sa setLogicalFontSizeStep()
*/
int QStyleSheetItem::logicalFontSizeStep() const
{
return d->fontsizestep;
}
/*!
Sets the logical font size step of this style to \a s.
\sa logicalFontSizeStep()
*/
void QStyleSheetItem::setLogicalFontSizeStep( int s )
{
d->fontsizestep = s;
}
/*!
Sets the font size setting of the style to \a s points.
\sa fontSize(), QFont::pointSize(), QFont::setPointSize()
*/
void QStyleSheetItem::setFontSize(int s)
{
d->fontsize = s;
}
/*!
Returns the font size setting of the style. This is either a valid
point size or \c QStyleSheetItem::Undefined.
\sa setFontSize(), QFont::pointSize(), QFont::setPointSize()
*/
int QStyleSheetItem::fontSize() const
{
return d->fontsize;
}
/*!
Returns the font family setting of the style. This is either a
valid font family or QString::null if no family has been set.
\sa setFontFamily(), QFont::family(), QFont::setFamily()
*/
QString QStyleSheetItem::fontFamily() const
{
return d->fontfamily;
}
/*!
Sets the font family setting of the style to \a fam.
\sa fontFamily(), QFont::family(), QFont::setFamily()
*/
void QStyleSheetItem::setFontFamily( const QString& fam)
{
d->fontfamily = fam;
}
/*!\obsolete
Returns the number of columns for this style.
\sa setNumberOfColumns(), displayMode(), setDisplayMode()
*/
int QStyleSheetItem::numberOfColumns() const
{
return d->ncolumns;
}
/*!\obsolete
Sets the number of columns for this style. Elements in the style
are divided into columns.
This makes sense only if the style uses a block display mode
(see QStyleSheetItem::DisplayMode).
\sa numberOfColumns()
*/
void QStyleSheetItem::setNumberOfColumns(int ncols)
{
if (ncols > 0)
d->ncolumns = ncols;
}
/*!
Returns the text color of this style or an invalid color if no
color has been set.
\sa setColor() QColor::isValid()
*/
QColor QStyleSheetItem::color() const
{
return d->col;
}
/*!
Sets the text color of this style to \a c.
\sa color()
*/
void QStyleSheetItem::setColor( const QColor &c)
{
d->col = c;
}
/*!
Returns whether this style is an anchor.
\sa setAnchor()
*/
bool QStyleSheetItem::isAnchor() const
{
return d->anchor;
}
/*!
If \a anc is TRUE, sets this style to be an anchor (hypertext
link); otherwise sets it to not be an anchor. Elements in this
style link to other documents or anchors.
\sa isAnchor()
*/
void QStyleSheetItem::setAnchor(bool anc)
{
d->anchor = anc;
}
/*!
Returns the whitespace mode.
\sa setWhiteSpaceMode() WhiteSpaceMode
*/
QStyleSheetItem::WhiteSpaceMode QStyleSheetItem::whiteSpaceMode() const
{
return d->whitespacemode;
}
/*!
Sets the whitespace mode to \a m.
\sa WhiteSpaceMode
*/
void QStyleSheetItem::setWhiteSpaceMode(WhiteSpaceMode m)
{
d->whitespacemode = m;
}
/*!
Returns the width of margin \a m in pixels.
The margin, \a m, can be \c MarginLeft, \c MarginRight, \c
MarginTop, \c MarginBottom, \c MarginAll, \c MarginVertical or \c
MarginHorizontal.
\sa setMargin() Margin
*/
int QStyleSheetItem::margin(Margin m) const
{
return d->margin[m];
}
/*!
Sets the width of margin \a m to \a v pixels.
The margin, \a m, can be \c MarginLeft, \c MarginRight, \c
MarginTop, \c MarginBottom, \c MarginAll, \c MarginVertical or \c
MarginHorizontal. The value \a v must be >= 0.
\sa margin()
*/
void QStyleSheetItem::setMargin(Margin m, int v)
{
if (m == MarginAll ) {
d->margin[0] = v;
d->margin[1] = v;
d->margin[2] = v;
d->margin[3] = v;
d->margin[4] = v;
} else if (m == MarginVertical ) {
d->margin[MarginTop] = v;
d->margin[MarginBottom] = v;
} else if (m == MarginHorizontal ) {
d->margin[MarginLeft] = v;
d->margin[MarginRight] = v;
} else {
d->margin[m] = v;
}
}
/*!
Returns the list style of the style.
\sa setListStyle() ListStyle
*/
QStyleSheetItem::ListStyle QStyleSheetItem::listStyle() const
{
return d->list;
}
/*!
\enum QStyleSheetItem::ListStyle
This enum type defines how the items in a list are prefixed when
displayed.
\value ListDisc a filled circle (i.e. a bullet)
\value ListCircle an unfilled circle
\value ListSquare a filled square
\value ListDecimal an integer in base 10: \e 1, \e 2, \e 3, ...
\value ListLowerAlpha a lowercase letter: \e a, \e b, \e c, ...
\value ListUpperAlpha an uppercase letter: \e A, \e B, \e C, ...
*/
/*!
Sets the list style of the style to \a s.
This is used by nested elements that have a display mode of \c
DisplayListItem.
\sa listStyle() DisplayMode ListStyle
*/
void QStyleSheetItem::setListStyle(ListStyle s)
{
d->list=s;
}
/*!
Returns a space-separated list of names of styles that may contain
elements of this style. If nothing has been set, contexts()
returns an empty string, which indicates that this style can be
nested everywhere.
\sa setContexts()
*/
QString QStyleSheetItem::contexts() const
{
return d->contxt;
}
/*!
Sets a space-separated list of names of styles that may contain
elements of this style. If \a c is empty, the style can be nested
everywhere.
\sa contexts()
*/
void QStyleSheetItem::setContexts( const QString& c)
{
d->contxt = QChar(' ') + c + QChar(' ');
}
/*!
Returns TRUE if this style can be nested into an element of style
\a s; otherwise returns FALSE.
\sa contexts(), setContexts()
*/
bool QStyleSheetItem::allowedInContext( const QStyleSheetItem* s) const
{
if ( d->contxt.isEmpty() )
return TRUE;
return d->contxt.find( QChar(' ')+s->name()+QChar(' ')) != -1;
}
/*!
Returns TRUE if this style has self-nesting enabled; otherwise
returns FALSE.
\sa setSelfNesting()
*/
bool QStyleSheetItem::selfNesting() const
{
return d->selfnest;
}
/*!
Sets the self-nesting property for this style to \a nesting.
In order to support "dirty" HTML, paragraphs \c{<p>} and list
items \c{<li>} are not self-nesting. This means that starting a
new paragraph or list item automatically closes the previous one.
\sa selfNesting()
*/
void QStyleSheetItem::setSelfNesting( bool nesting )
{
d->selfnest = nesting;
}
/*
Sets the linespacing to be at least \a ls pixels.
For compatibility with previous Qt releases, small values get
treated differently: If \a ls is smaller than the default font
line spacing in pixels at parse time, the resulting line spacing
is the sum of the default line spacing plus \a ls. We recommend
not relying on this behavior.
*/
void QStyleSheetItem::setLineSpacing( int ls )
{
d->lineSpacing = ls;
}
/*!
\obsolete
Returns the linespacing
*/
int QStyleSheetItem::lineSpacing() const
{
return d->lineSpacing;
}
//************************************************************************
//************************************************************************
/*!
\class QStyleSheet qstylesheet.h
\ingroup text
\brief The QStyleSheet class is a collection of styles for rich text
rendering and a generator of tags.
\ingroup graphics
\ingroup helpsystem
By creating QStyleSheetItem objects for a style sheet you build a
definition of a set of tags. This definition will be used by the
internal rich text rendering system to parse and display text
documents to which the style sheet applies. Rich text is normally
visualized in a QTextView or a QTextBrowser. However, QLabel,
QWhatsThis and QMessageBox also support it, and other classes are
likely to follow. With QSimpleRichText it is possible to use the
rich text renderer for custom widgets as well.
The default QStyleSheet object has the following style bindings,
sorted by structuring bindings, anchors, character style bindings
(i.e. inline styles), special elements such as horizontal lines or
images, and other tags. In addition, rich text supports simple
HTML tables.
The structuring tags are
\table
\header \i Structuring tags \i Notes
\row \i \c{<qt>}...\c{</qt>}
\i A Qt rich text document. It understands the following
attributes:
\list
\i \c title -- The caption of the document. This attribute is
easily accessible with QTextView::documentTitle().
\i \c type -- The type of the document. The default type is \c
page. It indicates that the document is displayed in a
page of its own. Another style is \c detail, which can be
used to explain certain expressions in more detail in a
few sentences. For \c detail, QTextBrowser will then keep
the current page and display the new document in a small
popup similar to QWhatsThis. Note that links will not work
in documents with \c{<qt type="detail">...</qt>}.
\i \c bgcolor -- The background color, for example \c
bgcolor="yellow" or \c bgcolor="#0000FF".
\i \c background -- The background pixmap, for example \c
background="granite.xpm". The pixmap name will be resolved
by a QMimeSourceFactory().
\i \c text -- The default text color, for example \c text="red".
\i \c link -- The link color, for example \c link="green".
\endlist
\row \i \c{<h1>...</h1>}
\i A top-level heading.
\row \i \c{<h2>...</h2>}
\i A sublevel heading.
\row \i \c{<h3>...</h3>}
\i A sub-sublevel heading.
\row \i \c{<p>...</p>}
\i A left-aligned paragraph. Adjust the alignment with the \c
align attribute. Possible values are \c left, \c right and
\c center.
\row \i \c{<center>...}<br>\c{</center>}
\i A centered paragraph.
\row \i \c{<blockquote>...}<br>\c{</blockquote>}
\i An indented paragraph that is useful for quotes.
\row \i \c{<ul>...</ul>}
\i An unordered list. You can also pass a type argument to
define the bullet style. The default is \c type=disc;
other types are \c circle and \c square.
\row \i \c{<ol>...</ol>}
\i An ordered list. You can also pass a type argument to
define the enumeration label style. The default is \c
type="1"; other types are \c "a" and \c "A".
\row \i \c{<li>...</li>}
\i A list item. This tag can be used only within the context
of \c{<ol>} or \c{<ul>}.
\row \i \c{<pre>...</pre>}
\i For larger chunks of code. Whitespaces in the contents are
preserved. For small bits of code use the inline-style \c
code.
\endtable
Anchors and links are done with a single tag:
\table
\header \i Anchor tags \i Notes
\row \i \c{<a>...</a>}
\i An anchor or link.
\list
\i A link is created by using an \c href
attribute, for example
<br>\c{<a href="target.qml">Link Text</a>}. Links to
targets within a document are achieved in the same way
as for HTML, e.g.
<br>\c{<a href="target.qml#subtitle">Link Text</a>}.
\i A target is created by using a \c name
attribute, for example
<br>\c{<a name="subtitle"><h2>Sub Title</h2></a>}.
\endlist
\endtable
The default character style bindings are
\table
\header \i Style tags \i Notes
\row \i \c{<em>...</em>}
\i Emphasized. By default this is the same as \c{<i>...</i>}
(italic).
\row \i \c{<strong>...</strong>}
\i Strong. By default this is the same as \c{<b>...</b>}
(bold).
\row \i \c{<i>...</i>}
\i Italic font style.
\row \i \c{<b>...</b>}
\i Bold font style.
\row \i \c{<u>...</u>}
\i Underlined font style.
\row \i \c{<s>...</s>}
\i Strike out font style.
\row \i \c{<big>...</big>}
\i A larger font size.
\row \i \c{<small>...</small>}
\i A smaller font size.
\row \i \c{<code>...</code>}
\i Indicates code. By default this is the same as
\c{<tt>...</tt>} (typewriter). For larger junks of code
use the block-tag \c{<}\c{pre>}.
\row \i \c{<tt>...</tt>}
\i Typewriter font style.
\row \i \c{<font>...</font>}
\i Customizes the font size, family and text color. The tag
understands the following attributes:
\list
\i \c color -- The text color, for example \c color="red" or
\c color="#FF0000".
\i \c size -- The logical size of the font. Logical sizes 1
to 7 are supported. The value may either be absolute
(for example, \c size=3) or relative (\c size=-2). In
the latter case the sizes are simply added.
\i \c face -- The family of the font, for example \c face=times.
\endlist
\endtable
Special elements are:
\table
\header \i Special tags \i Notes
\row \i \c{<img>}
\i An image. The image name for the mime source factory is
given in the source attribute, for example
\c{<img src="qt.xpm">} The image tag also understands the
attributes \c width and \c height that determine the size
of the image. If the pixmap does not fit the specified
size it will be scaled automatically (by using
QImage::smoothScale()).
<br>
The \c align attribute determines where the image is
placed. By default, an image is placed inline just like a
normal character. Specify \c left or \c right to place the
image at the respective side.
\row \i \c{<hr>}
\i A horizonal line.
\row \i \c{<br>}
\i A line break.
\row \i \c{<nobr>...</nobr>}
\i No break. Prevents word wrap.
\endtable
In addition, rich text supports simple HTML tables. A table
consists of one or more rows each of which contains one or more
cells. Cells are either data cells or header cells, depending on
their content. Cells which span rows and columns are supported.
\table
\header \i Table tags \i Notes
\row \i \c{<table>...</table>}
\i A table. Tables support the following attributes:
\list
\i \c bgcolor -- The background color.
\i \c width -- The table width. This is either an absolute
pixel width or a relative percentage of the table's
width, for example \c width=80%.
\i \c border -- The width of the table border. The default is
0 (= no border).
\i \c cellspacing -- Additional space around the table cells.
The default is 2.
\i \c cellpadding -- Additional space around the contents of
table cells. The default is 1.
\endlist
\row \i \c{<tr>...</tr>}
\i A table row. This is only valid within a \c table. Rows
support the following attribute:
\list
\i \c bgcolor -- The background color.
\endlist
\row \i \c{<th>...</th>}
\i A table header cell. Similar to \c td, but defaults to
center alignment and a bold font.
\row \i \c{<td>...</td>}
\i A table data cell. This is only valid within a \c tr.
Cells support the following attributes:
\list
\i \c bgcolor -- The background color.
\i \c width -- The cell width. This is either an absolute
pixel width or a relative percentage of table's width,
for example \c width=50%.
\i \c colspan -- Specifies how many columns this cell spans.
The default is 1.
\i \c rowspan -- Specifies how many rows this cell spans. The
default is 1.
\i \c align -- Alignment; possible values are \c left, \c
right, and \c center. The default is left.
\endlist
\endtable
*/
/*!
Creates a style sheet called \a name, with parent \a parent. Like
any QObject it will be deleted when its parent is destroyed (if
the child still exists).
By default the style sheet has the tag definitions defined above.
*/
QStyleSheet::QStyleSheet( QObject *parent, const char *name )
: QObject( parent, name )
{
init();
}
/*!
Destroys the style sheet. All styles inserted into the style sheet
will be deleted.
*/
QStyleSheet::~QStyleSheet()
{
}
/*!
\internal
Initialized the style sheet to the basic Qt style.
*/
void QStyleSheet::init()
{
styles.setAutoDelete( TRUE );
nullstyle = new QStyleSheetItem( this,
QString::fromLatin1("") );
QStyleSheetItem* style;
style = new QStyleSheetItem( this, "qml" ); // compatibility
style->setDisplayMode( QStyleSheetItem::DisplayBlock );
style = new QStyleSheetItem( this, QString::fromLatin1("qt") );
style->setDisplayMode( QStyleSheetItem::DisplayBlock );
style = new QStyleSheetItem( this, QString::fromLatin1("a") );
style->setAnchor( TRUE );
style = new QStyleSheetItem( this, QString::fromLatin1("em") );
style->setFontItalic( TRUE );
style = new QStyleSheetItem( this, QString::fromLatin1("i") );
style->setFontItalic( TRUE );
style = new QStyleSheetItem( this, QString::fromLatin1("big") );
style->setLogicalFontSizeStep( 1 );
style = new QStyleSheetItem( this, QString::fromLatin1("large") ); // compatibility
style->setLogicalFontSizeStep( 1 );
style = new QStyleSheetItem( this, QString::fromLatin1("small") );
style->setLogicalFontSizeStep( -1 );
style = new QStyleSheetItem( this, QString::fromLatin1("strong") );
style->setFontWeight( QFont::Bold);
style = new QStyleSheetItem( this, QString::fromLatin1("b") );
style->setFontWeight( QFont::Bold);
style = new QStyleSheetItem( this, QString::fromLatin1("h1") );
style->setFontWeight( QFont::Bold);
style->setLogicalFontSize(6);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginTop, 18);
style-> setMargin(QStyleSheetItem::MarginBottom, 12);
style = new QStyleSheetItem( this, QString::fromLatin1("h2") );
style->setFontWeight( QFont::Bold);
style->setLogicalFontSize(5);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginTop, 16);
style-> setMargin(QStyleSheetItem::MarginBottom, 12);
style = new QStyleSheetItem( this, QString::fromLatin1("h3") );
style->setFontWeight( QFont::Bold);
style->setLogicalFontSize(4);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginTop, 14);
style-> setMargin(QStyleSheetItem::MarginBottom, 12);
style = new QStyleSheetItem( this, QString::fromLatin1("h4") );
style->setFontWeight( QFont::Bold);
style->setLogicalFontSize(3);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginVertical, 12);
style = new QStyleSheetItem( this, QString::fromLatin1("h5") );
style->setFontWeight( QFont::Bold);
style->setLogicalFontSize(2);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginTop, 12);
style-> setMargin(QStyleSheetItem::MarginBottom, 4);
style = new QStyleSheetItem( this, QString::fromLatin1("p") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style-> setMargin(QStyleSheetItem::MarginVertical, 12);
style->setSelfNesting( FALSE );
style = new QStyleSheetItem( this, QString::fromLatin1("center") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setAlignment( AlignCenter );
style = new QStyleSheetItem( this, QString::fromLatin1("twocolumn") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setNumberOfColumns( 2 );
style = new QStyleSheetItem( this, QString::fromLatin1("multicol") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
(void) new QStyleSheetItem( this, QString::fromLatin1("font") );
style = new QStyleSheetItem( this, QString::fromLatin1("ul") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setListStyle( QStyleSheetItem::ListDisc );
style-> setMargin(QStyleSheetItem::MarginVertical, 12);
style->setMargin( QStyleSheetItem::MarginLeft, 40 );
style = new QStyleSheetItem( this, QString::fromLatin1("ol") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setListStyle( QStyleSheetItem::ListDecimal );
style-> setMargin(QStyleSheetItem::MarginVertical, 12);
style->setMargin( QStyleSheetItem::MarginLeft, 40 );
style = new QStyleSheetItem( this, QString::fromLatin1("li") );
style->setDisplayMode(QStyleSheetItem::DisplayListItem);
style->setSelfNesting( FALSE );
style = new QStyleSheetItem( this, QString::fromLatin1("code") );
style->setFontFamily( QString::fromLatin1("courier") );
style = new QStyleSheetItem( this, QString::fromLatin1("tt") );
style->setFontFamily( QString::fromLatin1("courier") );
new QStyleSheetItem(this, QString::fromLatin1("img"));
new QStyleSheetItem(this, QString::fromLatin1("br"));
new QStyleSheetItem(this, QString::fromLatin1("hr"));
style = new QStyleSheetItem(this, QString::fromLatin1("sub"));
style->setVerticalAlignment( QStyleSheetItem::VAlignSub );
style = new QStyleSheetItem(this, QString::fromLatin1("sup"));
style->setVerticalAlignment( QStyleSheetItem::VAlignSuper );
style = new QStyleSheetItem( this, QString::fromLatin1("pre") );
style->setFontFamily( QString::fromLatin1("courier") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setWhiteSpaceMode(QStyleSheetItem::WhiteSpacePre);
style = new QStyleSheetItem( this, QString::fromLatin1("blockquote") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setMargin(QStyleSheetItem::MarginHorizontal, 40 );
style = new QStyleSheetItem( this, QString::fromLatin1("head") );
style->setDisplayMode(QStyleSheetItem::DisplayNone);
style = new QStyleSheetItem( this, QString::fromLatin1("body") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style = new QStyleSheetItem( this, QString::fromLatin1("div") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock) ;
style = new QStyleSheetItem( this, QString::fromLatin1("span") );
style = new QStyleSheetItem( this, QString::fromLatin1("dl") );
style-> setMargin(QStyleSheetItem::MarginVertical, 8);
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style = new QStyleSheetItem( this, QString::fromLatin1("dt") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setContexts(QString::fromLatin1("dl") );
style = new QStyleSheetItem( this, QString::fromLatin1("dd") );
style->setDisplayMode(QStyleSheetItem::DisplayBlock);
style->setMargin(QStyleSheetItem::MarginLeft, 30);
style->setContexts(QString::fromLatin1("dt dl") );
style = new QStyleSheetItem( this, QString::fromLatin1("u") );
style->setFontUnderline( TRUE);
style = new QStyleSheetItem( this, QString::fromLatin1("s") );
style->setFontStrikeOut( TRUE);
style = new QStyleSheetItem( this, QString::fromLatin1("nobr") );
style->setWhiteSpaceMode( QStyleSheetItem::WhiteSpaceNoWrap );
// compatibily with some minor 3.0.x Qt versions that had an
// undocumented <wsp> tag. ### Remove 3.1
style = new QStyleSheetItem( this, QString::fromLatin1("wsp") );
style->setWhiteSpaceMode( QStyleSheetItem::WhiteSpacePre );
// tables
style = new QStyleSheetItem( this, QString::fromLatin1("table") );
style = new QStyleSheetItem( this, QString::fromLatin1("tr") );
style->setContexts(QString::fromLatin1("table"));
style = new QStyleSheetItem( this, QString::fromLatin1("td") );
style->setContexts(QString::fromLatin1("tr"));
style = new QStyleSheetItem( this, QString::fromLatin1("th") );
style->setFontWeight( QFont::Bold );
style->setAlignment( Qt::AlignCenter );
style->setContexts(QString::fromLatin1("tr"));
style = new QStyleSheetItem( this, QString::fromLatin1("html") );
}
static QStyleSheet* defaultsheet = 0;
static QSingleCleanupHandler<QStyleSheet> qt_cleanup_stylesheet;
/*!
Returns the application-wide default style sheet. This style sheet
is used by rich text rendering classes such as QSimpleRichText,
QWhatsThis and QMessageBox to define the rendering style and
available tags within rich text documents. It also serves as the
initial style sheet for the more complex render widgets, QTextEdit
and QTextBrowser.
\sa setDefaultSheet()
*/
QStyleSheet* QStyleSheet::defaultSheet()
{
if (!defaultsheet) {
defaultsheet = new QStyleSheet();
qt_cleanup_stylesheet.set( &defaultsheet );
}
return defaultsheet;
}
/*!
Sets the application-wide default style sheet to \a sheet,
deleting any style sheet previously set. The ownership is
transferred to QStyleSheet.
\sa defaultSheet()
*/
void QStyleSheet::setDefaultSheet( QStyleSheet* sheet)
{
if ( defaultsheet != sheet ) {
if ( defaultsheet )
qt_cleanup_stylesheet.reset();
delete defaultsheet;
}
defaultsheet = sheet;
if ( defaultsheet )
qt_cleanup_stylesheet.set( &defaultsheet );
}
/*!\internal
Inserts \a style. Any tags generated after this time will be
bound to this style. Note that \a style becomes owned by the
style sheet and will be deleted when the style sheet is destroyed.
*/
void QStyleSheet::insert( QStyleSheetItem* style )
{
styles.insert(style->name(), style);
}
/*!
Returns the style called \a name or 0 if there is no such style.
*/
QStyleSheetItem* QStyleSheet::item( const QString& name)
{
if ( name.isNull() )
return 0;
return styles[name];
}
/*!
\overload
Returns the style called \a name or 0 if there is no such style
(const version)
*/
const QStyleSheetItem* QStyleSheet::item( const QString& name) const
{
if ( name.isNull() )
return 0;
return styles[name];
}
/*!
\preliminary
Generates an internal object for the tag called \a name, given the
attributes \a attr, and using additional information provided by
the mime source factory \a factory.
\a context is the optional context of the document, i.e. the path
to look for relative links. This becomes important if the text
contains relative references, for example within image tags.
QSimpleRichText always uses the default mime source factory (see
\l{QMimeSourceFactory::defaultFactory()}) to resolve these
references. The context will then be used to calculate the
absolute path. See QMimeSourceFactory::makeAbsolute() for details.
\a emptyTag and \a doc are for internal use only.
This function should not be used in application code.
*/
QTextCustomItem* QStyleSheet::tag( const QString& name,
const QMap<QString, QString> &attr,
const QString& context,
const QMimeSourceFactory& factory,
bool /*emptyTag */, QTextDocument *doc ) const
{
const QStyleSheetItem* style = item( name );
// first some known tags
if ( !style )
return 0;
if ( style->name() == "img" )
return new QTextImage( doc, attr, context, (QMimeSourceFactory&)factory );
if ( style->name() == "hr" )
return new QTextHorizontalLine( doc, attr, context, (QMimeSourceFactory&)factory );
return 0;
}
/*! Auxiliary function. Converts the plain text string \a plain to a
rich text formatted paragraph while preserving most of its look.
\a mode defines the whitespace mode. Possible values are \c
QStyleSheetItem::WhiteSpacePre (no wrapping, all whitespaces
preserved) and \c QStyleSheetItem::WhiteSpaceNormal (wrapping,
simplified whitespaces).
\sa escape()
*/
QString QStyleSheet::convertFromPlainText( const QString& plain, QStyleSheetItem::WhiteSpaceMode mode )
{
int col = 0;
QString rich;
rich += "<p>";
for ( int i = 0; i < int(plain.length()); ++i ) {
if ( plain[i] == '\n' ){
int c = 1;
while ( i+1 < int(plain.length()) && plain[i+1] == '\n' ) {
i++;
c++;
}
if ( c == 1)
rich += "<br>\n";
else {
rich += "</p>\n";
while ( --c > 1 )
rich += "<br>\n";
rich += "<p>";
}
col = 0;
} else {
if ( mode == QStyleSheetItem::WhiteSpacePre && plain[i] == '\t' ){
rich += 0x00a0U;
++col;
while ( col % 8 ) {
rich += 0x00a0U;
++col;
}
}
else if ( mode == QStyleSheetItem::WhiteSpacePre && plain[i].isSpace() )
rich += 0x00a0U;
else if ( plain[i] == '<' )
rich +="&lt;";
else if ( plain[i] == '>' )
rich +="&gt;";
else if ( plain[i] == '&' )
rich +="&amp;";
else
rich += plain[i];
++col;
}
}
if ( col != 0 )
rich += "</p>";
return rich;
}
/*!
Auxiliary function. Converts the plain text string \a plain to a
rich text formatted string with any HTML meta-characters escaped.
\sa convertFromPlainText()
*/
QString QStyleSheet::escape( const QString& plain)
{
QString rich;
for ( int i = 0; i < int(plain.length()); ++i ) {
if ( plain[i] == '<' )
rich +="&lt;";
else if ( plain[i] == '>' )
rich +="&gt;";
else if ( plain[i] == '&' )
rich +="&amp;";
else
rich += plain[i];
}
return rich;
}
// Must doc this enum somewhere, and it is logically related to QStyleSheet
/*!
\enum Qt::TextFormat
This enum is used in widgets that can display both plain text and
rich text, e.g. QLabel. It is used for deciding whether a text
string should be interpreted as one or the other. This is normally
done by passing one of the enum values to a setTextFormat()
function.
\value PlainText The text string is interpreted as a plain text
string.
\value RichText The text string is interpreted as a rich text
string using the current QStyleSheet::defaultSheet().
\value AutoText The text string is interpreted as for \c RichText
if QStyleSheet::mightBeRichText() returns TRUE, otherwise as
\c PlainText.
*/
/*!
Returns TRUE if the string \a text is likely to be rich text;
otherwise returns FALSE.
This function uses a fast and therefore simple heuristic. It
mainly checks whether there is something that looks like a tag
before the first line break. Although the result may be correct
for common cases, there is no guarantee.
*/
bool QStyleSheet::mightBeRichText( const QString& text)
{
if ( text.isEmpty() )
return FALSE;
if ( text.left(5).lower() == "<!doc" )
return TRUE;
int open = 0;
while ( open < int(text.length()) && text[open] != '<'
&& text[open] != '\n' && text[open] != '&')
++open;
if ( text[open] == '&' ) {
if ( text.mid(open+1,3) == "lt;" )
return TRUE; // support desperate attempt of user to see <...>
} else if ( text[open] == '<' ) {
int close = text.find('>', open);
if ( close > -1 ) {
QString tag;
for (int i = open+1; i < close; ++i) {
if ( text[i].isDigit() || text[i].isLetter() )
tag += text[i];
else if ( !tag.isEmpty() && text[i].isSpace() )
break;
else if ( !text[i].isSpace() && (!tag.isEmpty() || text[i] != '!' ) )
return FALSE; // that's not a tag
}
return defaultSheet()->item( tag.lower() ) != 0;
}
}
return FALSE;
}
/*!
\fn void QStyleSheet::error( const QString& msg) const
This virtual function is called when an error occurs when
processing rich text. Reimplement it if you need to catch error
messages.
Errors might occur if some rich text strings contain tags that are
not understood by the stylesheet, if some tags are nested
incorrectly, or if tags are not closed properly.
\a msg is the error message.
*/
void QStyleSheet::error( const QString& ) const
{
}
/*!
Scales the font \a font to the appropriate physical point size
corresponding to the logical font size \a logicalSize.
When calling this function, \a font has a point size corresponding
to the logical font size 3.
Logical font sizes range from 1 to 7, with 1 being the smallest.
\sa QStyleSheetItem::logicalFontSize(), QStyleSheetItem::logicalFontSizeStep(), QFont::setPointSize()
*/
void QStyleSheet::scaleFont( QFont& font, int logicalSize ) const
{
if ( logicalSize < 1 )
logicalSize = 1;
if ( logicalSize > 7 )
logicalSize = 7;
int baseSize = font.pointSize();
bool pixel = FALSE;
if ( baseSize == -1 ) {
baseSize = font.pixelSize();
pixel = TRUE;
}
int s;
switch ( logicalSize ) {
case 1:
s = baseSize/2;
break;
case 2:
s = (8 * baseSize) / 10;
break;
case 4:
s = (12 * baseSize) / 10;
break;
case 5:
s = (15 * baseSize) / 10;
break;
case 6:
s = 2 * baseSize;
break;
case 7:
s = (24 * baseSize) / 10;
break;
default:
s = baseSize;
}
if ( pixel )
font.setPixelSize( s );
else
font.setPointSize( s );
}
diff --git a/noncore/apps/opie-write/qtextedit.cpp b/noncore/apps/opie-write/qtextedit.cpp
index 82401c6..27dd515 100644
--- a/noncore/apps/opie-write/qtextedit.cpp
+++ b/noncore/apps/opie-write/qtextedit.cpp
@@ -1,3134 +1,3114 @@
/****************************************************************************
** $Id$
**
** Implementation of the QTextEdit class
**
** Created : 990101
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the widgets module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qtextedit.h"
#include "qrichtext_p.h"
-#include "qpainter.h"
-#include "qpen.h"
-#include "qbrush.h"
-#include "qpixmap.h"
-#include "qfont.h"
-#include "qcolor.h"
-#include "qstyle.h"
-#include "qsize.h"
-#include "qevent.h"
-#include "qtimer.h"
-#include "qapplication.h"
#include "qlistbox.h"
-#include "qvbox.h"
-#include "qapplication.h"
#include "qclipboard.h"
-#include "qcolordialog.h"
-#include "qfontdialog.h"
-#include "qstylesheet.h"
-#include "qdragobject.h"
-#include "qurl.h"
-#include "qcursor.h"
-#include "qregexp.h"
#include "qpopupmenu.h"
#define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
using namespace Qt3;
static bool qt_enable_richtext_copy = FALSE;
struct QUndoRedoInfoPrivate
{
QTextString text;
};
namespace Qt3 {
class QTextEditPrivate
{
public:
QTextEditPrivate()
:preeditStart(-1),preeditLength(-1),ensureCursorVisibleInShowEvent(FALSE)
{
for ( int i=0; i<7; i++ )
id[i] = 0;
}
int id[ 7 ];
int preeditStart;
int preeditLength;
bool ensureCursorVisibleInShowEvent;
QString scrollToAnchor; // used to deferr scrollToAnchor() until the show event when we are resized
};
}
static bool block_set_alignment = FALSE;
/*!
\class QTextEdit qtextedit.h
\brief The QTextEdit widget provides a powerful single-page rich text editor.
\ingroup basic
\ingroup text
\mainclass
\tableofcontents
\section1 Introduction and Concepts
QTextEdit is an advanced WYSIWYG viewer/editor supporting rich
text formatting using HTML-style tags. It is optimized to handle
large documents and to respond quickly to user input.
QTextEdit has three modes of operation:
\table
\header \i Mode \i Command \i Notes
\row \i Plain Text Editor \i setTextFormat(PlainText)
\i Set text with setText(); text() returns plain text. Text
attributes (e.g. colors) can be set, but plain text is always
returned.<sup>1.</sup>
\row \i Rich Text Editor \i setTextFormat(RichText)
\i Set text with setText(); text() returns rich text. Rich
text editing is fairly limited. You can't set margins or
insert images for example (although you can read and
correctly display files that have margins set and that
include images). This mode is mostly useful for editing small
amounts of rich text. <sup>2.</sup>
\row \i Text Viewer<sup>3.</sup> \i setReadOnly(TRUE)
\i Set text with setText() or append() (which has no undo
history so is faster and uses less memory); text() returns
plain or rich text depending on the textFormat(). This mode
can correctly display a large subset of HTML tags.
\endtable
<sup>1.</sup><small>We do \e not recommend using QTextEdit to
create syntax highlighting editors because the current API is
insufficient for this purpose. We hope to release a more complete
API that will support syntax highlighting in a later
release.</small>
<sup>2.</sup><small>A more complete API that supports setting
margins, images, etc., is planned for a later Qt release.</small>
<sup>3.</sup><small>Qt 3.1 will provide a Log Viewer mode which is
optimised for the fast and memory efficient display of large
amounts of read only text.</small>
We recommend that you always call setTextFormat() to set the mode
you want to use. If you use \c AutoText then setText() and
append() will try to determine whether the text they are given is
plain text or rich text. If you use \c RichText then setText() and
append() will assume that the text they are given is rich text.
insert() simply inserts the text it is given.
QTextEdit works on paragraphs and characters. A paragraph is a
formatted string which is word-wrapped to fit into the width of
the widget. By default when reading plain text, two newlines
signify a paragraph. A document consists of zero or more
paragraphs, indexed from 0. Characters are indexed on a
per-paragraph basis, also indexed from 0. The words in the
paragraph are aligned in accordance with the paragraph's
alignment(). Paragraphs are separated by hard line breaks. Each
character within a paragraph has its own attributes, for example,
font and color.
The text edit documentation uses the following concepts:
\list
\i \e{current format} --
this is the format at the current cursor position, \e and it
is the format of the selected text if any.
\i \e{current paragraph} -- the paragraph which contains the
cursor.
\endlist
QTextEdit can display images (using QMimeSourceFactory), lists and
tables. If the text is too large to view within the text edit's
viewport, scrollbars will appear. The text edit can load both
plain text and HTML files (a subset of HTML 3.2 and 4). The
rendering style and the set of valid tags are defined by a
styleSheet(). Custom tags can be created and placed in a custom
style sheet. Change the style sheet with \l{setStyleSheet()}; see
QStyleSheet for details. The images identified by image tags are
displayed if they can be interpreted using the text edit's
\l{QMimeSourceFactory}; see setMimeSourceFactory().
If you want a text browser with more navigation use QTextBrowser.
If you just need to display a small piece of rich text use QLabel
or QSimpleRichText.
If you create a new QTextEdit, and want to allow the user to edit
rich text, call setTextFormat(Qt::RichText) to ensure that the
text is treated as rich text. (Rich text uses HTML tags to set
text formatting attributes. See QStyleSheet for information on the
HTML tags that are supported.). If you don't call setTextFormat()
explicitly the text edit will guess from the text itself whether
it is rich text or plain text. This means that if the text looks
like HTML or XML it will probably be interpreted as rich text, so
you should call setTextFormat(Qt::PlainText) to preserve such
text.
Note that we do not intend to add a full-featured web browser
widget to Qt (because that would easily double Qt's size and only
a few applications would benefit from it). The rich
text support in Qt is designed to provide a fast, portable and
efficient way to add reasonable online help facilities to
applications, and to provide a basis for rich text editors.
\section1 Using QTextEdit as a Display Widget
QTextEdit can display a large HTML subset, including tables and
images.
The text is set or replaced using setText() which deletes any
existing text and replaces it with the text passed in the
setText() call. If you call setText() with legacy HTML (with
setTextFormat(RichText) in force), and then call text(), the text
that is returned may have different markup, but will render the
same. Text can be inserted with insert(), paste(), pasteSubType()
and append(). Text that is appended does not go into the undo
history; this makes append() faster and consumes less memory. Text
can also be cut(). The entire text is deleted with clear() and the
selected text is deleted with removeSelectedText(). Selected
(marked) text can also be deleted with del() (which will delete
the character to the right of the cursor if no text is selected).
Loading and saving text is achieved using setText() and text(),
for example:
\code
QFile file( fileName ); // Read the text from a file
if ( file.open( IO_ReadOnly ) ) {
QTextStream ts( &file );
textEdit->setText( ts.read() );
}
\endcode
\code
QFile file( fileName ); // Write the text to a file
if ( file.open( IO_WriteOnly ) ) {
QTextStream ts( &file );
ts << textEdit->text();
textEdit->setModified( FALSE );
}
\endcode
By default the text edit wraps words at whitespace to fit within
the text edit widget. The setWordWrap() function is used to
specify the kind of word wrap you want, or \c NoWrap if you don't
want any wrapping. Call setWordWrap() to set a fixed pixel width
\c FixedPixelWidth, or character column (e.g. 80 column) \c
FixedColumnWidth with the pixels or columns specified with
setWrapColumnOrWidth(). If you use word wrap to the widget's width
\c WidgetWidth, you can specify whether to break on whitespace or
anywhere with setWrapPolicy().
The background color is set differently than other widgets, using
setPaper(). You specify a brush style which could be a plain color
or a complex pixmap.
Hypertext links are automatically underlined; this can be changed
with setLinkUnderline(). The tab stop width is set with
setTabStopWidth().
The zoomIn() and zoomOut() functions can be used to resize the
text by increasing (decreasing for zoomOut()) the point size used.
Images are not affected by the zoom functions.
The lines() function returns the number of lines in the text and
paragraphs() returns the number of paragraphs. The number of lines
within a particular paragraph is returned by linesOfParagraph().
The length of the entire text in characters is returned by
length().
You can scroll to an anchor in the text, e.g. \c{<a
name="anchor">} with scrollToAnchor(). The find() function can be
used to find and select a given string within the text.
A read-only QTextEdit provides the same functionality as the
(obsolete) QTextView. (QTextView is still supplied for
compatibility with old code.)
\section2 Read-only key bindings
When QTextEdit is used read-only the key-bindings are limited to
navigation, and text may only be selected with the mouse:
\table
\header \i Keypresses \i Action
\row \i \e{UpArrow} \i Move one line up
\row \i \e{DownArrow} \i Move one line down
\row \i \e{LeftArrow} \i Move one character left
\row \i \e{RightArrow} \i Move one character right
\row \i \e{PageUp} \i Move one (viewport) page up
\row \i \e{PageDown} \i Move one (viewport) page down
\row \i \e{Home} \i Move to the beginning of the text
\row \i \e{End} \i Move to the end of the text
\row \i \e{Shift+Wheel} \i Scroll the page horizontally (the Wheel is the mouse wheel)
\row \i \e{Ctrl+Wheel} \i Zoom the text
\endtable
The text edit may be able to provide some meta-information. For
example, the documentTitle() function will return the text from
within HTML \c{<title>} tags.
The text displayed in a text edit has a \e context. The context is
a path which the text edit's QMimeSourceFactory uses to resolve
the locations of files and images. It is passed to the
mimeSourceFactory() when quering data. (See QTextEdit() and
\l{context()}.)
\section1 Using QTextEdit as an Editor
All the information about using QTextEdit as a display widget also
applies here.
The current format's attributes are set with setItalic(),
setBold(), setUnderline(), setFamily() (font family),
setPointSize(), setColor() and setCurrentFont(). The current
paragraph's alignment is set with setAlignment().
Use setSelection() to select text. The setSelectionAttributes()
function is used to indicate how selected text should be
displayed. Use hasSelectedText() to find out if any text is
selected. The currently selected text's position is available
using getSelection() and the selected text itself is returned by
selectedText(). The selection can be copied to the clipboard with
copy(), or cut to the clipboard with cut(). It can be deleted with
removeSelectedText(). The entire text can be selected (or
unselected) using selectAll(). QTextEdit supports multiple
selections. Most of the selection functions operate on the default
selection, selection 0. If the user presses a non-selecting key,
e.g. a cursor key without also holding down Shift, all selections
are cleared.
Set and get the position of the cursor with setCursorPosition()
and getCursorPosition() respectively. When the cursor is moved,
the signals currentFontChanged(), currentColorChanged() and
currentAlignmentChanged() are emitted to reflect the font, color
and alignment at the new cursor position.
If the text changes, the textChanged() signal is emitted, and if
the user inserts a new line by pressing Return or Enter,
returnPressed() is emitted. The isModified() function will return
TRUE if the text has been modified.
QTextEdit provides command-based undo and redo. To set the depth
of the command history use setUndoDepth() which defaults to 100
steps. To undo or redo the last operation call undo() or redo().
The signals undoAvailable() and redoAvailable() indicate whether
the undo and redo operations can be executed.
The indent() function is used to reindent a paragraph. It is
useful for code editors, for example in <em>Qt Designer</em>'s
code editor \e{Ctrl+I} invokes the indent() function.
\section2 Editing key bindings
The list of key-bindings which are implemented for editing:
\table
\header \i Keypresses \i Action
\row \i \e{Backspace} \i Delete the character to the left of the cursor
\row \i \e{Delete} \i Delete the character to the right of the cursor
\row \i \e{Ctrl+A} \i Move the cursor to the beginning of the line
\row \i \e{Ctrl+B} \i Move the cursor one character left
\row \i \e{Ctrl+C} \i Copy the marked text to the clipboard (also
\e{Ctrl+Insert} under Windows)
\row \i \e{Ctrl+D} \i Delete the character to the right of the cursor
\row \i \e{Ctrl+E} \i Move the cursor to the end of the line
\row \i \e{Ctrl+F} \i Move the cursor one character right
\row \i \e{Ctrl+H} \i Delete the character to the left of the cursor
\row \i \e{Ctrl+K} \i Delete to end of line
\row \i \e{Ctrl+N} \i Move the cursor one line down
\row \i \e{Ctrl+P} \i Move the cursor one line up
\row \i \e{Ctrl+V} \i Paste the clipboard text into line edit
(also \e{Shift+Insert} under Windows)
\row \i \e{Ctrl+X} \i Cut the marked text, copy to clipboard
(also \e{Shift+Delete} under Windows)
\row \i \e{Ctrl+Z} \i Undo the last operation
\row \i \e{Ctrl+Y} \i Redo the last operation
\row \i \e{LeftArrow} \i Move the cursor one character left
\row \i \e{Ctrl+LeftArrow} \i Move the cursor one word left
\row \i \e{RightArrow} \i Move the cursor one character right
\row \i \e{Ctrl+RightArrow} \i Move the cursor one word right
\row \i \e{UpArrow} \i Move the cursor one line up
\row \i \e{Ctrl+UpArrow} \i Move the cursor one word up
\row \i \e{DownArrow} \i Move the cursor one line down
\row \i \e{Ctrl+Down Arrow} \i Move the cursor one word down
\row \i \e{PageUp} \i Move the cursor one page up
\row \i \e{PageDown} \i Move the cursor one page down
\row \i \e{Home} \i Move the cursor to the beginning of the line
\row \i \e{Ctrl+Home} \i Move the cursor to the beginning of the text
\row \i \e{End} \i Move the cursor to the end of the line
\row \i \e{Ctrl+End} \i Move the cursor to the end of the text
\row \i \e{Shift+Wheel} \i Scroll the page horizontally
(the Wheel is the mouse wheel)
\row \i \e{Ctrl+Wheel} \i Zoom the text
\endtable
To select (mark) text hold down the Shift key whilst pressing one
of the movement keystrokes, for example, <i>Shift+Right Arrow</i>
will select the character to the right, and <i>Shift+Ctrl+Right
Arrow</i> will select the word to the right, etc.
By default the text edit widget operates in insert mode so all
text that the user enters is inserted into the text edit and any
text to the right of the cursor is moved out of the way. The mode
can be changed to overwrite, where new text overwrites any text to
the right of the cursor, using setOverwriteMode().
*/
/*! \enum QTextEdit::KeyboardAction
This enum is used by doKeyboardAction() to specify which action
should be executed:
\value ActionBackspace Delete the character to the left of the
cursor.
\value ActionDelete Delete the character to the right of the cursor.
\value ActionReturn Split the paragraph at the cursor position.
\value ActionKill If the cursor is not at the end of the paragraph,
delete the text from the cursor position until the end of the
paragraph. If the cursor is at the end of the paragraph, delete the
hard line break at the end of the paragraph - this will cause this
paragraph to be joined with the following paragraph.
*/
/*! \enum QTextEdit::VerticalAlignment
This enum is used to set the vertical alignment of the text.
\value AlignNormal Normal alignment
\value AlignSuperScript Superscript
\value AlignSubScript Subscript
*/
/*! \fn void QTextEdit::copyAvailable (bool yes)
This signal is emitted when text is selected or de-selected in the text
edit.
When text is selected this signal will be emitted with \a yes set to
TRUE. If no text has been selected or if the selected text is
de-selected this signal is emitted with \a yes set to FALSE.
If \a yes is TRUE then copy() can be used to copy the selection to the
clipboard. If \a yes is FALSE then copy() does nothing.
\sa selectionChanged()
*/
/*! \fn void QTextEdit::textChanged()
This signal is emitted whenever the text in the text edit changes.
\sa setText() append()
*/
/*! \fn void QTextEdit::selectionChanged()
This signal is emitted whenever the selection changes.
\sa setSelection() copyAvailable()
*/
/*! \fn QTextDocument *QTextEdit::document() const
\internal
This function returns the QTextDocument which is used by the text
edit.
*/
/*! \fn void QTextEdit::setDocument( QTextDocument *doc )
\internal
This function sets the QTextDocument which should be used by the text
edit to \a doc. This can be used, for example, if you want to
display a document using multiple views. You would create a
QTextDocument and set it to the text edits which should display it.
You would need to connect to the textChanged() and
selectionChanged() signals of all the text edits and update them all
accordingly (preferably with a slight delay for efficiency reasons).
*/
/*! \enum QTextEdit::CursorAction
This enum is used by moveCursor() to specify in which direction
the cursor should be moved:
\value MoveBackward Moves the cursor one character backward
\value MoveWordBackward Moves the cursor one word backward
\value MoveForward Moves the cursor one character forward
\value MoveWordForward Moves the cursor one word forward
\value MoveUp Moves the cursor up one line
\value MoveDown Moves the cursor down one line
\value MoveLineStart Moves the cursor to the beginning of the line
\value MoveLineEnd Moves the cursor to the end of the line
\value MoveHome Moves the cursor to the beginning of the document
\value MoveEnd Moves the cursor to the end of the document
\value MovePgUp Moves the cursor one page up
\value MovePgDown Moves the cursor one page down
*/
/*!
\property QTextEdit::overwriteMode
\brief the text edit's overwrite mode
If FALSE (the default) characters entered by the user are inserted
with any characters to the right being moved out of the way.
If TRUE, the editor is in overwrite mode, i.e. characters entered by
the user overwrite any characters to the right of the cursor position.
*/
/*! \fn void QTextEdit::setCurrentFont( const QFont &f )
Sets the font of the current format to \a f.
\sa font() setPointSize() setFamily()
*/
/*!
\property QTextEdit::undoDepth
\brief the depth of the undo history
The maximum number of steps in the undo/redo history.
The default is 100.
\sa undo() redo()
*/
/*! \fn void QTextEdit::undoAvailable( bool yes )
This signal is emitted when the availability of undo changes. If \a
yes is TRUE, then undo() will work until undoAvailable( FALSE ) is
next emitted.
\sa undo() undoDepth()
*/
/*! \fn void QTextEdit::modificationChanged( bool m )
This signal is emitted when the modification of the document
changed. If \a m is TRUE, the document was modified, otherwise the
modification state has been reset to unmodified.
\sa modified
*/
/*! \fn void QTextEdit::redoAvailable( bool yes )
This signal is emitted when the availability of redo changes. If \a
yes is TRUE, then redo() will work until redoAvailable( FALSE ) is
next emitted.
\sa redo() undoDepth()
*/
/*! \fn void QTextEdit::currentFontChanged( const QFont &f )
This signal is emitted if the font of the current format has changed.
The new font is \a f.
\sa setCurrentFont()
*/
/*! \fn void QTextEdit::currentColorChanged( const QColor &c )
This signal is emitted if the color of the current format has changed.
The new color is \a c.
\sa setColor()
*/
/*! \fn void QTextEdit::currentVerticalAlignmentChanged( VerticalAlignment a )
This signal is emitted if the vertical alignment of the current
format has changed.
The new vertical alignment is \a a.
\sa setVerticalAlignment()
*/
/*! \fn void QTextEdit::currentAlignmentChanged( int a )
This signal is emitted if the alignment of the current paragraph
has changed.
The new alignment is \a a.
\sa setAlignment()
*/
/*! \fn void QTextEdit::cursorPositionChanged( QTextCursor *c )
This signal is emitted if the position of the cursor changed. \a c
points to the text cursor object.
\sa setCursorPosition()
*/
/*! \overload void QTextEdit::cursorPositionChanged( int para, int pos )
This signal is emitted if the position of the cursor changed. \a
para contains the paragraph index and \a pos contains the character
position within the paragraph.
\sa setCursorPosition()
*/
/*! \fn void QTextEdit::returnPressed()
This signal is emitted if the user pressed the Return or the Enter key.
*/
/*!
\fn QTextCursor *QTextEdit::textCursor() const
Returns the text edit's text cursor.
\warning QTextCursor is not in the public API, but in special
circumstances you might wish to use it.
*/
/*! Constructs an empty QTextEdit with parent \a parent and name \a
name.
*/
QTextEdit::QTextEdit( QWidget *parent, const char *name )
: QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
{
init();
}
/*!
Constructs a QTextEdit with parent \a parent and name \a name. The
text edit will display the text \a text using context \a context.
The \a context is a path which the text edit's QMimeSourceFactory
uses to resolve the locations of files and images. It is passed to
the mimeSourceFactory() when quering data.
For example if the text contains an image tag,
\c{<img src="image.png">}, and the context is "path/to/look/in", the
QMimeSourceFactory will try to load the image from
"path/to/look/in/image.png". If the tag was
\c{<img src="/image.png">}, the context will not be used (because
QMimeSourceFactory recognizes that we have used an absolute path)
and will try to load "/image.png". The context is applied in exactly
the same way to \e hrefs, for example,
\c{<a href="target.html">Target</a>}, would resolve to
"path/to/look/in/target.html".
*/
QTextEdit::QTextEdit( const QString& text, const QString& context,
QWidget *parent, const char *name)
: QScrollView( parent, name, WStaticContents | WRepaintNoErase | WResizeNoErase ),
doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
{
init();
setText( text, context );
}
/*! \reimp */
QTextEdit::~QTextEdit()
{
delete undoRedoInfo.d;
undoRedoInfo.d = 0;
delete cursor;
delete doc;
delete d;
}
void QTextEdit::init()
{
setFrameStyle( Sunken );
undoEnabled = TRUE;
readonly = TRUE;
setReadOnly( FALSE );
d = new QTextEditPrivate;
connect( doc, SIGNAL( minimumWidthChanged( int ) ),
this, SLOT( documentWidthChanged( int ) ) );
mousePressed = FALSE;
inDoubleClick = FALSE;
modified = FALSE;
onLink = QString::null;
overWrite = FALSE;
wrapMode = WidgetWidth;
wrapWidth = -1;
wPolicy = AtWhiteSpace;
inDnD = FALSE;
doc->setFormatter( new QTextFormatterBreakWords );
doc->formatCollection()->defaultFormat()->setFont( QScrollView::font() );
doc->formatCollection()->defaultFormat()->setColor( colorGroup().color( QColorGroup::Text ) );
currentFormat = doc->formatCollection()->defaultFormat();
currentAlignment = Qt3::AlignAuto;
viewport()->setBackgroundMode( PaletteBase );
viewport()->setAcceptDrops( TRUE );
resizeContents( 0, doc->lastParagraph() ?
( doc->lastParagraph()->paragId() + 1 ) * doc->formatCollection()->defaultFormat()->height() : 0 );
setKeyCompression( TRUE );
viewport()->setMouseTracking( TRUE );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
cursor = new QTextCursor( doc );
formatTimer = new QTimer( this );
connect( formatTimer, SIGNAL( timeout() ),
this, SLOT( formatMore() ) );
lastFormatted = doc->firstParagraph();
scrollTimer = new QTimer( this );
connect( scrollTimer, SIGNAL( timeout() ),
this, SLOT( autoScrollTimerDone() ) );
interval = 0;
changeIntervalTimer = new QTimer( this );
connect( changeIntervalTimer, SIGNAL( timeout() ),
this, SLOT( doChangeInterval() ) );
cursorVisible = TRUE;
blinkTimer = new QTimer( this );
connect( blinkTimer, SIGNAL( timeout() ),
this, SLOT( blinkCursor() ) );
#ifndef QT_NO_DRAGANDDROP
dragStartTimer = new QTimer( this );
connect( dragStartTimer, SIGNAL( timeout() ),
this, SLOT( startDrag() ) );
#endif
formatMore();
blinkCursorVisible = FALSE;
viewport()->setFocusProxy( this );
viewport()->setFocusPolicy( WheelFocus );
viewport()->installEventFilter( this );
installEventFilter( this );
}
void QTextEdit::paintDocument( bool drawAll, QPainter *p, int cx, int cy, int cw, int ch )
{
bool drawCur = hasFocus() || viewport()->hasFocus();
if ( hasSelectedText() || isReadOnly() || !cursorVisible )
drawCur = FALSE;
QColorGroup g = colorGroup();
if ( doc->paper() )
g.setBrush( QColorGroup::Base, *doc->paper() );
if ( contentsY() < doc->y() ) {
p->fillRect( contentsX(), contentsY(), visibleWidth(), doc->y(),
g.brush( QColorGroup::Base ) );
}
if ( drawAll && doc->width() - contentsX() < cx + cw ) {
p->fillRect( doc->width() - contentsX(), cy, cx + cw - doc->width() + contentsX(), ch,
g.brush( QColorGroup::Base ) );
}
p->setBrushOrigin( -contentsX(), -contentsY() );
lastFormatted = doc->draw( p, cx, cy, cw, ch, g, !drawAll, drawCur, cursor );
if ( lastFormatted == doc->lastParagraph() )
resizeContents( contentsWidth(), doc->height() );
if ( contentsHeight() < visibleHeight() && ( !doc->lastParagraph() || doc->lastParagraph()->isValid() ) && drawAll )
p->fillRect( 0, contentsHeight(), visibleWidth(),
visibleHeight() - contentsHeight(), g.brush( QColorGroup::Base ) );
}
/*! \reimp */
void QTextEdit::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
{
paintDocument( TRUE, p, cx, cy, cw, ch );
int v;
p->setPen( foregroundColor() );
if ( document()->isPageBreakEnabled() && ( v = document()->flow()->pageSize() ) > 0 ) {
int l = int(cy / v) * v;
while ( l < cy + ch ) {
p->drawLine( cx, l, cx + cw - 1, l );
l += v;
}
}
}
/*! \reimp */
void QTextEdit::drawContents( QPainter * )
{
}
/*! \reimp */
bool QTextEdit::event( QEvent *e )
{
if ( e->type() == QEvent::AccelOverride && !isReadOnly() ) {
QKeyEvent* ke = (QKeyEvent*) e;
if ( ke->state() == NoButton || ke->state() == Keypad ) {
if ( ke->key() < Key_Escape ) {
ke->accept();
} else {
switch ( ke->key() ) {
case Key_Return:
case Key_Enter:
case Key_Delete:
case Key_Home:
case Key_End:
case Key_Backspace:
ke->accept();
default:
break;
}
}
} else if ( ke->state() & ControlButton ) {
switch ( ke->key() ) {
// Those are too frequently used for application functionality
/* case Key_A:
case Key_B:
case Key_D:
case Key_E:
case Key_F:
case Key_H:
case Key_I:
case Key_K:
case Key_N:
case Key_P:
case Key_T:
*/
case Key_C:
case Key_V:
case Key_X:
case Key_Y:
case Key_Z:
case Key_Left:
case Key_Right:
case Key_Up:
case Key_Down:
case Key_Home:
case Key_End:
case Key_Tab:
#if defined (Q_WS_WIN)
case Key_Insert:
case Key_Delete:
#endif
ke->accept();
default:
break;
}
} else {
switch ( ke->key() ) {
#if defined (Q_WS_WIN)
case Key_Insert:
ke->accept();
#endif
default:
break;
}
}
}
if ( e->type() == QEvent::Show ) {
if ( d->ensureCursorVisibleInShowEvent ) {
sync();
ensureCursorVisible();
d->ensureCursorVisibleInShowEvent = FALSE;
}
if ( !d->scrollToAnchor.isEmpty() ) {
scrollToAnchor( d->scrollToAnchor );
d->scrollToAnchor = QString::null;
}
}
return QWidget::event( e );
}
/*!
Processes the key event, \a e.
By default key events are used to provide keyboard navigation and
text editing.
*/
void QTextEdit::keyPressEvent( QKeyEvent *e )
{
changeIntervalTimer->stop();
interval = 10;
bool unknown = FALSE;
if ( isReadOnly() ) {
if ( !handleReadOnlyKeyEvent( e ) )
QScrollView::keyPressEvent( e );
changeIntervalTimer->start( 100, TRUE );
return;
}
bool selChanged = FALSE;
for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
selChanged = doc->removeSelection( i ) || selChanged;
if ( selChanged ) {
cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
repaintChanged();
}
bool clearUndoRedoInfo = TRUE;
switch ( e->key() ) {
case Key_Left:
case Key_Right: {
// a bit hacky, but can't change this without introducing new enum values for move and keeping the
// correct semantics and movement for BiDi and non BiDi text.
CursorAction a;
if ( cursor->paragraph()->string()->isRightToLeft() == (e->key() == Key_Right) )
a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
else
a = e->state() & ControlButton ? MoveWordForward : MoveForward;
moveCursor( a, e->state() & ShiftButton );
break;
}
case Key_Up:
moveCursor( e->state() & ControlButton ? MovePgUp : MoveUp, e->state() & ShiftButton );
break;
case Key_Down:
moveCursor( e->state() & ControlButton ? MovePgDown : MoveDown, e->state() & ShiftButton );
break;
case Key_Home:
moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
break;
case Key_End:
moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
break;
case Key_Prior:
moveCursor( MovePgUp, e->state() & ShiftButton );
break;
case Key_Next:
moveCursor( MovePgDown, e->state() & ShiftButton );
break;
case Key_Return: case Key_Enter:
if ( doc->hasSelection( QTextDocument::Standard, FALSE ) )
removeSelectedText();
if ( textFormat() == Qt::RichText && ( e->state() & ControlButton ) ) {
// Ctrl-Enter inserts a line break in rich text mode
insert( QString( QChar( 0x2028) ), TRUE, FALSE, TRUE );
} else {
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
clearUndoRedoInfo = FALSE;
doKeyboardAction( ActionReturn );
emit returnPressed();
}
break;
case Key_Delete:
#if defined (Q_WS_WIN)
if ( e->state() & ShiftButton ) {
cut();
break;
} else
#endif
if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
removeSelectedText();
break;
}
doKeyboardAction( ActionDelete );
clearUndoRedoInfo = FALSE;
break;
case Key_Insert:
if ( e->state() & ShiftButton )
paste();
#if defined (Q_WS_WIN)
else if ( e->state() & ControlButton )
copy();
#endif
break;
case Key_Backspace:
if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
removeSelectedText();
break;
}
doKeyboardAction( ActionBackspace );
clearUndoRedoInfo = FALSE;
break;
case Key_F16: // Copy key on Sun keyboards
copy();
break;
case Key_F18: // Paste key on Sun keyboards
paste();
break;
case Key_F20: // Cut key on Sun keyboards
cut();
break;
default: {
if ( e->text().length() &&
( !( e->state() & ControlButton ) &&
!( e->state() & AltButton ) ||
( ( e->state() & ControlButton | AltButton ) == (ControlButton|AltButton) ) ) &&
( !e->ascii() || e->ascii() >= 32 || e->text() == "\t" ) ) {
clearUndoRedoInfo = FALSE;
if ( e->key() == Key_Tab ) {
if ( textFormat() == Qt::RichText && cursor->paragraph()->isListItem() ) {
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Style;
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.eid = undoRedoInfo.id;
undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
cursor->paragraph()->setListDepth( cursor->paragraph()->listDepth() +1 );
clearUndoRedo();
drawCursor( FALSE );
repaintChanged();
drawCursor( TRUE );
break;
}
}
if ( textFormat() == Qt::RichText && !cursor->paragraph()->isListItem() ) {
if ( cursor->index() == 0 && ( e->text()[0] == '-' || e->text()[0] == '*' ) ) {
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Style;
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.eid = undoRedoInfo.id;
undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
clearUndoRedo();
drawCursor( FALSE );
repaintChanged();
drawCursor( TRUE );
break;
}
}
if ( overWrite && !cursor->atParagEnd() )
cursor->remove();
QString t = e->text();
QTextParagraph *p = cursor->paragraph();
if ( p && p->string() && p->string()->isRightToLeft() ) {
QChar *c = (QChar *)t.unicode();
int l = t.length();
while( l-- ) {
if ( c->mirrored() )
*c = c->mirroredChar();
c++;
}
}
insert( t, TRUE, FALSE, TRUE );
break;
} else if ( e->state() & ControlButton ) {
switch ( e->key() ) {
case Key_C: case Key_F16: // Copy key on Sun keyboards
copy();
break;
case Key_V:
paste();
break;
case Key_X:
cut();
break;
case Key_I: case Key_T: case Key_Tab:
indent();
break;
case Key_A:
#if defined(Q_WS_X11)
moveCursor( MoveLineStart, e->state() & ShiftButton );
#else
selectAll( TRUE );
#endif
break;
case Key_B:
moveCursor( MoveBackward, e->state() & ShiftButton );
break;
case Key_F:
moveCursor( MoveForward, e->state() & ShiftButton );
break;
case Key_D:
if ( doc->hasSelection( QTextDocument::Standard ) ) {
removeSelectedText();
break;
}
doKeyboardAction( ActionDelete );
clearUndoRedoInfo = FALSE;
break;
case Key_H:
if ( doc->hasSelection( QTextDocument::Standard ) ) {
removeSelectedText();
break;
}
if ( !cursor->paragraph()->prev() &&
cursor->atParagStart() )
break;
doKeyboardAction( ActionBackspace );
clearUndoRedoInfo = FALSE;
break;
case Key_E:
moveCursor( MoveLineEnd, e->state() & ShiftButton );
break;
case Key_N:
moveCursor( MoveDown, e->state() & ShiftButton );
break;
case Key_P:
moveCursor( MoveUp, e->state() & ShiftButton );
break;
case Key_Z:
if(e->state() & ShiftButton)
redo();
else
undo();
break;
case Key_Y:
redo();
break;
case Key_K:
doKeyboardAction( ActionKill );
break;
#if defined(Q_WS_WIN)
case Key_Insert:
copy();
break;
case Key_Delete:
del();
break;
#endif
default:
unknown = FALSE;
break;
}
} else {
unknown = TRUE;
}
}
}
emit cursorPositionChanged( cursor );
emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
if ( clearUndoRedoInfo )
clearUndoRedo();
changeIntervalTimer->start( 100, TRUE );
if ( unknown )
e->ignore();
}
/*!
Executes keyboard action \a action. This is normally called by
a key event handler.
*/
void QTextEdit::doKeyboardAction( KeyboardAction action )
{
if ( isReadOnly() )
return;
if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
return;
lastFormatted = cursor->paragraph();
drawCursor( FALSE );
bool doUpdateCurrentFormat = TRUE;
switch ( action ) {
case ActionDelete:
if ( !cursor->atParagEnd() ) {
checkUndoRedoInfo( UndoRedoInfo::Delete );
if ( !undoRedoInfo.valid() ) {
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.index = cursor->index();
undoRedoInfo.d->text = QString::null;
}
undoRedoInfo.d->text.insert( undoRedoInfo.d->text.length(), cursor->paragraph()->at( cursor->index() ), TRUE );
cursor->remove();
} else {
clearUndoRedo();
doc->setSelectionStart( QTextDocument::Temp, *cursor );
cursor->gotoNextLetter();
doc->setSelectionEnd( QTextDocument::Temp, *cursor );
removeSelectedText( QTextDocument::Temp );
}
break;
case ActionBackspace:
if ( textFormat() == Qt::RichText && cursor->paragraph()->isListItem() && cursor->index() == 0 ) {
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Style;
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.eid = undoRedoInfo.id;
undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
int ldepth = cursor->paragraph()->listDepth();
ldepth = QMAX( ldepth-1, 0 );
cursor->paragraph()->setListDepth( ldepth );
if ( ldepth == 0 )
cursor->paragraph()->setListItem( FALSE );
clearUndoRedo();
lastFormatted = cursor->paragraph();
repaintChanged();
drawCursor( TRUE );
return;
}
if ( !cursor->atParagStart() ) {
checkUndoRedoInfo( UndoRedoInfo::Delete );
if ( !undoRedoInfo.valid() ) {
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.index = cursor->index();
undoRedoInfo.d->text = QString::null;
}
cursor->gotoPreviousLetter();
undoRedoInfo.d->text.insert( 0, cursor->paragraph()->at( cursor->index() ), TRUE );
undoRedoInfo.index = cursor->index();
cursor->remove();
lastFormatted = cursor->paragraph();
} else if ( cursor->paragraph()->prev() ){
clearUndoRedo();
doc->setSelectionStart( QTextDocument::Temp, *cursor );
cursor->gotoPreviousLetter();
doc->setSelectionEnd( QTextDocument::Temp, *cursor );
removeSelectedText( QTextDocument::Temp );
}
break;
case ActionReturn:
checkUndoRedoInfo( UndoRedoInfo::Return );
if ( !undoRedoInfo.valid() ) {
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.index = cursor->index();
undoRedoInfo.d->text = QString::null;
}
undoRedoInfo.d->text += "\n";
cursor->splitAndInsertEmptyParagraph();
if ( cursor->paragraph()->prev() ) {
lastFormatted = cursor->paragraph()->prev();
lastFormatted->invalidate( 0 );
}
doUpdateCurrentFormat = FALSE;
break;
case ActionKill:
clearUndoRedo();
doc->setSelectionStart( QTextDocument::Temp, *cursor );
if ( cursor->atParagEnd() )
cursor->gotoNextLetter();
else
cursor->setIndex( cursor->paragraph()->length() - 1 );
doc->setSelectionEnd( QTextDocument::Temp, *cursor );
removeSelectedText( QTextDocument::Temp );
break;
}
formatMore();
repaintChanged();
ensureCursorVisible();
drawCursor( TRUE );
updateMicroFocusHint();
if ( doUpdateCurrentFormat )
updateCurrentFormat();
setModified();
emit textChanged();
}
void QTextEdit::readFormats( QTextCursor &c1, QTextCursor &c2, QTextString &text, bool fillStyles )
{
QDataStream styleStream( undoRedoInfo.styleInformation, IO_WriteOnly );
c2.restoreState();
c1.restoreState();
int lastIndex = text.length();
if ( c1.paragraph() == c2.paragraph() ) {
for ( int i = c1.index(); i < c2.index(); ++i )
text.insert( lastIndex + i - c1.index(), c1.paragraph()->at( i ), TRUE );
if ( fillStyles ) {
styleStream << (int) 1;
c1.paragraph()->writeStyleInformation( styleStream );
}
} else {
int i;
for ( i = c1.index(); i < c1.paragraph()->length()-1; ++i )
text.insert( lastIndex++, c1.paragraph()->at( i ), TRUE );
int num = 2; // start and end, being different
text += "\n"; lastIndex++;
QTextParagraph *p = c1.paragraph()->next();
while ( p && p != c2.paragraph() ) {
for ( i = 0; i < p->length()-1; ++i )
text.insert( lastIndex++ , p->at( i ), TRUE );
text += "\n"; num++; lastIndex++;
p = p->next();
}
for ( i = 0; i < c2.index(); ++i )
text.insert( i + lastIndex, c2.paragraph()->at( i ), TRUE );
if ( fillStyles ) {
styleStream << num;
for ( QTextParagraph *p = c1.paragraph(); --num >= 0; p = p->next() )
p->writeStyleInformation( styleStream );
}
}
}
/*! Removes the selection \a selNum (by default 0). This does not
remove the selected text.
\sa removeSelectedText()
*/
void QTextEdit::removeSelection( int selNum )
{
doc->removeSelection( selNum );
repaintChanged();
}
/*! Deletes the selected text (i.e. the default selection's text) of
the selection \a selNum (by default, 0). If there is no selected text
nothing happens.
\sa selectedText removeSelection()
*/
void QTextEdit::removeSelectedText( int selNum )
{
if ( isReadOnly() )
return;
QTextCursor c1 = doc->selectionStartCursor( selNum );
c1.restoreState();
QTextCursor c2 = doc->selectionEndCursor( selNum );
c2.restoreState();
// ### no support for editing tables yet, plus security for broken selections
if ( c1.nestedDepth() || c2.nestedDepth() )
return;
for ( int i = 0; i < (int)doc->numSelections(); ++i ) {
if ( i == selNum )
continue;
doc->removeSelection( i );
}
drawCursor( FALSE );
checkUndoRedoInfo( UndoRedoInfo::RemoveSelected );
if ( !undoRedoInfo.valid() ) {
doc->selectionStart( selNum, undoRedoInfo.id, undoRedoInfo.index );
undoRedoInfo.d->text = QString::null;
}
readFormats( c1, c2, undoRedoInfo.d->text, TRUE );
doc->removeSelectedText( selNum, cursor );
if ( cursor->isValid() ) {
ensureCursorVisible();
lastFormatted = cursor->paragraph();
formatMore();
repaintChanged();
ensureCursorVisible();
drawCursor( TRUE );
clearUndoRedo();
#if defined(Q_WS_WIN)
// there seems to be a problem with repainting or erasing the area
// of the scrollview which is not the contents on windows
if ( contentsHeight() < visibleHeight() )
viewport()->repaint( 0, contentsHeight(), visibleWidth(), visibleHeight() - contentsHeight(), TRUE );
#endif
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
updateMicroFocusHint();
} else {
delete cursor;
cursor = new QTextCursor( doc );
drawCursor( TRUE );
viewport()->repaint( TRUE );
}
setModified();
emit textChanged();
emit selectionChanged();
}
/*! Moves the text cursor according to \a action. This is normally
used by some key event handler. \a select specifies whether the text
between the current cursor position and the new position should be
selected.
*/
void QTextEdit::moveCursor( CursorAction action, bool select )
{
drawCursor( FALSE );
if ( select ) {
if ( !doc->hasSelection( QTextDocument::Standard ) )
doc->setSelectionStart( QTextDocument::Standard, *cursor );
moveCursor( action );
if ( doc->setSelectionEnd( QTextDocument::Standard, *cursor ) ) {
cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
repaintChanged();
} else {
drawCursor( TRUE );
}
ensureCursorVisible();
emit selectionChanged();
emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
} else {
bool redraw = doc->removeSelection( QTextDocument::Standard );
moveCursor( action );
if ( !redraw ) {
ensureCursorVisible();
drawCursor( TRUE );
} else {
cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
repaintChanged();
ensureCursorVisible();
drawCursor( TRUE );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
}
if ( redraw ) {
emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
emit selectionChanged();
}
}
drawCursor( TRUE );
updateCurrentFormat();
updateMicroFocusHint();
}
/*! \overload
*/
void QTextEdit::moveCursor( CursorAction action )
{
switch ( action ) {
case MoveBackward:
cursor->gotoPreviousLetter();
break;
case MoveWordBackward:
cursor->gotoPreviousWord();
break;
case MoveForward:
cursor->gotoNextLetter();
break;
case MoveWordForward:
cursor->gotoNextWord();
break;
case MoveUp:
cursor->gotoUp();
break;
case MovePgUp:
cursor->gotoPageUp( visibleHeight() );
break;
case MoveDown:
cursor->gotoDown();
break;
case MovePgDown:
cursor->gotoPageDown( visibleHeight() );
break;
case MoveLineStart:
cursor->gotoLineStart();
break;
case MoveHome:
cursor->gotoHome();
break;
case MoveLineEnd:
cursor->gotoLineEnd();
break;
case MoveEnd:
ensureFormatted( doc->lastParagraph() );
cursor->gotoEnd();
break;
}
updateMicroFocusHint();
updateCurrentFormat();
}
/*! \reimp */
void QTextEdit::resizeEvent( QResizeEvent *e )
{
QScrollView::resizeEvent( e );
if ( doc->visibleWidth() == 0 )
doResize();
}
/*! \reimp */
void QTextEdit::viewportResizeEvent( QResizeEvent *e )
{
QScrollView::viewportResizeEvent( e );
if ( e->oldSize().width() != e->size().width() ) {
bool stayAtBottom = e->oldSize().height() != e->size().height() &&
contentsY() > 0 && contentsY() >= doc->height() - e->oldSize().height();
doResize();
if ( stayAtBottom )
scrollToBottom();
}
}
/*!
Ensures that the cursor is visible by scrolling the text edit if
necessary.
\sa setCursorPosition()
*/
void QTextEdit::ensureCursorVisible()
{
if ( !isVisible() ) {
d->ensureCursorVisibleInShowEvent = TRUE;
return;
}
lastFormatted = cursor->paragraph();
formatMore();
QTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
int x = cursor->paragraph()->rect().x() + chr->x + cursor->offsetX();
int y = 0; int dummy;
cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
y += cursor->paragraph()->rect().y() + cursor->offsetY();
int w = 1;
ensureVisible( x, y + h / 2, w, h / 2 + 2 );
}
/*!
\internal
*/
void QTextEdit::drawCursor( bool visible )
{
if ( !isUpdatesEnabled() ||
!viewport()->isUpdatesEnabled() ||
!cursor->paragraph() ||
!cursor->paragraph()->isValid() ||
!selectedText().isEmpty() ||
( visible && !hasFocus() && !viewport()->hasFocus() && !inDnD ) ||
isReadOnly() )
return;
QPainter p( viewport() );
QRect r( cursor->topParagraph()->rect() );
cursor->paragraph()->setChanged( TRUE );
p.translate( -contentsX() + cursor->totalOffsetX(), -contentsY() + cursor->totalOffsetY() );
QPixmap *pix = 0;
QColorGroup cg( colorGroup() );
if ( cursor->paragraph()->background() )
cg.setBrush( QColorGroup::Base, *cursor->paragraph()->background() );
else if ( doc->paper() )
cg.setBrush( QColorGroup::Base, *doc->paper() );
p.setBrushOrigin( -contentsX(), -contentsY() );
cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
if ( !cursor->nestedDepth() ) {
int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
int dist = 5;
if ( ( cursor->paragraph()->alignment() & Qt3::AlignJustify ) == Qt3::AlignJustify )
dist = 50;
int x = r.x() - cursor->totalOffsetX() + cursor->x() - dist;
x = QMAX( x, 0 );
p.setClipRect( QRect( x - contentsX(),
r.y() - cursor->totalOffsetY() + cursor->y() - contentsY(), 2 * dist, h ) );
doc->drawParagraph( &p, cursor->paragraph(), x,
r.y() - cursor->totalOffsetY() + cursor->y(), 2 * dist, h, pix, cg, visible, cursor );
} else {
doc->drawParagraph( &p, cursor->paragraph(), r.x() - cursor->totalOffsetX(),
r.y() - cursor->totalOffsetY(), r.width(), r.height(),
pix, cg, visible, cursor );
}
cursorVisible = visible;
}
enum {
IdUndo = 0,
IdRedo = 1,
IdCut = 2,
IdCopy = 3,
IdPaste = 4,
IdClear = 5,
IdSelectAll = 6
};
/*! \reimp */
#ifndef QT_NO_WHEELEVENT
void QTextEdit::contentsWheelEvent( QWheelEvent *e )
{
if ( isReadOnly() ) {
if ( e->state() & ControlButton ) {
if ( e->delta() > 0 )
zoomOut();
else if ( e->delta() < 0 )
zoomIn();
return;
}
}
QScrollView::contentsWheelEvent( e );
}
#endif
/*! \reimp */
void QTextEdit::contentsMousePressEvent( QMouseEvent *e )
{
clearUndoRedo();
QTextCursor oldCursor = *cursor;
QTextCursor c = *cursor;
mousePos = e->pos();
mightStartDrag = FALSE;
pressedLink = QString::null;
if ( e->button() == LeftButton ) {
mousePressed = TRUE;
drawCursor( FALSE );
placeCursor( e->pos() );
ensureCursorVisible();
if ( isReadOnly() && linksEnabled() ) {
QTextCursor c = *cursor;
placeCursor( e->pos(), &c, TRUE );
if ( c.paragraph() && c.paragraph()->at( c.index() ) &&
c.paragraph()->at( c.index() )->isAnchor() ) {
pressedLink = c.paragraph()->at( c.index() )->anchorHref();
}
}
#ifndef QT_NO_DRAGANDDROP
if ( doc->inSelection( QTextDocument::Standard, e->pos() ) ) {
mightStartDrag = TRUE;
drawCursor( TRUE );
dragStartTimer->start( QApplication::startDragTime(), TRUE );
dragStartPos = e->pos();
return;
}
#endif
bool redraw = FALSE;
if ( doc->hasSelection( QTextDocument::Standard ) ) {
if ( !( e->state() & ShiftButton ) ) {
redraw = doc->removeSelection( QTextDocument::Standard );
doc->setSelectionStart( QTextDocument::Standard, *cursor );
} else {
redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
}
} else {
if ( isReadOnly() || !( e->state() & ShiftButton ) ) {
doc->setSelectionStart( QTextDocument::Standard, *cursor );
} else {
doc->setSelectionStart( QTextDocument::Standard, c );
redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
}
}
for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
redraw = doc->removeSelection( i ) || redraw;
if ( !redraw ) {
drawCursor( TRUE );
} else {
repaintChanged();
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
}
} else if ( e->button() == MidButton ) {
bool redraw = doc->removeSelection( QTextDocument::Standard );
if ( !redraw ) {
drawCursor( TRUE );
} else {
repaintChanged();
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
}
}
if ( *cursor != oldCursor )
updateCurrentFormat();
}
/*! \reimp */
void QTextEdit::contentsMouseMoveEvent( QMouseEvent *e )
{
if ( mousePressed ) {
#ifndef QT_NO_DRAGANDDROP
if ( mightStartDrag ) {
dragStartTimer->stop();
if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
startDrag();
#ifndef QT_NO_CURSOR
if ( !isReadOnly() )
viewport()->setCursor( ibeamCursor );
#endif
return;
}
#endif
mousePos = e->pos();
handleMouseMove( mousePos );
oldMousePos = mousePos;
}
#ifndef QT_NO_CURSOR
if ( !isReadOnly() && !mousePressed ) {
if ( doc->hasSelection( QTextDocument::Standard ) && doc->inSelection( QTextDocument::Standard, e->pos() ) )
viewport()->setCursor( arrowCursor );
else
viewport()->setCursor( ibeamCursor );
}
#endif
updateCursor( e->pos() );
}
/*! \reimp */
void QTextEdit::contentsMouseReleaseEvent( QMouseEvent * e )
{
QTextCursor oldCursor = *cursor;
if ( scrollTimer->isActive() )
scrollTimer->stop();
#ifndef QT_NO_DRAGANDDROP
if ( dragStartTimer->isActive() )
dragStartTimer->stop();
if ( mightStartDrag ) {
selectAll( FALSE );
mousePressed = FALSE;
}
#endif
if ( mousePressed ) {
mousePressed = FALSE;
}
emit cursorPositionChanged( cursor );
emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
if ( oldCursor != *cursor )
updateCurrentFormat();
inDoubleClick = FALSE;
#ifndef QT_NO_NETWORKPROTOCOL
if ( !onLink.isEmpty() && onLink == pressedLink && linksEnabled() ) {
QUrl u( doc->context(), onLink, TRUE );
emitLinkClicked( u.toString( FALSE, FALSE ) );
// emitting linkClicked() may result in that the cursor winds
// up hovering over a different valid link - check this and
// set the appropriate cursor shape
updateCursor( e->pos() );
}
#endif
drawCursor( TRUE );
if ( !doc->hasSelection( QTextDocument::Standard, TRUE ) )
doc->removeSelection( QTextDocument::Standard );
emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
emit selectionChanged();
}
/*! \reimp */
void QTextEdit::contentsMouseDoubleClickEvent( QMouseEvent * )
{
QTextCursor c1 = *cursor;
QTextCursor c2 = *cursor;
if ( cursor->index() > 0 && !cursor->paragraph()->at( cursor->index()-1 )->c.isSpace() )
c1.gotoPreviousWord();
if ( !cursor->paragraph()->at( cursor->index() )->c.isSpace() && !cursor->atParagEnd() )
c2.gotoNextWord();
doc->setSelectionStart( QTextDocument::Standard, c1 );
doc->setSelectionEnd( QTextDocument::Standard, c2 );
*cursor = c2;
repaintChanged();
inDoubleClick = TRUE;
mousePressed = TRUE;
}
#ifndef QT_NO_DRAGANDDROP
/*! \reimp */
void QTextEdit::contentsDragEnterEvent( QDragEnterEvent *e )
{
if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
e->ignore();
return;
}
e->acceptAction();
inDnD = TRUE;
}
/*! \reimp */
void QTextEdit::contentsDragMoveEvent( QDragMoveEvent *e )
{
if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
e->ignore();
return;
}
drawCursor( FALSE );
placeCursor( e->pos(), cursor );
drawCursor( TRUE );
e->acceptAction();
}
/*! \reimp */
void QTextEdit::contentsDragLeaveEvent( QDragLeaveEvent * )
{
inDnD = FALSE;
}
/*! \reimp */
void QTextEdit::contentsDropEvent( QDropEvent *e )
{
if ( isReadOnly() )
return;
inDnD = FALSE;
e->acceptAction();
QString text;
bool intern = FALSE;
if ( QTextDrag::decode( e, text ) ) {
bool hasSel = doc->hasSelection( QTextDocument::Standard );
bool internalDrag = e->source() == this || e->source() == viewport();
int dropId, dropIndex;
QTextCursor insertCursor = *cursor;
dropId = cursor->paragraph()->paragId();
dropIndex = cursor->index();
if ( hasSel && internalDrag ) {
QTextCursor c1, c2;
int selStartId, selStartIndex;
int selEndId, selEndIndex;
c1 = doc->selectionStartCursor( QTextDocument::Standard );
c1.restoreState();
c2 = doc->selectionEndCursor( QTextDocument::Standard );
c2.restoreState();
selStartId = c1.paragraph()->paragId();
selStartIndex = c1.index();
selEndId = c2.paragraph()->paragId();
selEndIndex = c2.index();
if ( ( ( dropId > selStartId ) ||
( dropId == selStartId && dropIndex > selStartIndex ) ) &&
( ( dropId < selEndId ) ||
( dropId == selEndId && dropIndex <= selEndIndex ) ) )
insertCursor = c1;
if ( dropId == selEndId && dropIndex > selEndIndex ) {
insertCursor = c1;
if ( selStartId == selEndId ) {
insertCursor.setIndex( dropIndex -
( selEndIndex - selStartIndex ) );
} else {
insertCursor.setIndex( dropIndex - selEndIndex +
selStartIndex );
}
}
}
if ( internalDrag && e->action() == QDropEvent::Move ) {
removeSelectedText();
intern = TRUE;
} else {
doc->removeSelection( QTextDocument::Standard );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
}
drawCursor( FALSE );
cursor->setParagraph( insertCursor.paragraph() );
cursor->setIndex( insertCursor.index() );
drawCursor( TRUE );
if ( !cursor->nestedDepth() ) {
insert( text, FALSE, TRUE, FALSE );
} else {
if ( intern )
undo();
e->ignore();
}
}
}
#endif
void QTextEdit::autoScrollTimerDone()
{
if ( mousePressed )
handleMouseMove( viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) ) );
}
void QTextEdit::handleMouseMove( const QPoint& pos )
{
if ( !mousePressed )
return;
if ( !scrollTimer->isActive() && pos.y() < contentsY() || pos.y() > contentsY() + visibleHeight() )
scrollTimer->start( 100, FALSE );
else if ( scrollTimer->isActive() && pos.y() >= contentsY() && pos.y() <= contentsY() + visibleHeight() )
scrollTimer->stop();
drawCursor( FALSE );
QTextCursor oldCursor = *cursor;
placeCursor( pos );
if ( inDoubleClick ) {
QTextCursor cl = *cursor;
cl.gotoPreviousWord();
QTextCursor cr = *cursor;
cr.gotoNextWord();
int diff = QABS( oldCursor.paragraph()->at( oldCursor.index() )->x - mousePos.x() );
int ldiff = QABS( cl.paragraph()->at( cl.index() )->x - mousePos.x() );
int rdiff = QABS( cr.paragraph()->at( cr.index() )->x - mousePos.x() );
if ( cursor->paragraph()->lineStartOfChar( cursor->index() ) !=
oldCursor.paragraph()->lineStartOfChar( oldCursor.index() ) )
diff = 0xFFFFFF;
if ( rdiff < diff && rdiff < ldiff )
*cursor = cr;
else if ( ldiff < diff && ldiff < rdiff )
*cursor = cl;
else
*cursor = oldCursor;
}
ensureCursorVisible();
bool redraw = FALSE;
if ( doc->hasSelection( QTextDocument::Standard ) ) {
redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
}
if ( !redraw ) {
drawCursor( TRUE );
} else {
repaintChanged();
drawCursor( TRUE );
}
if ( currentFormat && currentFormat->key() != cursor->paragraph()->at( cursor->index() )->format()->key() ) {
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( cursor->index() )->format() );
if ( currentFormat->isMisspelled() ) {
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
}
emit currentFontChanged( currentFormat->font() );
emit currentColorChanged( currentFormat->color() );
emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
}
if ( currentAlignment != cursor->paragraph()->alignment() ) {
currentAlignment = cursor->paragraph()->alignment();
block_set_alignment = TRUE;
emit currentAlignmentChanged( currentAlignment );
block_set_alignment = FALSE;
}
}
/*!
\fn void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c )
Places the cursor \a c at the character which is closest to position
\a pos (in contents coordinates). If \a c is 0, the default text
cursor is used.
\sa setCursorPosition()
*/
void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c, bool link )
{
if ( !c )
c = cursor;
c->restoreState();
QTextParagraph *s = doc->firstParagraph();
c->place( pos, s, link );
updateMicroFocusHint();
}
void QTextEdit::updateMicroFocusHint()
{
QTextCursor c( *cursor );
if ( d->preeditStart != -1 )
c.setIndex( d->preeditStart );
if ( hasFocus() || viewport()->hasFocus() ) {
int h = c.paragraph()->lineHeightOfChar( cursor->index() );
if ( !readonly ) {
QFont f = c.paragraph()->at( c.index() )->format()->font();
setMicroFocusHint( c.x() - contentsX() + frameWidth(),
c.y() + cursor->paragraph()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE );
}
}
}
void QTextEdit::formatMore()
{
if ( !lastFormatted )
return;
int bottom = contentsHeight();
int lastBottom = -1;
int to = 20;
bool firstVisible = FALSE;
QRect cr( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
for ( int i = 0; ( i < to || firstVisible ) && lastFormatted; ++i ) {
lastFormatted->format();
if ( i == 0 )
firstVisible = lastFormatted->rect().intersects( cr );
else if ( firstVisible )
firstVisible = lastFormatted->rect().intersects( cr );
bottom = QMAX( bottom, lastFormatted->rect().top() +
lastFormatted->rect().height() );
lastBottom = lastFormatted->rect().top() + lastFormatted->rect().height();
lastFormatted = lastFormatted->next();
if ( lastFormatted )
lastBottom = -1;
}
if ( bottom > contentsHeight() ) {
resizeContents( contentsWidth(), QMAX( doc->height(), bottom ) );
} else if ( lastBottom != -1 && lastBottom < contentsHeight() ) {
resizeContents( contentsWidth(), QMAX( doc->height(), lastBottom ) );
if ( contentsHeight() < visibleHeight() )
updateContents( 0, contentsHeight(), visibleWidth(),
visibleHeight() - contentsHeight() );
}
if ( lastFormatted )
formatTimer->start( interval, TRUE );
else
interval = QMAX( 0, interval );
}
void QTextEdit::doResize()
{
if ( wrapMode == FixedPixelWidth )
return;
doc->setMinimumWidth( -1 );
resizeContents( 0, 0 );
doc->setWidth( visibleWidth() );
doc->invalidate();
lastFormatted = doc->firstParagraph();
interval = 0;
formatMore();
repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE );
}
/*! \internal */
void QTextEdit::doChangeInterval()
{
interval = 0;
}
/*! \reimp */
bool QTextEdit::eventFilter( QObject *o, QEvent *e )
{
if ( o == this || o == viewport() ) {
if ( e->type() == QEvent::FocusIn ) {
blinkTimer->start( QApplication::cursorFlashTime() / 2 );
drawCursor( TRUE );
updateMicroFocusHint();
} else if ( e->type() == QEvent::FocusOut ) {
blinkTimer->stop();
drawCursor( FALSE );
}
}
return QScrollView::eventFilter( o, e );
}
/*! Inserts \a text at the current cursor position. If \a indent is
TRUE, the paragraph is re-indented. If \a checkNewLine is TRUE,
newline characters in \a text result in hard line breaks (i.e. new
paragraphs). If \a checkNewLine is FALSE and there are newlines in
\a text, the behavior is undefined. If \a checkNewLine is FALSE the
behaviour of the editor is undefined if the \a text contains
newlines. If \a removeSelected is TRUE, any selected text (in
selection 0) is removed before the text is inserted.
\sa paste() pasteSubType()
*/
void QTextEdit::insert( const QString &text, bool indent, bool checkNewLine, bool removeSelected )
{
if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
return;
QString txt( text );
drawCursor( FALSE );
if ( !isReadOnly() && doc->hasSelection( QTextDocument::Standard ) && removeSelected )
removeSelectedText();
QTextCursor c2 = *cursor;
int oldLen = 0;
if ( undoEnabled && !isReadOnly() ) {
checkUndoRedoInfo( UndoRedoInfo::Insert );
if ( !undoRedoInfo.valid() ) {
undoRedoInfo.id = cursor->paragraph()->paragId();
undoRedoInfo.index = cursor->index();
undoRedoInfo.d->text = QString::null;
}
oldLen = undoRedoInfo.d->text.length();
}
lastFormatted = checkNewLine && cursor->paragraph()->prev() ?
cursor->paragraph()->prev() : cursor->paragraph();
QTextCursor oldCursor = *cursor;
cursor->insert( txt, checkNewLine );
if ( doc->useFormatCollection() ) {
doc->setSelectionStart( QTextDocument::Temp, oldCursor );
doc->setSelectionEnd( QTextDocument::Temp, *cursor );
doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
doc->removeSelection( QTextDocument::Temp );
}
if ( indent && ( txt == "{" || txt == "}" || txt == ":" || txt == "#" ) )
cursor->indent();
formatMore();
repaintChanged();
ensureCursorVisible();
drawCursor( TRUE );
if ( undoEnabled && !isReadOnly() ) {
undoRedoInfo.d->text += txt;
if ( !doc->preProcessor() ) {
for ( int i = 0; i < (int)txt.length(); ++i ) {
if ( txt[ i ] != '\n' && c2.paragraph()->at( c2.index() )->format() ) {
c2.paragraph()->at( c2.index() )->format()->addRef();
undoRedoInfo.d->text.setFormat( oldLen + i, c2.paragraph()->at( c2.index() )->format(), TRUE );
}
c2.gotoNextLetter();
}
}
}
if ( !removeSelected ) {
doc->setSelectionStart( QTextDocument::Standard, oldCursor );
doc->setSelectionEnd( QTextDocument::Standard, *cursor );
repaintChanged();
}
updateMicroFocusHint();
setModified();
emit textChanged();
}
/*! Inserts \a text in the paragraph \a para and position \a index */
void QTextEdit::insertAt( const QString &text, int para, int index )
{
removeSelection( QTextDocument::Standard );
QTextParagraph *p = doc->paragAt( para );
if ( !p )
return;
QTextCursor tmp = *cursor;
cursor->setParagraph( p );
cursor->setIndex( index );
insert( text, FALSE, TRUE, FALSE );
*cursor = tmp;
removeSelection( QTextDocument::Standard );
}
/*! Inserts \a text as the paragraph at position \a para. If \a para
is -1, the text is appended.
*/
void QTextEdit::insertParagraph( const QString &text, int para )
{
QTextParagraph *p = doc->paragAt( para );
if ( p ) {
QTextCursor tmp( doc );
tmp.setParagraph( p );
tmp.setIndex( 0 );
tmp.insert( text, TRUE );
tmp.splitAndInsertEmptyParagraph();
repaintChanged();
} else {
append( text );
}
}
/*! Removes the paragraph \a para */
void QTextEdit::removeParagraph( int para )
{
QTextParagraph *p = doc->paragAt( para );
if ( !p )
return;
for ( int i = 0; i < doc->numSelections(); ++i )
doc->removeSelection( i );
if ( p == doc->firstParagraph() && p == doc->lastParagraph() ) {
p->remove( 0, p->length() - 1 );
repaintChanged();
return;
}
drawCursor( FALSE );
bool resetCursor = cursor->paragraph() == p;
if ( p->prev() )
p->prev()->setNext( p->next() );
else
doc->setFirstParagraph( p->next() );
if ( p->next() )
p->next()->setPrev( p->prev() );
else
doc->setLastParagraph( p->prev() );
QTextParagraph *start = p->next();
int h = p->rect().height();
delete p;
p = start;
int dy = -h;
while ( p ) {
p->setParagId( p->prev() ? p->prev()->paragId() + 1 : 0 );
p->move( dy );
p->invalidate( 0 );
p->setEndState( -1 );
p = p->next();
}
if ( resetCursor ) {
cursor->setParagraph( doc->firstParagraph() );
cursor->setIndex( 0 );
}
repaintChanged();
drawCursor( TRUE );
}
/*!
Undoes the last operation.
If there is no operation to undo, e.g. there is no undo step in the
undo/redo history, nothing happens.
\sa undoAvailable() redo() undoDepth()
*/
void QTextEdit::undo()
{
// XXX FIXME The next line is here because there may be a command
// that needs to be 'flushed'. The FIXME is because I am not
// 100% certain this is the right call to do this.
clearUndoRedo();
if ( isReadOnly() || !doc->commands()->isUndoAvailable() || !undoEnabled )
return;
for ( int i = 0; i < (int)doc->numSelections(); ++i )
doc->removeSelection( i );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
clearUndoRedo();
drawCursor( FALSE );
QTextCursor *c = doc->undo( cursor );
if ( !c ) {
drawCursor( TRUE );
return;
}
lastFormatted = 0;
ensureCursorVisible();
repaintChanged();
drawCursor( TRUE );
updateMicroFocusHint();
setModified();
emit textChanged();
}
/*!
Redoes the last operation.
If there is no operation to redo, e.g. there is no redo step in the
undo/redo history, nothing happens.
\sa redoAvailable() undo() undoDepth()
*/
void QTextEdit::redo()
{
if ( isReadOnly() || !doc->commands()->isRedoAvailable() || !undoEnabled )
return;
for ( int i = 0; i < (int)doc->numSelections(); ++i )
doc->removeSelection( i );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
clearUndoRedo();
drawCursor( FALSE );
QTextCursor *c = doc->redo( cursor );
if ( !c ) {
drawCursor( TRUE );
return;
}
lastFormatted = 0;
ensureCursorVisible();
repaintChanged();
ensureCursorVisible();
drawCursor( TRUE );
updateMicroFocusHint();
setModified();
emit textChanged();
}
/*!
Pastes the text from the clipboard into the text edit at the current
cursor position. Only plain text is pasted.
If there is no text in the clipboard nothing happens.
\sa pasteSubType() cut() QTextEdit::copy()
*/
void QTextEdit::paste()
{
#ifndef QT_NO_CLIPBOARD
if ( isReadOnly() )
return;
pasteSubType( "plain" );
updateMicroFocusHint();
#endif
}
void QTextEdit::checkUndoRedoInfo( UndoRedoInfo::Type t )
{
if ( undoRedoInfo.valid() && t != undoRedoInfo.type ) {
clearUndoRedo();
}
undoRedoInfo.type = t;
}
/*! Repaints any paragraphs that have changed.
Although used extensively internally you shouldn't need to call this
yourself.
*/
void QTextEdit::repaintChanged()
{
if ( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() )
return;
QPainter p( viewport() );
p.translate( -contentsX(), -contentsY() );
paintDocument( FALSE, &p, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
}
/*!
Copies the selected text (from selection 0) to the clipboard and
deletes it from the text edit.
If there is no selected text (in selection 0) nothing happens.
\sa QTextEdit::copy() paste() pasteSubType()
*/
void QTextEdit::cut()
{
if ( isReadOnly() )
return;
QString t;
if ( doc->hasSelection( QTextDocument::Standard ) &&
!( t = doc->selectedText( QTextDocument::Standard, qt_enable_richtext_copy ) ).isEmpty() ) {
QApplication::clipboard()->setText( t );
removeSelectedText();
}
updateMicroFocusHint();
}
/*! Copies any selected text (from selection 0) to the clipboard.
\sa hasSelectedText() copyAvailable()
*/
void QTextEdit::copy()
{
QString t = doc->selectedText( QTextDocument::Standard, qt_enable_richtext_copy );
if ( doc->hasSelection( QTextDocument::Standard ) &&
!t.isEmpty() && t.simplifyWhiteSpace() != "<selstart/>" )
QApplication::clipboard()->setText( t );
}
/*!
Re-indents the current paragraph.
*/
void QTextEdit::indent()
{
if ( isReadOnly() )
return;
drawCursor( FALSE );
if ( !doc->hasSelection( QTextDocument::Standard ) )
cursor->indent();
else
doc->indentSelection( QTextDocument::Standard );
repaintChanged();
drawCursor( TRUE );
setModified();
emit textChanged();
}
/*! Reimplemented to allow tabbing through links.
If \a n is TRUE the tab moves the focus to the next child; if \a n
is FALSE the tab moves the focus to the previous child.
Returns TRUE if the focus was moved; otherwise returns FALSE.
*/
bool QTextEdit::focusNextPrevChild( bool n )
{
if ( !isReadOnly() || !linksEnabled() )
return FALSE;
bool b = doc->focusNextPrevChild( n );
repaintChanged();
if ( b )
//##### this does not work with tables. The focusIndicator
//should really be a QTextCursor. Fix 3.1
makeParagVisible( doc->focusIndicator.parag );
return b;
}
/*!
\internal
This functions sets the current format to \a f. Only the fields of \a
f which are specified by the \a flags are used.
*/
void QTextEdit::setFormat( QTextFormat *f, int flags )
{
if ( doc->hasSelection( QTextDocument::Standard ) ) {
drawCursor( FALSE );
QTextCursor c1 = doc->selectionStartCursor( QTextDocument::Standard );
c1.restoreState();
QTextCursor c2 = doc->selectionEndCursor( QTextDocument::Standard );
c2.restoreState();
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Format;
undoRedoInfo.id = c1.paragraph()->paragId();
undoRedoInfo.index = c1.index();
undoRedoInfo.eid = c2.paragraph()->paragId();
undoRedoInfo.eindex = c2.index();
readFormats( c1, c2, undoRedoInfo.d->text );
undoRedoInfo.format = f;
undoRedoInfo.flags = flags;
clearUndoRedo();
doc->setFormat( QTextDocument::Standard, f, flags );
repaintChanged();
formatMore();
drawCursor( TRUE );
setModified();
emit textChanged();
}
if ( currentFormat && currentFormat->key() != f->key() ) {
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( f );
if ( currentFormat->isMisspelled() ) {
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
}
emit currentFontChanged( currentFormat->font() );
emit currentColorChanged( currentFormat->color() );
emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
if ( cursor->index() == cursor->paragraph()->length() - 1 ) {
currentFormat->addRef();
cursor->paragraph()->string()->setFormat( cursor->index(), currentFormat, TRUE );
if ( cursor->paragraph()->length() == 1 ) {
cursor->paragraph()->invalidate( 0 );
cursor->paragraph()->format();
repaintChanged();
}
}
}
}
/*! \reimp */
void QTextEdit::setPalette( const QPalette &p )
{
QScrollView::setPalette( p );
if ( textFormat() == PlainText ) {
QTextFormat *f = doc->formatCollection()->defaultFormat();
f->setColor( colorGroup().text() );
updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
}
}
/*! \internal
\warning In Qt 3.1 we will provide a cleaer API for the
functionality which is provided by this function and in Qt 4.0 this
function will go away.
Sets the paragraph style of the current paragraph
to \a dm. If \a dm is QStyleSheetItem::DisplayListItem, the
type of the list item is set to \a listStyle.
\sa setAlignment()
*/
void QTextEdit::setParagType( QStyleSheetItem::DisplayMode dm, QStyleSheetItem::ListStyle listStyle )
{
if ( isReadOnly() )
return;
drawCursor( FALSE );
QTextParagraph *start = cursor->paragraph();
QTextParagraph *end = start;
if ( doc->hasSelection( QTextDocument::Standard ) ) {
start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
if ( end->paragId() < start->paragId() )
return; // do not trust our selections
}
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Style;
undoRedoInfo.id = start->paragId();
undoRedoInfo.eid = end->paragId();
undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
while ( start != end->next() ) {
start->setListStyle( listStyle );
if ( dm == QStyleSheetItem::DisplayListItem ) {
start->setListItem( TRUE );
if( start->listDepth() == 0 )
start->setListDepth( 1 );
} else if ( start->isListItem() ) {
start->setListItem( FALSE );
start->setListDepth( QMAX( start->listDepth()-1, 0 ) );
}
start = start->next();
}
clearUndoRedo();
repaintChanged();
formatMore();
drawCursor( TRUE );
setModified();
emit textChanged();
}
/*!
Sets the alignment of the current paragraph to \a a. Valid alignments
are \c Qt::AlignLeft, \c Qt::AlignRight, Qt::AlignJustify and
Qt::AlignCenter (which centers horizontally).
*/
void QTextEdit::setAlignment( int a )
{
if ( isReadOnly() || block_set_alignment )
return;
drawCursor( FALSE );
QTextParagraph *start = cursor->paragraph();
QTextParagraph *end = start;
if ( doc->hasSelection( QTextDocument::Standard ) ) {
start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
if ( end->paragId() < start->paragId() )
return; // do not trust our selections
}
clearUndoRedo();
undoRedoInfo.type = UndoRedoInfo::Style;
undoRedoInfo.id = start->paragId();
undoRedoInfo.eid = end->paragId();
undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
while ( start != end->next() ) {
start->setAlignment( a );
start = start->next();
}
clearUndoRedo();
repaintChanged();
formatMore();
drawCursor( TRUE );
if ( currentAlignment != a ) {
currentAlignment = a;
emit currentAlignmentChanged( currentAlignment );
}
setModified();
emit textChanged();
}
void QTextEdit::updateCurrentFormat()
{
int i = cursor->index();
if ( i > 0 )
--i;
if ( doc->useFormatCollection() &&
( !currentFormat || currentFormat->key() != cursor->paragraph()->at( i )->format()->key() ) ) {
if ( currentFormat )
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( i )->format() );
if ( currentFormat->isMisspelled() ) {
currentFormat->removeRef();
currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
}
emit currentFontChanged( currentFormat->font() );
emit currentColorChanged( currentFormat->color() );
emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
}
if ( currentAlignment != cursor->paragraph()->alignment() ) {
currentAlignment = cursor->paragraph()->alignment();
block_set_alignment = TRUE;
emit currentAlignmentChanged( currentAlignment );
block_set_alignment = FALSE;
}
}
/*!
If \a b is TRUE sets the current format to italic; otherwise sets
the current format to non-italic.
\sa italic()
*/
void QTextEdit::setItalic( bool b )
{
QTextFormat f( *currentFormat );
f.setItalic( b );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Italic );
}
/*!
If \a b is TRUE sets the current format to bold; otherwise sets the
current format to non-bold.
\sa bold()
*/
void QTextEdit::setBold( bool b )
{
QTextFormat f( *currentFormat );
f.setBold( b );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Bold );
}
/*!
If \a b is TRUE sets the current format to underline; otherwise sets
the current format to non-underline.
\sa underline()
*/
void QTextEdit::setUnderline( bool b )
{
QTextFormat f( *currentFormat );
f.setUnderline( b );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Underline );
}
/*!
Sets the font family of the current format to \a fontFamily.
\sa family() setCurrentFont()
*/
void QTextEdit::setFamily( const QString &fontFamily )
{
QTextFormat f( *currentFormat );
f.setFamily( fontFamily );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Family );
}
/*!
Sets the point size of the current format to \a s.
Note that if \a s is zero or negative, the behaviour of this
function is not defined.
\sa pointSize() setCurrentFont() setFamily()
*/
void QTextEdit::setPointSize( int s )
{
QTextFormat f( *currentFormat );
f.setPointSize( s );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Size );
}
/*!
Sets the color of the current format, i.e. of the text, to \a c.
\sa color() setPaper()
*/
void QTextEdit::setColor( const QColor &c )
{
QTextFormat f( *currentFormat );
f.setColor( c );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Color );
}
/*!
Sets the vertical alignment of the current format, i.e. of the text, to \a a.
\sa color() setPaper()
*/
void QTextEdit::setVerticalAlignment( VerticalAlignment a )
{
QTextFormat f( *currentFormat );
f.setVAlign( (QTextFormat::VerticalAlignment)a );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::VAlign );
}
void QTextEdit::setFontInternal( const QFont &f_ )
{
QTextFormat f( *currentFormat );
f.setFont( f_ );
QTextFormat *f2 = doc->formatCollection()->format( &f );
setFormat( f2, QTextFormat::Font );
}
QString QTextEdit::text() const
{
if ( isReadOnly() )
return doc->originalText();
return doc->text();
}
/*!
\overload
Returns the text of paragraph \a para.
If textFormat() is \c RichText the text will contain HTML
formatting tags.
*/
QString QTextEdit::text( int para ) const
{
return doc->text( para );
}
/*!
\overload
Changes the text of the text edit to the string \a text and the
context to \a context. Any previous text is removed.
\a text may be interpreted either as plain text or as rich text,
depending on the textFormat(). The default setting is \c AutoText,
i.e. the text edit autodetects the format from \a text.
The optional \a context is a path which the text edit's
QMimeSourceFactory uses to resolve the locations of files and images.
(See \l{QTextEdit::QTextEdit()}.) It is passed to the text edit's
QMimeSourceFactory when quering data.
Note that the undo/redo history is cleared by this function.
\sa text(), setTextFormat()
*/
void QTextEdit::setText( const QString &text, const QString &context )
{
if ( !isModified() && isReadOnly() &&
this->context() == context && this->text() == text )
return;
emit undoAvailable( FALSE );
emit redoAvailable( FALSE );
undoRedoInfo.clear();
doc->commands()->clear();
lastFormatted = 0;
cursor->restoreState();
doc->setText( text, context );
if ( wrapMode == FixedPixelWidth ) {
resizeContents( wrapWidth, 0 );
doc->setWidth( wrapWidth );
doc->setMinimumWidth( wrapWidth );
} else {
doc->setMinimumWidth( -1 );
resizeContents( 0, 0 );
}
lastFormatted = doc->firstParagraph();
delete cursor;
cursor = new QTextCursor( doc );
updateContents( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
if ( isModified() )
setModified( FALSE );
emit textChanged();
formatMore();
updateCurrentFormat();
d->scrollToAnchor = QString::null;
}
/*!
\property QTextEdit::text
\brief the text edit's text
There is no default text.
On setting, any previous text is deleted.
The text may be interpreted either as plain text or as rich text,
depending on the textFormat(). The default setting is \c AutoText,
i.e. the text edit autodetects the format of the text.
For richtext, calling text() on an editable QTextEdit will cause the text
to be regenerated from the textedit. This may mean that the QString returned
may not be exactly the same as the one that was set.
\sa textFormat
*/
/*!
\property QTextEdit::readOnly
\brief whether the text edit is read-only
In a read-only text edit the user can only navigate through the text
and select text; modifying the text is not possible.
This property's default is FALSE.
*/
/*!
Finds the next occurrence of the string, \a expr. Returns TRUE if
\a expr is found; otherwise returns FALSE.
If \a para and \a index are both null the search begins from the
current cursor position. If \a para and \a index are both not
null, the search begins from the \e *\a index character position
in the \e *\a para paragraph.
If \a cs is TRUE the search is case sensitive, otherwise it is
case insensitive. If \a wo is TRUE the search looks for whole word
matches only; otherwise it searches for any matching text. If \a
forward is TRUE (the default) the search works forward from the
starting position to the end of the text, otherwise it works
backwards to the beginning of the text.
If \a expr is found the function returns TRUE. If \a index and \a
para are not null, the number of the paragraph in which the first
character of the match was found is put into \e *\a para, and the
index position of that character within the paragraph is put into
\e *\a index.
If \a expr is not found the function returns FALSE. If \a index
and \a para are not null and \a expr is not found, \e *\a index
and \e *\a para are undefined.
*/
bool QTextEdit::find( const QString &expr, bool cs, bool wo, bool forward,
int *para, int *index )
{
drawCursor( FALSE );
#ifndef QT_NO_CURSOR
viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
#endif
QTextCursor findcur = *cursor;
if ( para && index ) {
if ( doc->paragAt( *para ) )
findcur.gotoPosition( doc->paragAt(*para), *index );
else
findcur.gotoEnd();
} else if ( doc->hasSelection( QTextDocument::Standard ) ){
// maks sure we do not find the same selection again
if ( forward )
findcur.gotoNextLetter();
else
findcur.gotoPreviousLetter();
}
removeSelection( QTextDocument::Standard );
bool found = doc->find( findcur, expr, cs, wo, forward );
if ( found ) {
if ( para )
*para = findcur.paragraph()->paragId();
if ( index )
*index = findcur.index();
*cursor = findcur;
repaintChanged();
ensureCursorVisible();
}
drawCursor( TRUE );
return found;
}
void QTextEdit::blinkCursor()
{
if ( !cursorVisible )
return;
bool cv = cursorVisible;
blinkCursorVisible = !blinkCursorVisible;
drawCursor( blinkCursorVisible );
cursorVisible = cv;
}
/*!
Sets the cursor to position \a index in paragraph \a para.
\sa getCursorPosition()
*/
void QTextEdit::setCursorPosition( int para, int index )
{
QTextParagraph *p = doc->paragAt( para );
if ( !p )
return;
if ( index > p->length() - 1 )
index = p->length() - 1;
drawCursor( FALSE );
cursor->setParagraph( p );
cursor->setIndex( index );
ensureCursorVisible();
drawCursor( TRUE );
updateCurrentFormat();
emit cursorPositionChanged( cursor );
emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
}
/*!
This function sets the \e *\a para and \e *\a index parameters to the
current cursor position. \a para and \a index must be non-null int
pointers.
\sa setCursorPosition()
*/
void QTextEdit::getCursorPosition( int *para, int *index ) const
{
if ( !para || !index )
return;
*para = cursor->paragraph()->paragId();
*index = cursor->index();
}
/*! Sets a selection which starts at position \a indexFrom in
paragraph \a paraFrom and ends at position \a indexTo in paragraph
\a paraTo. Existing selections which have a different id (selNum)
are not removed, existing selections which have the same id as \a
selNum are removed.
Uses the selection settings of selection \a selNum. If \a selNum is 0,
this is the default selection.
The cursor is moved to the end of the selection if \a selNum is 0,
otherwise the cursor position remains unchanged.
\sa getSelection() selectedText
*/
void QTextEdit::setSelection( int paraFrom, int indexFrom,
int paraTo, int indexTo, int selNum )
{
if ( doc->hasSelection( selNum ) ) {
doc->removeSelection( selNum );
repaintChanged();
}
if ( selNum > doc->numSelections() - 1 )
doc->addSelection( selNum );
QTextParagraph *p1 = doc->paragAt( paraFrom );
if ( !p1 )
return;
QTextParagraph *p2 = doc->paragAt( paraTo );
if ( !p2 )
return;
if ( indexFrom > p1->length() - 1 )
indexFrom = p1->length() - 1;
if ( indexTo > p2->length() - 1 )
indexTo = p2->length() - 1;
drawCursor( FALSE );
QTextCursor c = *cursor;
QTextCursor oldCursor = *cursor;
c.setParagraph( p1 );
c.setIndex( indexFrom );
cursor->setParagraph( p2 );
cursor->setIndex( indexTo );
doc->setSelectionStart( selNum, c );
doc->setSelectionEnd( selNum, *cursor );
repaintChanged();
ensureCursorVisible();
if ( selNum != QTextDocument::Standard )
*cursor = oldCursor;
drawCursor( TRUE );
}
/*!
If there is a selection, \e *\a paraFrom is set to the number of the
paragraph in which the selection begins and \e *\a paraTo is set to
the number of the paragraph in which the selection ends. (They could
be the same.) \e *\a indexFrom is set to the index at which the
selection begins within \e *\a paraFrom, and \e *\a indexTo is set to
the index at which the selection ends within \e *\a paraTo.
If there is no selection, \e *\a paraFrom, \e *\a indexFrom, \e *\a
paraTo and \e *\a indexTo are all set to -1.
\a paraFrom, \a indexFrom, \a paraTo and \a indexTo must be non-null
int pointers.
The \a selNum is the number of the selection (multiple selections
are supported). It defaults to 0 (the default selection).
\sa setSelection() selectedText
*/
void QTextEdit::getSelection( int *paraFrom, int *indexFrom,
int *paraTo, int *indexTo, int selNum ) const
{
if ( !paraFrom || !paraTo || !indexFrom || !indexTo )
return;
if ( !doc->hasSelection( selNum ) ) {
*paraFrom = -1;
*indexFrom = -1;
*paraTo = -1;
*indexTo = -1;
return;
}
doc->selectionStart( selNum, *paraFrom, *indexFrom );
doc->selectionEnd( selNum, *paraTo, *indexTo );
}
/*!
\property QTextEdit::textFormat
\brief the text format: rich text, plain text or auto text
The text format is one of the following:
\list
\i PlainText - all characters, except newlines, are displayed
verbatim, including spaces. Whenever a newline appears in the text the
text edit inserts a hard line break and begins a new paragraph.
\i RichText - rich text rendering. The available styles are
defined in the default stylesheet QStyleSheet::defaultSheet().
\i AutoText - this is the default. The text edit autodetects
which rendering style is best, \c PlainText or \c RichText. This is
done by using the QStyleSheet::mightBeRichText() function.
\endlist
*/
void QTextEdit::setTextFormat( TextFormat format )
{
doc->setTextFormat( format );
}
Qt::TextFormat QTextEdit::textFormat() const
{
return doc->textFormat();
}
/*!
Returns the number of paragraphs in the text; this could be 0.
*/
int QTextEdit::paragraphs() const
{
return doc->lastParagraph()->paragId() + 1;
}
/*!
Returns the number of lines in paragraph \a para, or -1 if there
is no paragraph with index \a para.
*/
int QTextEdit::linesOfParagraph( int para ) const
{
QTextParagraph *p = doc->paragAt( para );
if ( !p )
return -1;
return p->lines();
}
/*!
Returns the length of the paragraph \a para (number of
characters), or -1 if there is no paragraph with index \a para
*/
int QTextEdit::paragraphLength( int para ) const
{
QTextParagraph *p = doc->paragAt( para );
if ( !p )
return -1;
return p->length() - 1;
}
/*!
Returns the number of lines in the text edit; this could be 0.
\warning This function may be slow. Lines change all the time
during word wrapping, so this function has to iterate over all the
paragraphs and get the number of lines from each one individually.
*/
int QTextEdit::lines() const
{
QTextParagraph *p = doc->firstParagraph();
int l = 0;
while ( p ) {
l += p->lines();
p = p->next();
}
diff --git a/noncore/apps/oxygen/calcdlgui.cpp b/noncore/apps/oxygen/calcdlgui.cpp
index f8dfde5..2bb8337 100644
--- a/noncore/apps/oxygen/calcdlgui.cpp
+++ b/noncore/apps/oxygen/calcdlgui.cpp
@@ -1,64 +1,63 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
-#include "oxygen.h"
#include "calcdlgui.h"
#include "kmolcalc.h"
#include <qlineedit.h>
#include <qmultilineedit.h>
#include <qpushbutton.h>
calcDlgUI::calcDlgUI() : CalcDlg()
{
kmolcalc = new KMolCalc;
connect( calculate, SIGNAL( clicked() ), this, SLOT( calc() ) );
connect( clear_fields, SIGNAL( clicked() ), this, SLOT( clear() ) );
result->setReadOnly( true );
}
void calcDlgUI::calc()
{
QString compound( formula->text() );
if ( compound.isEmpty() ) {
clear();
return;
}
QString errors( kmolcalc->readFormula( compound ) );
QString mw, ea;
double weight = kmolcalc->getWeight();
if ( errors == "OK" ) {
mw.setNum( weight );
ea = kmolcalc->getEmpFormula() + " :\n" + kmolcalc->getEA();
} else {
mw = "???";
ea = tr( "ERROR: \n" ).arg( errors )+ "\n";
}
result->setText( mw );
anal_display->setText( ea );
}
/**
* * Clear all text entry / result fields.
* */
void calcDlgUI::clear()
{
formula->clear();
result->clear();
anal_display->clear();
}
diff --git a/noncore/apps/oxygen/dataTable.cpp b/noncore/apps/oxygen/dataTable.cpp
index e3906be..48e2b20 100644
--- a/noncore/apps/oxygen/dataTable.cpp
+++ b/noncore/apps/oxygen/dataTable.cpp
@@ -1,152 +1,149 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
#include <qpe/config.h>
#include "dataTable.h"
-#include <qwidget.h>
#include <qhbox.h>
#include <qlabel.h>
-#include <qfont.h>
#include <qlayout.h>
#include <qpe/qpeapplication.h>
-#include <qstringlist.h>
OxydataWidget::OxydataWidget(QWidget *parent, const char *name, const QStringList &list ) : QWidget( parent,name ), names( list )
{
QGridLayout *qgrid = new QGridLayout( this, 2,1 );
QHBox *hbox = new QHBox( this );
left = new QLabel( hbox );
middle = new QLabel( hbox );
right = new QLabel( hbox );
right->setAlignment( AlignRight );
middle->setAlignment( AlignHCenter );
QFont bf;
bf.setBold( true );
bf.setPointSize( bf.pointSize()+2 );
middle->setFont( bf );
DataTable = new OxydataTable( 9,2, this );
setTable();
qgrid->addWidget( hbox,0,0 );
qgrid->addWidget( DataTable,1,0 );
}
void OxydataWidget::setElement( int el )
{
QStringList::ConstIterator it = names.at(el);
Config configobj( QPEApplication::qpeDir() +"share/oxygen/oxygendata", Config::File );
configobj.setGroup( QString::number( el+1 ));
left->setText( configobj.readEntry( "Symbol" ) );
middle->setText( *it );
right->setText( QString::number( el+1 ) );
DataTable->setText( 0,1,tr( "%1 u" ).arg( configobj.readEntry( "Weight" ) ) );
DataTable->setText( 1,1,configobj.readEntry( "Block" ) );
DataTable->setText( 2,1,configobj.readEntry( "Group" ) );
DataTable->setText( 3,1,configobj.readEntry( "EN" ) );
DataTable->setText( 4,1,tr( "%1 pm" ).arg( configobj.readEntry( "AR" ) ) ) ;
DataTable->setText( 5,1,tr( "%1 J" ).arg( configobj.readEntry( "IE" ) ) );
DataTable->setText( 6,1,tr( "%1 g/cm^3" ).arg( configobj.readEntry( "Density" ) ) );
DataTable->setText( 7,1,tr( "%1 K" ).arg( configobj.readEntry( "BP" ) ) );
DataTable->setText( 8,1,tr( "%1 K" ).arg( configobj.readEntry( "MP" ) ) );
}
void OxydataWidget::setTable() const
{
DataTable->setText( 0,0, tr( "Weight" ) );
DataTable->setText( 1,0, tr( "Block" )) ;
DataTable->setText( 2,0, tr( "Group" )) ;
DataTable->setText( 3,0, tr( "Electronegativity" )) ;
DataTable->setText( 4,0, tr( "Atomic radius" )) ;
DataTable->setText( 5,0, tr( "Ionization Energy" )) ;
DataTable->setText( 6,0, tr( "Density" )) ;
DataTable->setText( 7,0, tr( "Boiling point" ) );
DataTable->setText( 8,0, tr( "Melting point" ) );
}
void OxydataWidget::setLayout()
{
#warning this is not working and I have no idea why!
// DataTable->setColumnWidth ( 0 , this->width()/2 );
// DataTable->setColumnWidth ( 1 , this->width()/2 );
//X DataTable->setColumnWidth ( 0 , 110 );
//X DataTable->setColumnWidth ( 1 , 110 );
}
OxydataTable::OxydataTable(int numRows, int numCols, QWidget *parent,
const char *name) : QTable(numRows, numCols,parent, name)
{
for (int zeile = 0; zeile < numRows; zeile++)
for ( int spalte = 0; spalte < numCols; spalte++ )
{
OxydataQTI *testus = new OxydataQTI (this, OxydataQTI::Never, "hm" );
setItem(zeile, spalte, (QTableItem*)testus);
}
this->setShowGrid( false );
this->setHScrollBarMode(QScrollView::AlwaysOff);
this->horizontalHeader()->hide();
this->verticalHeader()->hide();
this->setTopMargin( 0 );
this->setLeftMargin( 0 );
}
void OxydataTable::paintCell( QPainter *p, int row, int col, const QRect &cr, bool selected)
{
if ( cr.width() == 0 || cr.height() == 0 )
return;
selected = FALSE;
QTableItem *itm = item( row, col );
QColorGroup colgrp = colorGroup();
if ( itm )
{
if ( row%2 )
colgrp.setColor( QColorGroup::Base, QColor( 180,200,210 ) );
else
colgrp.setColor( QColorGroup::Base, QColor( 230,235,235 ) );
p->save();
itm->paint( p, colgrp, cr, selected );
p->restore();
}
}
OxydataQTI::OxydataQTI(QTable * table, EditType et, const QString & text )
: QTableItem ( table, et, text )
{
}
int OxydataQTI::alignment() const
{
if ( col()%2 )
{
return AlignRight | AlignVCenter;
}else return AlignLeft | AlignVCenter;
};
diff --git a/noncore/apps/oxygen/datawidgetui.cpp b/noncore/apps/oxygen/datawidgetui.cpp
index e1d6e41..dcb80e5 100644
--- a/noncore/apps/oxygen/datawidgetui.cpp
+++ b/noncore/apps/oxygen/datawidgetui.cpp
@@ -1,53 +1,48 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
#include "datawidgetui.h"
#include "dataTable.h"
-#include <qpe/config.h>
-#include <qstring.h>
#include <qcombobox.h>
#include <qlayout.h>
-#include <qhbox.h>
-#include <qlabel.h>
-#include <qpe/qpeapplication.h>
dataWidgetUI::dataWidgetUI(const QStringList &list) : QWidget()
{
names = list;
this->setCaption( tr( "Chemical Data" ));
QGridLayout *qgrid = new QGridLayout( this, 2,1 );
dataCombo = new QComboBox( this );
//read in all names of the 118 elements
int i = 0;
for ( QStringList::ConstIterator it = names.begin() ; it != names.end() ; ++it,i++)
{
dataCombo->insertItem( QString::number( i+1 )+" - "+*it );
}
OxydataWidget *oxyDW = new OxydataWidget(this, "OxydataWidget_oxyDW", names);
connect ( dataCombo, SIGNAL( activated(int) ), oxyDW, SLOT( setElement(int) ) );
oxyDW->setElement( 0 );
oxyDW->setLayout();
qgrid->addWidget( dataCombo, 0,0);
qgrid->addWidget( oxyDW , 1,0 );
}
diff --git a/noncore/apps/oxygen/kmolcalc.cpp b/noncore/apps/oxygen/kmolcalc.cpp
index 7a47942..b9f5209 100644
--- a/noncore/apps/oxygen/kmolcalc.cpp
+++ b/noncore/apps/oxygen/kmolcalc.cpp
@@ -1,199 +1,196 @@
/*
* kmolcalc.cpp
*
* Copyright (C) 2000,2001 Tomislav Gountchev <tomi@idiom.com>
* Copyright (C) 2002 Carsten Niehaus <cniehaus@handhelds.org>
*/
/**
* KMOLCALC is the calculation engine. It knows about a hashtable of user defined atomic
* weights and group definitions ELSTABLE, and the currently processed formula, stored
* as a list of elements and their coefficients, ELEMENTS.
*/
#include "kmolcalc.h"
-#include <qdict.h>
-#include <qdir.h>
-#include <qfile.h>
#include <qpe/qpeapplication.h>
/**
* Construct a new calculator object.
*/
KMolCalc::KMolCalc() {
elements = new ElementList;
elstable = NULL;
readElstable();
}
KMolCalc::~KMolCalc() {
delete elements;
}
void KMolCalc::readElstable() {
weight = -1; // not calculated yet
if (elstable) delete elstable;
elstable = new QDict<SubUnit> (197, TRUE);
elstable->setAutoDelete(TRUE);
mwfile = QPEApplication::qpeDir() +"share/oxygen/kmolweights";
QFile f(mwfile);
if (f.exists()) readMwfile(f);
}
/**
* Parse a string S and construct the ElementList this->ELEMENTS, representing the
* composition of S. Returns 0 if successful, or an error code (currently -1) if
* parsing failed.
* The elements is S must be valid element or group symbols, as stored in this->ELSTABLE.
* See help files for correct formula syntax.
*/
QString KMolCalc::readFormula(const QString& s) {
weight = -1;
if (elements) delete elements;
elements = new ElementList;
return KMolCalc::readGroup(s, elements);
}
// read a formula group recursively. Called by readFormula.
QString KMolCalc::readGroup(const QString& s, ElementList* els) {
if (s.isEmpty()) return QString ("Enter a formula."); //ERROR
int sl = s.length();
int i = 0;
QString errors ("OK");
bool ok = TRUE;
while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++;
double prefix = (i == 0 ? 1 : s.left(i).toDouble(&ok));
if (! ok || i == sl || prefix == 0) return QString ("Bad formula."); // ERROR
ElementList* elstemp = new ElementList;
while (i < sl) {
int j = i;
if (s[i] == '(') {
ElementList* inner = new ElementList;
int level = 1; // count levels of nested ( ).
while (1) {
if (i++ == sl) {
delete inner;
delete elstemp;
return QString ("Bad formula."); //ERROR
}
if (s[i] == '(') level++;
if (s[i] == ')') level--;
if (level == 0) break;
}
errors = KMolCalc::readGroup(s.mid(j+1, i-j-1), inner);
j = ++i;
while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++;
double suffix = (i == j ? 1 : s.mid(j, i-j).toDouble(&ok));
if (! ok || suffix == 0) {
delete inner;
delete elstemp;
return QString ("Bad formula."); // ERROR
}
inner->addTo(*elstemp, suffix);
delete inner;
inner = NULL;
} else if ((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z')) {
while (++i < sl && ((s[i] >= 'a' && s[i] <= 'z') || s[i] == '*' ||
s[i] == '\''));
QString elname = s.mid(j, i-j);
j = i;
while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++;
double suffix = (i == j ? 1 : s.mid(j, i-j).toDouble(&ok));
if (! ok || suffix == 0) {
delete elstemp;
return QString ("Bad formula."); // ERROR
}
SubUnit* group = elstable->find(elname);
if (group == 0) {
delete elstemp;
return QString ("Undefined symbol: ") + elname; //ERROR
}
group->addTo(*elstemp, suffix);
} else if (s[i] == '+') {
if (elstemp->isEmpty()) {
delete elstemp;
return QString ("Bad formula."); //ERROR
}
elstemp->addTo(*els, prefix);
delete elstemp;
errors = KMolCalc::readGroup(s.mid(i+1, sl-i-1), els);
return errors;
} else {
delete elstemp;
return QString ("Bad formula."); //ERROR
}
}
elstemp->addTo(*els, prefix);
delete elstemp;
return errors;
}
/**
* Calculate and return the molecular weight of the current chemical formula.
*/
double KMolCalc::getWeight() {
if (weight == -1) weight = elements->getWeight(elstable);
return weight;
}
/**
* Return the elemental composition of the current formula, as a string of tab-separated
* element - percentage pairs, separated by newlines.
*/
QString KMolCalc::getEA() {
if (weight == -1) weight = elements->getWeight(elstable);
if (weight == -1) return QString("ERROR: Couldn't get Mw..."); // ERROR
return elements->getEA(elstable, weight);
}
/**
* Return the empirical formula of the current compound as a QString.
*/
QString KMolCalc::getEmpFormula() {
return elements->getEmpFormula();
}
// Read the element definition file.
void KMolCalc::readMwfile(QFile& f) {
if (! f.open(IO_ReadOnly)) return; //ERROR
QTextStream fs (&f);
QString line;
while (! fs.eof()) {
line = fs.readLine();
SubUnit* s = SubUnit::makeSubUnit(line);
elstable->replace(s->getName(), s);
}
f.close();
}
/**
* Remove a group or element definition from ELSTABLE.
*/
void KMolCalc::undefineGroup (const QString& name) {
elstable->remove (name);
}
/**
* Add a new element name - atomic weight record to the ELSTABLE hashtable. Assumes
* NAME has valid syntax.
*/
void KMolCalc::defineElement (const QString& name, double weight) {
Element* el = new Element(name, weight);
elstable->replace(name, el);
}
/**
* Add a new group definition to the ELSTABLE. Returns 0 if OK, -1 if parsing FORMULA
* fails. Assumes the syntax of grpname is correct.
*/
QString KMolCalc::defineGroup (const QString& grpname, const QString& formula) {
ElementList* els = new ElementList(grpname);
QString error = readGroup(formula, els);
if (error != "OK") return error;
if (els->contains(grpname)) return QString("Can't define a group recursively!\n");
elstable->replace(grpname, els);
return QString("OK");
}
diff --git a/noncore/apps/oxygen/oxyframe.cpp b/noncore/apps/oxygen/oxyframe.cpp
index 5a4dbbe..8cc520e 100644
--- a/noncore/apps/oxygen/oxyframe.cpp
+++ b/noncore/apps/oxygen/oxyframe.cpp
@@ -1,41 +1,39 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
-#include "oxygen.h"
-#include <qpe/config.h>
#include "oxyframe.h"
OxyFrame::OxyFrame(QWidget *parent, const char *name, QString symbol )
: QLabel(parent,name)
{
N = name;
this->setFrameStyle( QFrame::Box );
this->setLineWidth( 0 );
this->setMidLineWidth( 1 );
this->setFrameShadow( QFrame::Sunken );
setMinimumSize(6,6);
setScaledContents( true );
QFont font;
font.setWeight(QFont::Light);
font.setPixelSize(3);
setFont( font );
setText( symbol );
}
void OxyFrame::mousePressEvent ( QMouseEvent* /*e*/ ){
emit num( N );
};
diff --git a/noncore/apps/oxygen/oxygen.cpp b/noncore/apps/oxygen/oxygen.cpp
index 5bdc2aa..5ea97bf 100644
--- a/noncore/apps/oxygen/oxygen.cpp
+++ b/noncore/apps/oxygen/oxygen.cpp
@@ -1,157 +1,155 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
#include "oxygen.h"
-#include <qapplication.h>
#include <qtabwidget.h>
-#include "calcdlg.h"
#include "calcdlgui.h"
#include "datawidgetui.h"
#include "psewidget.h"
Oxygen::Oxygen( QWidget *parent, const char *name, WFlags f) : QMainWindow( parent, name, f )
{
loadNames();
calcDlgUI *CalcDlgUI = new calcDlgUI();
PSEWidget *pse = new PSEWidget(names);
dataWidgetUI *DataWidgetUI = new dataWidgetUI(names);
setCaption( tr( "Oxygen" ) );
QTabWidget *tabw = new QTabWidget( this , "qtab" );
tabw->addTab( pse, tr( "PSE" ));
tabw->addTab( DataWidgetUI , tr( "Data" ) );
tabw->addTab( CalcDlgUI, tr( "Calculations" ) );
setCentralWidget( tabw );
}
void Oxygen::loadNames()
{
names.clear();
names.append( tr("Hydrogen") );
names.append( tr("Helium") );
names.append( tr("Lithium") );
names.append( tr("Beryllium") );
names.append( tr("Boron") );
names.append( tr("Carbon") );
names.append( tr("Nitrogen") );
names.append( tr("Oxygen") );
names.append( tr("Fluorine") );
names.append( tr("Neon") );
names.append( tr("Sodium") );
names.append( tr("Magnesium") );
names.append( tr("Aluminum") );
names.append( tr("Silicon") );
names.append( tr("Phosphorus") );
names.append( tr("Sulfur") );
names.append( tr("Chlorine") );
names.append( tr("Argon") );
names.append( tr("Potassium") );
names.append( tr("Calcium") );
names.append( tr("Scandium") );
names.append( tr("Titanium") );
names.append( tr("Vanadium") );
names.append( tr("Chromium") );
names.append( tr("Manganese") );
names.append( tr("Iron") );
names.append( tr("Cobalt") );
names.append( tr("Nickel") );
names.append( tr("Copper") );
names.append( tr("Zinc") );
names.append( tr("Gallium") );
names.append( tr("Germanium") );
names.append( tr("Arsenic") );
names.append( tr("Selenium") );
names.append( tr("Bromine") );
names.append( tr("Krypton") );
names.append( tr("Rubidium") );
names.append( tr("Strontium") );
names.append( tr("Yttrium") );
names.append( tr("Zirconium") );
names.append( tr("Niobium") );
names.append( tr("Molybdenum") );
names.append( tr("Technetium") );
names.append( tr("Ruthenium") );
names.append( tr("Rhodium") );
names.append( tr("Palladium") );
names.append( tr("Silver") );
names.append( tr("Cadmium") );
names.append( tr("Indium") );
names.append( tr("Tin") );
names.append( tr("Antimony") );
names.append( tr("Tellurium") );
names.append( tr("Iodine") );
names.append( tr("Xenon") );
names.append( tr("Cesium") );
names.append( tr("Barium") );
names.append( tr("Lanthanum") );
names.append( tr("Cerium") );
names.append( tr("Praseodymium") );
names.append( tr("Neodymium") );
names.append( tr("Promethium") );
names.append( tr("Samarium") );
names.append( tr("Europium") );
names.append( tr("Gadolinium") );
names.append( tr("Terbium") );
names.append( tr("Dysprosium") );
names.append( tr("Holmium") );
names.append( tr("Erbium") );
names.append( tr("Thulium") );
names.append( tr("Ytterbium") );
names.append( tr("Lutetium") );
names.append( tr("Hafnium") );
names.append( tr("Tantalum") );
names.append( tr("Tungsten") );
names.append( tr("Rhenium") );
names.append( tr("Osmium") );
names.append( tr("Iridium") );
names.append( tr("Platinum") );
names.append( tr("Gold") );
names.append( tr("Mercury") );
names.append( tr("Thallium") );
names.append( tr("Lead") );
names.append( tr("Bismuth") );
names.append( tr("Polonium") );
names.append( tr("Astatine") );
names.append( tr("Radon") );
names.append( tr("Francium") );
names.append( tr("Radium") );
names.append( tr("Actinium") );
names.append( tr("Thorium") );
names.append( tr("Protactinium") );
names.append( tr("Uranium") );
names.append( tr("Neptunium") );
names.append( tr("Plutonium") );
names.append( tr("Americium") );
names.append( tr("Curium") );
names.append( tr("Berkelium") );
names.append( tr("Californium") );
names.append( tr("Einsteinium") );
names.append( tr("Fermium") );
names.append( tr("Mendelevium") );
names.append( tr("Nobelium") );
names.append( tr("Lawrencium") );
names.append( tr("Rutherfordium") );
names.append( tr("Dubnium") );
names.append( tr("Seaborgium") );
names.append( tr("Bohrium") );
names.append( tr("Hassium") );
names.append( tr("Meitnerium") );
}
diff --git a/noncore/apps/oxygen/psewidget.cpp b/noncore/apps/oxygen/psewidget.cpp
index be5185b..7f7ae0c 100644
--- a/noncore/apps/oxygen/psewidget.cpp
+++ b/noncore/apps/oxygen/psewidget.cpp
@@ -1,198 +1,196 @@
/***************************************************************************
application: : Oxygen
begin : September 2002
copyright : ( C ) 2002, 2003 by Carsten Niehaus
email : cniehaus@handhelds.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. *
* *
**************************************************************************/
#include <qpe/config.h>
#include <qlayout.h>
#include <qpe/qpeapplication.h>
-#include <qlist.h>
#include "dataTable.h"
#include "psewidget.h"
-#include "oxyframe.h"
PSEWidget::PSEWidget(const QStringList &list) : QWidget()
{
this->setCaption( tr( "Periodic System" ) );
lastElement=1;
names = list;
QVBoxLayout *vlay = new QVBoxLayout( this );
QGridLayout *grid = new QGridLayout( 18,10 );
int h=0, v=0;
Config configobj( QPEApplication::qpeDir() +"share/oxygen/oxygendata", Config::File );
for( int n = 0 ; n < 109 ; n++ )
{
configobj.setGroup( QString::number( n+1 ));
position( n+1,h,v );
PSEframe.append( new OxyFrame( this , QString::number(n), configobj.readEntry( "Symbol" ) ) );
grid->addWidget( PSEframe.current() , v/40+1 , h/40 );
PSEframe.current()->setMinimumHeight( 11 );
PSEframe.current()->setPalette( QPalette( PSEColor( configobj.readEntry( "Block" ) ) ) );
connect( PSEframe.current(), SIGNAL( num(QString) ), this, SLOT( slotShowElement(QString) ));
connect( PSEframe.current(), SIGNAL( num(QString) ), this, SLOT( inverseColor(QString) ));
}
oxyDW = new OxydataWidget(this, "PSEWidget_oxyDW", names);
oxyDW->setElement( 0 );
oxyDW->setLayout();
vlay->addLayout( grid );
vlay->addWidget( oxyDW );
}
QColor PSEWidget::PSEColor( QString block ) const
{
QColor c;
if ( block == "s" ) c.setRgb( 213 , 233 , 231 );
else if ( block == "d" ) c.setRgb( 200,230,160 );
else if ( block == "p" ) c.setRgb( 238,146,138 );
else if ( block == "f" ) c.setRgb( 190 , 190 , 190 );
return c;
};
void PSEWidget::inverseColor( QString number)
{
Config configobj( QPEApplication::qpeDir() +"share/oxygen/oxygendata", Config::File );
configobj.setGroup( number );
QString block = configobj.readEntry( "Block" );
QColor c, d;
c = PSEColor( block );
d = c.dark();
PSEframe.at( number.toUInt() )->setPalette( QPalette( d ) );
configobj.setGroup( QString::number( lastElement+1 ) );
block = configobj.readEntry( "Block" );
c = PSEColor( block );
PSEframe.at( lastElement )->setPalette( QPalette( c ) );
lastElement=number.toInt();
}
void PSEWidget::slotShowElement(QString number)
{
oxyDW->setElement( number.toInt() );
};
void PSEWidget::position(int n, int& h, int& v)
{
//Hydrogen
if (n == 1)
{
h=0; v=0;
}
//Helium
if (n == 2)
{
h=680; v=0;
}
//Lithium
if (n == 3)
{
h=0; v=40;
}
//Beryllium
if (n == 4)
{
h=40; v=40;
}
//Boron-->Neon or Aluminum --> Argon
if ((n >= 5 && n <= 10) || (n >= 13 && n <= 18))
for (int i = 1; i <= (6-(10-n)); i++)
{
h=((i*40)+440);
v = 40;
if (n >= 13)
{
v=80;
h=(h-320);
}
}
//Sodium
if (n == 11)
{
h=0; v=80;
}
//Magnesium
if (n == 12)
{
h=40; v=80;
}
//Potassium --> Uuo without La and Ac
if ((n >= 19 && n <= 57) || (n >= 72 && n <= 89) || n >= 104)
for (int i = 1; i <= 18; i++)
{
int f = n;
if (n > 18)
f = n-18;
if (n > 36)
f = n-36;
if (n > 54)
f = n-54;
if (n > 71)
f = n-68;
if (n > 86)
f = n-86;
if (n > 103)
f = n-100;
h=((f*40)-40);
v = 120;
if (n >= 37)
v=160;
if (n >= 55)
v=200;
if (n >= 87)
v=240;
}
//Lanthanum --> Lutetium and Actinum --> Lawrencium
if ((n >= 58 && n <= 71) || (n >= 90 && n <= 103))
for (int i = 1; i <= 14; i++)
{
int f = n;
if (n > 57)
f = n-55;
if (n > 88)
f = n-87;
h=(f*40);
v = 290;
if (n >= 90)
v=330;
}
v += 10;
}
diff --git a/noncore/apps/qashmoney/account.cpp b/noncore/apps/qashmoney/account.cpp
index 181be23..f21598e 100755
--- a/noncore/apps/qashmoney/account.cpp
+++ b/noncore/apps/qashmoney/account.cpp
@@ -1,376 +1,374 @@
#include "account.h"
-#include "transaction.h"
-#include "transfer.h"
#include "preferences.h"
#include <qpixmap.h>
#include <stdlib.h>
extern Preferences *preferences;
Account::Account ()
{
adb = sqlite_open ( "qmaccounts.db", 0, NULL );
}
Account::~Account ()
{
sqlite_close ( adb );
}
void Account::addAccount ( QString name, int parentid, float balance, int type, QString description, float creditlimit,
int statementyear, int statementmonth, int statementday, float statementbalance, const char *currency )
{
sqlite_exec_printf ( adb, "insert into accounts2 values ( '%q', %i, %.2f, %i, '%q', %.2f, %i, %i, %i, %.2f, '%q', 0, 0, 0, 0, 0, NULL );", 0, 0, 0,
(const char *) name, parentid, balance, type, (const char *) description, creditlimit, statementyear, statementmonth, statementday, statementbalance, currency );
}
void Account::updateAccount ( QString name, QString description, QString currencycode, int accountid )
{
sqlite_exec_printf ( adb, "update accounts2 set name = '%q', description = '%q', currency = '%q' where accountid = %i;", 0, 0, 0, ( const char * ) name, ( const char * ) description, ( const char * ) currencycode, accountid );
}
void Account::deleteAccount ( int accountid )
{
sqlite_exec_printf ( adb, "delete from accounts2 where accountid = %i;", 0, 0, 0, accountid );
}
void Account::setAccountExpanded ( int expanded, int accountid )
{
sqlite_exec_printf ( adb, "update accounts2 set r1 = %i where accountid = %i;", 0, 0, 0, expanded, accountid );
}
int Account::getAccountExpanded ( int id )
{
char **results;
sqlite_get_table_printf ( adb, "select r1 from accounts2 where accountid = %i;", &results, 0, 0, 0, id );
if ( strlen ( results [1] ) == 0 )
return 0;
else
return atoi ( results [ 1 ] );
}
int Account::getNumberOfAccounts ()
{
char **results;
sqlite_get_table ( adb, "select count() from accounts2;", &results, NULL, NULL, NULL );
return atoi ( results [ 1 ] );
}
int Account::getNumberOfChildAccounts ( int id )
{
char **results;
sqlite_get_table_printf ( adb, "select count() from accounts2 where parent = %i;", &results, NULL, NULL, NULL, id );
return atoi ( results [ 1 ] );
}
void Account::updateAccountBalance ( int accountid )
{
// Here, we'll get a balance for the transactions in an account
sqlite *tdb = sqlite_open ( "qmtransactions.db", 0, NULL );
int rows, columns;
char **results;
sqlite_get_table_printf ( tdb, "select sum (amount) from transactions where accountid= %i;", &results, &rows, &columns, NULL, accountid );
float transactionsbalance = strtod ( results [ 1 ], 0 );
sqlite_close ( tdb );
// next, we'll get a balance for all the transfers from the account
sqlite *trdb = sqlite_open ( "qmtransfers.db", 0, NULL );
rows = 0;
columns = 0;
char **results2;
sqlite_get_table_printf ( trdb, "select sum (amount) from transfers where fromaccount = %i;", &results2, &rows, &columns, NULL, accountid );
float fromtransfersbalance = ( strtod ( results2 [ 1 ], 0 ) * -1 );
// finally, we'll get a balance for all the transfers into the account
rows = 0;
columns= 0;
char **results3;
sqlite_get_table_printf ( trdb, "select sum (amount) from transfers where toaccount = %i;", &results3, &rows, &columns, NULL, accountid );
float totransfersbalance = strtod ( results3 [ 1 ], 0 );
sqlite_close ( trdb );
// calculate and update new balance
sqlite_exec_printf ( adb, "update accounts2 set balance = %.2f where accountid = %i;", 0, 0, 0,
( transactionsbalance + fromtransfersbalance + totransfersbalance + getStatementBalance ( accountid ) ), accountid );
}
void Account::changeParentAccountBalance ( int parentid )
{
// select all child balances that share the parent of the current child account
char **results;
int rows;
sqlite_get_table_printf ( adb, "select sum ( balance ) from accounts2 where parent = %i;", &results, &rows, NULL, NULL, parentid );
sqlite_exec_printf ( adb, "update accounts2 set balance = %.2f where accountid = %i;", 0, 0, 0, strtod ( results[ 1 ], NULL ), parentid );
}
int Account::getParentAccountID ( int id )
{
char **results;
sqlite_get_table_printf ( adb, "select parent from accounts2 where accountid = %i;", &results, NULL, NULL, NULL, id );
return atoi ( results [ 1 ] );
}
int Account::getParentAccountID ( QString accountname )
{
char **results;
sqlite_get_table_printf ( adb, "select parent from accounts2 where name= '%q';", &results, NULL, NULL, NULL, ( const char * ) accountname );
return atoi ( results [ 1 ] );
}
void Account::displayAccounts ( QListView *listview )
{
char **results;
int rows, columns;
sqlite_get_table ( adb, "select name, parent, balance, accountid, currency from accounts2;", &results, &rows, &columns, 0 );
// determine if we are using currency support
int currency = preferences->getPreference ( 4 );
// remove all columns from the account display
int counter;
for ( counter = 0; counter <= columns; counter++ )
listview->removeColumn ( 0 );
// add columns to the account display
listview->addColumn ( "Account", 0 );
int columntoalign = 1;
if ( preferences->getPreference ( 4 ) == 1 ) // add the currency column if the user wants it
{
listview->addColumn ( "C", 0 );
columntoalign = 2;
}
listview->addColumn ( "Balance", 0 );
listview->addColumn ( "", 0 );
listview->setColumnAlignment ( columntoalign, Qt::AlignRight );
counter = 5;
int total = ( rows + 1 ) * columns;
while ( counter < total )
{
int accountid = atoi ( results [ counter + 3 ] );
if ( atoi ( results [ counter + 1 ] ) == -1 )
{
QListViewItem *parent = new QListViewItem ( listview );
parent->setText ( 0, results [ counter ] );
if ( currency == 0 )
{
parent->setText ( 1, results [ counter + 2 ] );
parent->setText ( 2, results [ counter + 3 ] );
}
else
{
if ( getNumberOfChildAccounts ( accountid ) == 0 ) // add the currency flag if this is a parent with no children
{
// create the string we'll use to set the currency pixmap
QString filename = "/opt/QtPalmtop/pics/flags/";
QString flag = results [ counter + 4 ];
filename.append ( flag );
filename.append ( ".png" );
parent->setPixmap ( 1, QPixmap ( filename ) );
parent->setText ( 1, flag );
}
parent->setText ( 2, results [ counter + 2 ] );
parent->setText ( 3, results [ counter + 3 ] );
}
if ( getAccountExpanded ( accountid ) == 1 )
parent->setOpen ( TRUE );
//Start display child accounts for this parent
int childcounter = 5;
while ( childcounter < total )
{
if ( atoi ( results [ childcounter + 1 ] ) == accountid )
{
if ( currency == 0 )
QListViewItem *child = new QListViewItem ( parent, results [ childcounter ], results [ childcounter + 2 ], results [ childcounter + 3 ] );
else
{
// create the string we'll use to set the currency pixmap
QString filename = "/opt/QtPalmtop/pics/flags/";
QString flag = results [ childcounter + 4 ];
filename.append ( flag );
filename.append ( ".png" );
QListViewItem *child = new QListViewItem ( parent, results [ childcounter ], "", results [ childcounter + 2 ], results [ childcounter + 3 ] );
child->setPixmap ( 1, QPixmap ( filename ) );
child->setText ( 1, flag );
}
}
childcounter = childcounter + 5;
}
//End display child accounts
}
counter = counter + 5;
}
// resize all columns appropriately
if ( preferences->getPreference ( 4 ) == 0 )
{
listview->setColumnWidth ( 0, preferences->getColumnPreference ( 1 ) );
listview->setColumnWidthMode ( 0, QListView::Manual );
listview->setColumnWidth ( 1, preferences->getColumnPreference ( 2 ) );
listview->setColumnWidthMode ( 1, QListView::Manual );
listview->setColumnWidthMode ( 2, QListView::Manual );
}
else
{
listview->setColumnWidth ( 0, preferences->getColumnPreference ( 10 ) );
listview->setColumnWidthMode ( 0, QListView::Manual );
listview->setColumnWidth ( 1, preferences->getColumnPreference ( 11 ) );
listview->setColumnWidthMode ( 1, QListView::Manual );
listview->setColumnWidth ( 2, preferences->getColumnPreference ( 12 ) );
listview->setColumnWidthMode ( 2, QListView::Manual );
listview->setColumnWidthMode ( 3, QListView::Manual );
}
// Now reset the column sorting to user preference
int column = 0;
int direction = 0;
preferences->getSortingPreference ( 1, &column, &direction );
listview->setSorting ( column, direction );
}
int Account::displayParentAccountNames ( QComboBox *combobox, QString indexstring )
{
char **results;
int rows, columns, index;
index = 0;
sqlite_get_table ( adb, "select name from accounts2 order by name asc;", &results, &rows, &columns, NULL );
int counter = 1;
int indexcounter = 1;
int total = ( rows + 1 ) * columns;
while ( counter < total )
{
if ( getParentAccountID ( results [ counter ] ) == -1 )
{
combobox->insertItem ( results [ counter ], -1 );
if ( strcmp ( results [ counter ], indexstring ) == 0 )
index = indexcounter;
indexcounter++;
}
counter ++;
}
return index;
}
int Account::getAccountType ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select type from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return atoi ( results [ 1 ] );
}
int Account::getStatementDay ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select statementday from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return atoi ( results [ 1 ] );
}
int Account::getStatementMonth ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select statementmonth from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return atoi ( results [ 1 ] );
}
int Account::getStatementYear ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select statementyear from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return atoi ( results [ 1 ] );
}
QString Account::getAccountDescription ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select description from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return ( QString ) results [ 1 ];
}
QString Account::getCurrencyCode ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select currency from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return ( QString ) results [ 1 ];
}
QString Account::getAccountName ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select name from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return ( QString ) results [ 1 ];
}
QString Account::getAccountBalance ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select balance from accounts2 where accountid= %i;", &results, NULL, NULL, NULL, accountid );
return ( QString ) results [ 1 ];
}
float Account::getAccountCreditLimit ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select creditlimit from accounts2 where accountid = %i;", &results, NULL, NULL, NULL, accountid );
return strtod ( results [ 1 ], NULL );
}
float Account::getStatementBalance ( int accountid )
{
char **results;
sqlite_get_table_printf ( adb, "select statementbalance from accounts2 where accountid = %i;", &results, NULL, NULL, NULL, accountid );
return strtod ( results [ 1 ], NULL );
}
GreyBackgroundItem::GreyBackgroundItem ( QListView *parent )
: QListViewItem ( parent )
{
}
GreyBackgroundItem::GreyBackgroundItem ( QListView *parent, QString label1, QString label2, QString label3 )
: QListViewItem ( parent, label1, label2, label3 )
{
}
GreyBackgroundItem::GreyBackgroundItem ( QListView *parent, QString label1, QString label2, QString label3, QString label4 )
: QListViewItem ( parent, label1, label2, label3, label4 )
{
}
GreyBackgroundItem::GreyBackgroundItem ( QListView *parent, QString label1, QString label2, QString label3, QString label4, QString label5 )
: QListViewItem ( parent, label1, label2, label3, label4, label5 )
{
}
void GreyBackgroundItem::paintCell ( QPainter *p, const QColorGroup &cg, int column, int width, int alignment )
{
QColorGroup _cg ( cg );
_cg.setColor ( QColorGroup::Base, Qt::lightGray );
QListViewItem::paintCell ( p, _cg, column, width, alignment );
}
QStringList Account::getAccountNames ()
{
QStringList accountnames;
char **results;
int rows, counter;
sqlite_get_table ( adb, "select name from accounts2;", &results, &rows, 0, 0 );
for ( counter = 0; counter < rows; counter++ )
accountnames.append ( results [ counter+1 ] );
return accountnames;
}
QStringList Account::getAccountIDs ()
{
QStringList accountids;
char **results;
int rows, counter;
sqlite_get_table ( adb, "select accountid from accounts2;", &results, &rows, 0, 0 );
for ( counter = 0; counter < rows; counter++ )
accountids.append ( results [ counter+1 ] );
return accountids;
}
diff --git a/noncore/apps/qashmoney/accountdisplay.cpp b/noncore/apps/qashmoney/accountdisplay.cpp
index d0ba82a..5ef5454 100755
--- a/noncore/apps/qashmoney/accountdisplay.cpp
+++ b/noncore/apps/qashmoney/accountdisplay.cpp
@@ -1,448 +1,446 @@
-#include <qdatetime.h>
#include <qmessagebox.h>
#include <qheader.h>
#include "accountdisplay.h"
#include "newaccount.h"
#include "transaction.h"
#include "transferdialog.h"
-#include "preferences.h"
#include "transfer.h"
extern Account *account;
extern Transaction *transaction;
extern Transfer *transfer;
extern Preferences *preferences;
AccountDisplay::AccountDisplay ( QWidget *parent ) : QWidget ( parent )
{
cleared = 0;
firstline = new QHBox ( this );
firstline->setSpacing ( 2 );
newaccount = new QPushButton ( firstline );
newaccount->setPixmap ( QPixmap ("/opt/QtPalmtop/pics/new.png") );
connect ( newaccount, SIGNAL ( released () ), this, SLOT ( addAccount () ) );
editaccount = new QPushButton ( firstline );
editaccount->setPixmap ( QPixmap ("/opt/QtPalmtop/pics/edit.png") );
connect ( editaccount, SIGNAL ( released () ), this, SLOT ( editAccount () ) );
deleteaccount = new QPushButton ( firstline );
deleteaccount->setPixmap( QPixmap ( "/opt/QtPalmtop/pics/delete.png") );
connect ( deleteaccount, SIGNAL ( released () ), this, SLOT ( deleteAccount () ) );
transferbutton = new QPushButton ( firstline );
transferbutton->setPixmap( QPixmap ( "/opt/QtPalmtop/pics/transfer.png") );
transferbutton->setToggleButton ( TRUE );
connect ( transferbutton, SIGNAL ( toggled ( bool ) ), this, SLOT ( accountTransfer ( bool ) ) );
listview = new QListView ( this );
listview->setAllColumnsShowFocus ( TRUE );
listview->setShowSortIndicator ( TRUE );
listview->setRootIsDecorated ( TRUE );
listview->setMultiSelection ( FALSE );
connect ( listview, SIGNAL ( expanded ( QListViewItem * ) ), this, SLOT ( setAccountExpanded ( QListViewItem * ) ) );
connect ( listview, SIGNAL ( collapsed ( QListViewItem * ) ), this, SLOT ( setAccountCollapsed ( QListViewItem * ) ) );
listview->header()->setTracking ( FALSE );
connect ( listview->header(), SIGNAL ( sizeChange ( int, int, int ) ), this, SLOT ( saveColumnSize ( int, int, int ) ) );
connect ( listview->header(), SIGNAL ( clicked ( int ) ), this, SLOT ( saveSortingPreference ( int ) ) );
layout = new QVBoxLayout ( this, 2, 5 );
layout->addWidget ( firstline );
layout->addWidget ( listview );
}
void AccountDisplay::setTabs ( QWidget *newtab2, QTabWidget *newtabs )
{
tab2 = newtab2;
maintabs = newtabs;
}
void AccountDisplay::addAccount ()
{
// initialize local variables
int parentid = 0;
type = 0;
QString parentlist [ listview->childCount() + 1 ] [ 3 ] ;
// create new account window for entering data
NewAccount *newaccount = new NewAccount ( this );
int width = this->width();
newaccount->accountbox->setMaximumWidth ( ( int ) ( width * 0.5 ) );
newaccount->datebox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newaccount->childbox->setMaximumWidth ( ( int ) ( width * 0.5 ) );
newaccount->balancebox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newaccount->creditlimitbox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
// if there are no accounts, disable the child check box
if ( account->getNumberOfAccounts () == 0 )
newaccount->childcheckbox->setEnabled ( FALSE );
// if there are accounts, fill up the pulldown menu for
// selecting a parent account. We should only add those parents without transactions
else
{
int c = 0;
QListViewItemIterator it ( listview );
for ( ; it.current(); ++it )
{
int id = it.current()->text ( getIDColumn() ).toInt();
// iterate through accountdisplay listview and add parents with no transactions
// add this item to the list box only if it is a parent and has no transactions
if ( transfer->getNumberOfTransfers ( id ) == 0 && transaction->getNumberOfTransactions ( id ) == 0 && it.current()->parent() == 0 )
{
newaccount->childbox->insertItem ( it.current()->text ( 0 ) );
parentlist [ c ] [ 0 ] = it.current()->text ( 0 );
parentlist [ c ] [ 1 ] = it.current()->text ( getIDColumn() );
parentlist [ c ] [ 2 ] = QString::number ( c );
c++;
}
}
}
if ( preferences->getPreference ( 4 ) == 0 )
newaccount->currencybox->setEnabled ( FALSE );
// enter today's date in the date box as default
QDate today = QDate::currentDate ();
int defaultday = today.day();
int defaultmonth = today.month();
int defaultyear = today.year();
newaccount->startdate->setText ( preferences->getDate ( defaultyear, defaultmonth, defaultday ) );
//add account information if user pushes OK button
if ( newaccount->exec() == QDialog::Accepted )
{
if ( newaccount->childcheckbox->isChecked () == TRUE ) // set a parent id and type for a child account
{
// go through the parentlist we created and determine the parent accountid
// we can't use the name of the account because there may be two accounts
// with the same name. This function does it all by accountid
int counter;
for ( counter = 0; counter < listview->childCount() + 1; counter++ )
if ( ( parentlist [ counter ] [ 2 ].toInt() ) == newaccount->childbox->currentItem() )
{
parentid = parentlist [ counter ] [ 1 ].toInt();
break;
}
type = ( newaccount->accounttype->currentItem() ) + 6; // sets account ids for child accounts. See accountdisplay.h for types
}
else
{
parentid = -1;
type = newaccount->accounttype->currentItem(); // sets account ids for parent accounts
}
// add the new account
if ( newaccount->getDateEdited () == TRUE )
account->addAccount ( newaccount->accountname->text(), parentid, newaccount->accountbalance->text().toFloat(), type,
newaccount->getDescription(), newaccount->creditlimit->text().toFloat(), newaccount->getYear(),
newaccount->getMonth(), newaccount->getDay(), newaccount->accountbalance->text().toFloat(), newaccount->currencybox->currencybox->currentText() );
else
account->addAccount ( newaccount->accountname->text (), parentid, newaccount->accountbalance->text().toFloat(), type,
newaccount->getDescription(), newaccount->creditlimit->text().toFloat(), defaultyear,
defaultmonth, defaultday, newaccount->accountbalance->text().toFloat(), newaccount->currencybox->currencybox->currentText() );
if ( parentid != -1 )
account->changeParentAccountBalance ( parentid );
// redisplay accounts
// this function clears the account display first
account->displayAccounts ( listview );
setToggleButton();
}
maintabs->setTabEnabled ( tab2, FALSE );
}
void AccountDisplay::deleteAccount ()
{
if ( listview->selectedItem() == 0 )
QMessageBox::warning ( this, "QashMoney", "Please select an account\nto delete.");
else if ( listview->selectedItem()->parent() == 0 && listview->selectedItem()->childCount() != 0 )
QMessageBox::warning ( this, "QashMoney", "Can't delete parent accounts\nwith children");
else
{
QMessageBox mb ( "Delete Account", "This will delete all transactions\nand transfers for this account.", QMessageBox::Information, QMessageBox::Ok, QMessageBox::Cancel, QMessageBox::NoButton );
if ( mb.exec() == QMessageBox::Ok )
{
int accountid = listview->selectedItem()->text ( getIDColumn() ).toInt ();
int parentid = account->getParentAccountID ( accountid );
// delete all the transactions and transfers for the account
transaction->deleteAllTransactions ( accountid );
transfer->deleteAllTransfers ( accountid );
// delete the account
account->deleteAccount ( accountid );
// update account balances
if ( parentid != -1 )
account->changeParentAccountBalance ( parentid );
//redisplay accounts
account->displayAccounts ( listview );
//remove all the columns from the accountdisplay if there are not any accounts
if ( account->getNumberOfAccounts() == 0 )
{
int columns = listview->columns();
int counter;
for ( counter = 0; counter <= columns; counter++ )
listview->removeColumn ( 0 );
}
setToggleButton();
}
}
maintabs->setTabEnabled ( tab2, FALSE );
}
void AccountDisplay::setToggleButton ()
{
// iterate through account display and determine how many "transferable" accounts we have
// if there are less than two, disable the transfer button
QListViewItemIterator it ( listview );
int counter = 0;
for ( ; it.current(); ++it )
{
// add one to counter if we find a transferable account
if ( it.current()->parent() != 0 || ( it.current()->childCount() ) == 0 )
counter++;
}
if ( counter > 1 )
transferbutton->show();
else
transferbutton->hide();
}
void AccountDisplay::accountTransfer ( bool state )
{
if ( state == TRUE )
{
firstaccountid = -1;
secondaccountid = -1;
listview->clearSelection ();
listview->setMultiSelection ( TRUE );
disableParentsWithChildren ();
connect ( listview, SIGNAL ( clicked ( QListViewItem * ) ), this, SLOT ( getTransferAccounts ( QListViewItem * ) ) );
}
else
{
firstaccountid = -1;
secondaccountid = -1;
listview->clearSelection ();
listview->setMultiSelection ( FALSE );
enableAccounts ();
disconnect ( listview, SIGNAL ( clicked ( QListViewItem * ) ), this, SLOT ( getTransferAccounts ( QListViewItem * ) ) );
}
}
void AccountDisplay::getTransferAccounts ( QListViewItem * item )
{
if ( item->parent() != 0 || item->childCount() == 0 ) // only set an account for transfer if its a child or parent with no children
{
if ( firstaccountid == -1 )
firstaccountid = item->text ( getIDColumn() ).toInt(); // set first account if we've selected a valid account
else
if ( item->text ( getIDColumn() ).toInt() != firstaccountid ) // set the second account if its not equal to the first
secondaccountid = item->text ( getIDColumn() ).toInt();
}
// open transfer window if both accounts are set
if ( firstaccountid != -1 && secondaccountid != -1 )
{
// construct the transferdialog window
TransferDialog *td = new TransferDialog ( this, firstaccountid, secondaccountid );
// enter today's date in the date box as default
QDate today = QDate::currentDate ();
int defaultday = today.day();
int defaultmonth = today.month();
int defaultyear = today.year();
td->date->setText ( preferences->getDate ( defaultyear, defaultmonth, defaultday ) );
if ( td->exec() == QDialog::Accepted )
{
// set the cleared integer if the checkbox is checked
if ( td->clearedcheckbox->isChecked() == TRUE )
cleared = 1;
qDebug("Year from transferdialog = %i",td->getYear());
// add the transfer with a new date if its been edited or use the default date
if ( td->getDateEdited () == TRUE )
transfer->addTransfer ( firstaccountid, account->getParentAccountID ( firstaccountid ), secondaccountid, account->getParentAccountID ( secondaccountid ), td->getDay(), td->getMonth(), td->getYear(), td->amount->text().toFloat(), cleared );
else
transfer->addTransfer ( firstaccountid, account->getParentAccountID ( firstaccountid ), secondaccountid, account->getParentAccountID ( secondaccountid ), defaultday, defaultmonth, defaultyear, td->amount->text().toFloat(), cleared );
// update account balances of both accounts and parents if necessary
account->updateAccountBalance ( firstaccountid );
if ( account->getParentAccountID ( firstaccountid ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( firstaccountid ) );
account->updateAccountBalance ( secondaccountid );
if ( account->getParentAccountID ( secondaccountid ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( secondaccountid ) );
// redisplay accounts
account->displayAccounts ( listview );
}
else
{
firstaccountid = -1;
secondaccountid = -1;
listview->clearSelection ();
listview->setMultiSelection ( FALSE );
disconnect ( listview, SIGNAL ( clicked ( QListViewItem * ) ), this, SLOT ( getTransferAccounts ( QListViewItem * ) ) );
}
// reset the accounts display window
transferbutton->toggle(); // toggling this button with clear the window as well
// reenable all the accounts so the transaction tab will be properly set
enableAccounts ();
}
}
void AccountDisplay::disableParentsWithChildren ()
{
// iterate through accountdisplay listview and disable all the parents that have children
QListViewItemIterator it ( listview );
for ( ; it.current(); ++it )
{
if ( it.current()->parent() == 0 && it.current()->childCount() != 0 )
it.current()->setSelectable ( FALSE );
}
}
void AccountDisplay::enableAccounts ()
{
// iterate through accountdisplay listview and enable all accounts
QListViewItemIterator it ( listview );
for ( ; it.current(); ++it )
it.current()->setSelectable ( TRUE );
}
void AccountDisplay::saveColumnSize ( int column, int oldsize, int newsize )
{
switch ( column )
{
case 0:
if ( listview->columns() == 3 )
preferences->changeColumnPreference ( 1, newsize );
else
preferences->changeColumnPreference ( 10, newsize );
break;
case 1:
if ( listview->columns() == 3 )
preferences->changeColumnPreference ( 2, newsize );
else
preferences->changeColumnPreference ( 11, newsize );
break;
case 2:
preferences->changeColumnPreference ( 12, newsize );
break;
}
}
void AccountDisplay::saveSortingPreference ( int column )
{
preferences->changeSortingPreference ( 1, column );
}
int AccountDisplay::getIDColumn ()
{
int counter;
int columns = listview->columns();
for ( counter = 0; counter <= columns; counter++ )
if ( listview->header()->label ( counter ).length() == 0 )
return counter;
}
void AccountDisplay::editAccount ()
{
if ( listview->selectedItem() == 0 )
QMessageBox::warning ( this, "QashMoney", "Please select an account\nto edit.");
else
{
// set the accountid
int accountid = listview->selectedItem()->text ( getIDColumn() ).toInt();
//construct new dialog box
QDialog *editaccountwindow = new QDialog ( this, 0, TRUE );
editaccountwindow->setCaption ( "Edit Account" );
// construct the items which will go in the dialog bix
QLabel *namelabel = new QLabel ( "Account Name", editaccountwindow );
QLineEdit *accountname = new QLineEdit ( editaccountwindow );
QLabel *descriptionlabel = new QLabel ( "Account Description", editaccountwindow );
QLineEdit *accountdescription = new QLineEdit ( editaccountwindow );
Currency *currencybox = new Currency ( editaccountwindow );
QVBoxLayout *layout = new QVBoxLayout ( editaccountwindow, 5, 2 );
layout->addWidget ( namelabel );
layout->addWidget ( accountname );
layout->addWidget ( descriptionlabel );
layout->addWidget ( accountdescription );
layout->addWidget ( currencybox );
//set the account name
accountname->setText ( listview->selectedItem()->text ( 0 ) );
//set the account description
accountdescription->setText ( account->getAccountDescription ( accountid ) );
if ( preferences->getPreference ( 4 ) == 1 )
{
// get currency code for this account then iterate through the currency box
// to find the one we want
int count = currencybox->currencybox->count();
QString code = account->getCurrencyCode ( accountid );
for ( int counter = 0; count - 1; counter++ )
{
if ( QString::compare ( currencybox->currencybox->text ( counter ), code ) == 0 )
{
currencybox->currencybox->setCurrentItem ( counter );
break;
}
}
}
else
currencybox->setEnabled ( FALSE );
//execute the dialog box
int response = editaccountwindow->exec();
if ( response == 1 )
{
account->updateAccount ( accountname->text(), accountdescription->text(), currencybox->currencybox->currentText(), accountid );
account->displayAccounts ( listview );
// Try and select the same account that was just edited
QListViewItemIterator it ( listview );
for ( ; it.current(); ++it )
{
if ( it.current()->text ( 0 ) == accountname->text() )
{
listview->setSelected ( it.current(), TRUE );
return;
}
}
maintabs->setTabEnabled ( tab2, FALSE );
}
}
}
void AccountDisplay::setAccountExpanded ( QListViewItem *item )
{
int accountid = item->text ( getIDColumn() ).toInt();
account->setAccountExpanded ( 1, accountid );
}
void AccountDisplay::setAccountCollapsed ( QListViewItem *item )
{
int accountid = item->text ( getIDColumn() ).toInt();
account->setAccountExpanded ( 0, accountid );
}
diff --git a/noncore/apps/qashmoney/budgetdisplay.cpp b/noncore/apps/qashmoney/budgetdisplay.cpp
index 492595a..d4047bf 100755
--- a/noncore/apps/qashmoney/budgetdisplay.cpp
+++ b/noncore/apps/qashmoney/budgetdisplay.cpp
@@ -1,420 +1,417 @@
#include <qmessagebox.h>
#include <qheader.h>
-#include <qfont.h>
#include <sqlite.h>
#include "budgetdisplay.h"
#include "budget.h"
-#include "newaccount.h"
#include "datepicker.h"
-#include "preferences.h"
#include "transaction.h"
extern Preferences *preferences;
extern Budget *budget;
extern Transaction *transaction;
BudgetDisplay::BudgetDisplay ( QWidget *parent ) : QWidget ( parent )
{
QFont font = this->font();
font.setWeight ( QFont::Bold );
//set the default date to today
newDate = QDate::currentDate ();
year = newDate.year();
month = newDate.month();
day = newDate.day();
datelabel = preferences->getDate ( year, month );
setCaption ( "Budget" );
firstline = new QHBox ( this );
firstline->setSpacing ( 2 );
secondline = new QHBox ( this );
secondline->setSpacing ( 10 );
menu = new QMenuBar ( this );
menu->setFrameStyle ( QFrame::Box | QFrame::Sunken );
budgetmenu = new QPopupMenu ( this );
lineitemsmenu = new QPopupMenu ( this );
datemenu = new QPopupMenu ( this );
menu->insertItem ( "Budget", budgetmenu );
menu->insertItem ( "Line Item", lineitemsmenu );
menu->insertItem ( "Date", datemenu );
budgetmenu->insertItem ( "New", this, SLOT ( newBudget () ), 0, 1 );
budgetmenu->insertItem ( "Edit", this, SLOT ( editBudget () ), 0, 2 );
budgetmenu->insertItem ( "Delete", this, SLOT ( deleteBudget () ), 0, 3 );
lineitemsmenu->insertItem ( "New", this, SLOT ( newLineItem () ), 0, 1 );
lineitemsmenu->insertItem ( "Edit", this, SLOT ( editLineItem () ), 0, 2 );
lineitemsmenu->insertItem ( "Delete", this, SLOT ( deleteLineItem () ), 0, 3 );
datemenu->insertItem ( "Change", this, SLOT ( showCalendar() ) );
budgetbox = new QComboBox ( firstline );
connect ( budgetbox, SIGNAL ( activated ( int ) ), this, SLOT ( setCurrentBudget ( int ) ) );
budgetview = new QComboBox ( firstline );
budgetview->insertItem ( "Month" );
budgetview->insertItem ( "Year" );
connect ( budgetview, SIGNAL ( activated ( int ) ), this, SLOT ( setCurrentView ( int ) ) );
budgeted = new QLabel ( secondline );
budgeted->setFont ( font );
actual = new QLabel ( secondline );
actual->setFont ( font );
date = new QLabel ( secondline );
date->setFont ( font );
listview = new QListView ( this );
listview->setAllColumnsShowFocus ( TRUE );
listview->setShowSortIndicator ( TRUE );
listview->setRootIsDecorated ( TRUE );
listview->setMultiSelection ( FALSE );
listview->addColumn ( "Line Item", preferences->getColumnPreference ( 13 ) ); // column id 13
listview->addColumn ( "Budget", preferences->getColumnPreference ( 14 ) ); // column id 14
listview->addColumn ( "Actual", preferences->getColumnPreference ( 15 ) ); // column id 15
listview->addColumn ( "", 0 ); // line item ids
listview->setColumnWidthMode ( 0, QListView::Manual );
listview->setColumnWidthMode ( 1, QListView::Manual );
listview->setColumnWidthMode ( 2, QListView::Manual );
listview->setColumnAlignment ( 1, Qt::AlignRight );
listview->setColumnAlignment ( 2, Qt::AlignRight );
listview->setColumnWidthMode ( 3, QListView::Manual );
listview->header()->setTracking ( FALSE );
connect ( listview->header(), SIGNAL ( sizeChange ( int, int, int ) ), this, SLOT ( saveColumnSize ( int, int, int ) ) );
connect ( listview->header(), SIGNAL ( clicked ( int ) ), this, SLOT ( saveSortingPreference ( int ) ) );
// pull the column sorting preference from the preferences table, and configure the listview accordingly
int column = 0;
int direction = 0;
preferences->getSortingPreference ( 3, &column, &direction );
listview->setSorting ( column, direction );
displayBudgetNames();
layout = new QVBoxLayout ( this, 2, 2 );
layout->setMenuBar ( menu );
layout->addWidget ( firstline );
layout->addWidget ( secondline );
layout->addWidget ( listview );
}
void BudgetDisplay::deleteBudget ()
{
listview->clear();
transaction->clearBudgetIDs ( currentbudget );
budget->deleteBudget ( currentbudget );
if ( budgetbox->count() != 0 )
displayBudgetNames();
checkBudgets();
}
void BudgetDisplay::saveColumnSize ( int column, int oldsize, int newsize )
{
switch ( column )
{
case 0:
preferences->changeColumnPreference ( 13, newsize );
break;
case 1:
preferences->changeColumnPreference ( 14, newsize );
break;
case 2:
preferences->changeColumnPreference ( 15, newsize );
break;
}
}
void BudgetDisplay::saveSortingPreference ( int column )
{
preferences->changeSortingPreference ( 3, column );
}
int BudgetDisplay::getIDColumn ()
{
int counter;
int columns = listview->columns();
for ( counter = 0; counter <= columns; counter++ )
if ( listview->header()->label ( counter ).length() == 0 )
return counter;
}
void BudgetDisplay::newBudget ()
{
constructBudgetWindow();
int response = nb->exec();
if ( response == 1 )
{
// open a new budget object
int addedbudget = budget->addBudget ( budgetname->text(), 0, description->text(), currencybox->currencybox->currentText(), day, month, year, day, month, year, 0 );
transaction->clearBudgetIDs ( addedbudget );
displayBudgetNames();
}
checkBudgets();
}
void BudgetDisplay::constructBudgetWindow ()
{
//construct and format the new budget window
nb = new QDialog ( this, 0, TRUE );
nb->setCaption ( "Budget" );
QLabel *namelabel = new QLabel ( "Budget Name", nb );
budgetname = new QLineEdit ( nb );
QLabel *descriptionlabel = new QLabel ( "Description", nb );
description = new QLineEdit ( nb );
currencybox = new Currency ( nb );
QBoxLayout *layout = new QVBoxLayout ( nb, 2, 2 );
layout->addWidget ( namelabel );
layout->addWidget ( budgetname );
layout->addWidget ( descriptionlabel );
layout->addWidget ( description );
layout->addWidget ( currencybox );
}
void BudgetDisplay::displayBudgetNames ()
{
budgetbox->clear();
if ( budget->getNumberOfBudgets() != 0 )
{
ids = budget->getBudgetIDs();
for ( QStringList::Iterator it = ids->begin(); it != ids->end(); ++it )
{
QString flag = "/opt/QtPalmtop/pics/flags/";
flag.append ( budget->getCurrency ( (*it).toInt() ) );
flag.append ( ".png" );
budgetbox->insertItem ( QPixmap ( flag ), budget->getBudgetName ( (*it).toInt() ) );
}
setCurrentBudget ( 0 );
}
else
checkBudgets();
}
void BudgetDisplay::setCurrentBudget ( int index )
{
currentbudget = ( ids->operator[] ( index ).toInt() );
displayLineItems();
}
void BudgetDisplay::setCurrentView ( int index )
{
displayLineItems();
}
void BudgetDisplay::showCalendar ()
{
// create new calendar object and show it
DatePicker *dp = new DatePicker ( QDate ( year, month, day ) );
dp->daylabel->hide();
dp->daybox->hide();
if ( budgetview->currentItem() == 1 )
{
dp->monthlabel->hide();
dp->monthbox->hide();
}
dp->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
int response = dp->exec();
if ( response == 1 )
{
// Set date integers
year = dp->getYear();
if ( budgetview->currentItem() == 0 )
month = dp->getMonth();
else
month = newDate.month();
datelabel = preferences->getDate ( year, month );
displayLineItems();
}
}
void BudgetDisplay::newLineItem ()
{
//construct and format the new line item window
constructLineItemWindow ();
int response = newlineitem->exec();
if ( response == 1 )
{
float amount;
if ( lineitemtime->currentItem() == 0 )
amount = lineitemamount->text().toFloat();
else if ( lineitemtime->currentItem() == 1 )
amount = lineitemamount->text().toFloat() * 12;
else
amount = lineitemamount->text().toFloat() * 52;
int lineitemadded = budget->addLineItem ( currentbudget, lineitemname->text(), amount, lineitemtime->currentItem() );
transaction->clearBudgetIDs ( currentbudget, lineitemadded );
displayLineItems();
}
checkBudgets();
}
void BudgetDisplay::constructLineItemWindow ()
{
//construct and format the new budget window
newlineitem = new QDialog ( this, 0, TRUE );
newlineitem->setCaption ( "Line Item" );
QLabel *namelabel = new QLabel ( "Line Item Name", newlineitem );
lineitemname = new QLineEdit ( newlineitem );
QLabel *budgetamountlabel = new QLabel ( "Budget Amount", newlineitem );
lineitemamount = new QLineEdit ( newlineitem );
QLabel *lineitemtimelabel = new QLabel ( "Per:", newlineitem );
lineitemtime = new QComboBox ( newlineitem );
lineitemtime->insertItem ( "Year" ); // type 0
lineitemtime->insertItem ( "Month" ); // type 1
lineitemtime->insertItem ( "Week" ); // type 2
QBoxLayout *layout = new QVBoxLayout ( newlineitem, 2, 2 );
layout->addWidget ( namelabel );
layout->addWidget ( lineitemname );
layout->addWidget ( budgetamountlabel );
layout->addWidget ( lineitemamount );
layout->addWidget ( lineitemtimelabel );
layout->addWidget ( lineitemtime );
}
void BudgetDisplay::deleteLineItem ()
{
if ( listview->selectedItem() != 0 )
{
int lineitemid = listview->selectedItem()->text ( getIDColumn() ).toInt();
transaction->clearBudgetIDs ( currentbudget, lineitemid );
budget->deleteLineItem ( currentbudget, lineitemid );
displayBudgetNames();
}
else
QMessageBox::warning ( this, "QashMoney", "Please select a line item to delete." );
checkBudgets();
}
void BudgetDisplay::displayLineItems ()
{
listview->clear();
if ( budget->getNumberOfBudgets() != 0 )
{
QString budgettable = budgetbox->currentText();
budgettable.append ( QString::number ( currentbudget ) );
budget->displayLineItems ( currentbudget, listview, month, year, budgetview->currentItem() );
totalactual = transaction->getActualTotal ( currentbudget, year, month, budgetview->currentItem() );
totalbudget = budget->getBudgetTotal ( currentbudget, budgetview->currentItem() );
updateBudgetInformation();
}
}
void BudgetDisplay::checkBudgets ()
{
if ( budget->getNumberOfBudgets() == 0 )
{
budgetview->setEnabled ( FALSE );
budgetmenu->setItemEnabled ( 2, FALSE );
budgetmenu->setItemEnabled ( 3, FALSE );
lineitemsmenu->setItemEnabled ( 1, FALSE );
lineitemsmenu->setItemEnabled ( 2, FALSE );
lineitemsmenu->setItemEnabled ( 3, FALSE );
}
else
{
budgetview->setEnabled ( TRUE );
budgetmenu->setItemEnabled ( 2, TRUE );
budgetmenu->setItemEnabled ( 3, TRUE );
lineitemsmenu->setItemEnabled ( 1, TRUE );
lineitemsmenu->setItemEnabled ( 2, FALSE );
lineitemsmenu->setItemEnabled ( 3, FALSE );
if ( budget->getNumberOfLineItems ( currentbudget ) != 0 )
{
lineitemsmenu->setItemEnabled ( 2, TRUE );
lineitemsmenu->setItemEnabled ( 3, TRUE );
}
}
}
void BudgetDisplay::updateBudgetInformation ()
{
if ( budgetview->currentItem() == 0 )
{
datelabel = preferences->getDate ( year, month );
datelabel.prepend ( "Date: " );
date->setText ( datelabel );
}
else
date->setText ( QString::number ( year ) );
QString budget = "Budget: ";
budget.append ( totalbudget );
budgeted->setText ( budget );
QString actualamount = "Actual: ";
actualamount.append ( totalactual );
actual->setText ( actualamount );
}
void BudgetDisplay::editBudget ()
{
constructBudgetWindow();
//set the title
budgetname->setText ( budget->getBudgetName ( currentbudget ) );
//set the description
description->setText ( budget->getBudgetDescription ( currentbudget ) );
// retrieve the two character currency code then
// go through the currencty box and find the code
//set the currency box to that index number
int count = currencybox->currencybox->count();
QString code = budget->getCurrency ( currentbudget );
for ( int counter = 0; count - 1; counter++ )
{
if ( QString::compare (currencybox->currencybox->text ( counter ), code ) == 0 )
{
currencybox->currencybox->setCurrentItem ( counter );
break;
}
}
int response = nb->exec();
if ( response == 1 )
{
budget->updateBudget ( budgetname->text(), description->text(), currencybox->currencybox->currentText(), currentbudget );
displayBudgetNames();
}
}
void BudgetDisplay::editLineItem ()
{
if ( listview->selectedItem() != 0 )
{
constructLineItemWindow();
// set the line item name
lineitemname->setText ( listview->selectedItem()->text( 0 ) );
// set the line item time combobox
int lineitemtype = budget->getLineItemTime ( currentbudget, listview->selectedItem()->text ( 3 ).toInt() );
lineitemtime->setCurrentItem ( lineitemtype );
// set the line item amount
float amount = budget->getLineItemAmount ( currentbudget, listview->selectedItem()->text ( 3 ).toInt() );
if ( lineitemtype == 1 )
amount = amount / 12;
else if ( lineitemtype == 2 )
amount = amount / 52;
lineitemamount->setText ( QString::number ( amount ) );
int response = newlineitem->exec();
if ( response == 1 )
{
float amount;
if ( lineitemtime->currentItem() == 0 )
amount = lineitemamount->text().toFloat();
else if ( lineitemtime->currentItem() == 1 )
amount = lineitemamount->text().toFloat() * 12;
else
amount = lineitemamount->text().toFloat() * 52;
budget->updateLineItem ( lineitemname->text(), amount, lineitemtime->currentItem(), currentbudget, listview->selectedItem()->text ( 3 ).toInt() );
displayLineItems();
}
}
else
QMessageBox::warning ( this, "QashMoney", "Please select a line item to edit." );
}
diff --git a/noncore/apps/qashmoney/newaccount.cpp b/noncore/apps/qashmoney/newaccount.cpp
index 2ad8f60..7e57a18 100755
--- a/noncore/apps/qashmoney/newaccount.cpp
+++ b/noncore/apps/qashmoney/newaccount.cpp
@@ -1,209 +1,206 @@
#include "newaccount.h"
#include "calculator.h"
#include "datepicker.h"
-#include "transaction.h"
-#include "preferences.h"
-#include <qdatetime.h>
#include <qmultilineedit.h>
extern Preferences *preferences;
NewAccount::NewAccount ( QWidget *parent, const char *name, bool modal ) : QDialog ( parent, name, modal )
{
accountdescription = "";
dateedited = FALSE;
setCaption( tr( "Account" ) );
namelabel = new QLabel ( "Account Name", this );
accountbox = new QHBox ( this );
accountname = new QLineEdit ( accountbox );
descriptionbutton = new QPushButton ( accountbox );
descriptionbutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/info.png" ) );
datelabel = new QLabel ( "Date", this );
datebox = new QHBox ( this );
startdate = new QLineEdit ( datebox );
startdate->setDisabled ( TRUE );
datebutton = new QPushButton ( datebox );
datebutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/date.png" ) );
childcheckbox = new QCheckBox ( this );
childcheckbox->setText( tr ( "Child Account" ) );
childlabel = new QLabel ( "Child of", this );
childbox = new QComboBox ( FALSE, this );
hideChildPulldownMenu ();
balancelabel = new QLabel ( "Balance", this );
balancebox = new QHBox ( this );
accountbalance = new QLineEdit ( balancebox );
accountbalance->setText ( "0.00" );
balancecalculator = new QPushButton( balancebox );
balancecalculator->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/kcalc.png" ) );
creditlimitlabel = new QLabel ( "Credit Limit", this );
creditlimitbox = new QHBox ( this );
creditlimit = new QLineEdit ( creditlimitbox );
creditlimitbox->setEnabled ( FALSE );
creditlimitcalculator = new QPushButton( creditlimitbox );
creditlimitcalculator->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/kcalc.png" ) );
currencybox = new Currency ( this );
typelabel = new QLabel ( "Type", this );
accounttype = new QComboBox ( FALSE, this );
accounttype->insertItem( tr( "Bank" ) );
accounttype->insertItem( tr( "Cash" ) );
accounttype->insertItem( tr( "Credit Card" ) );
accounttype->insertItem( tr( "Equity" ) );
accounttype->insertItem( tr( "Asset" ) );
accounttype->insertItem( tr( "Liability" ) );
layout = new QGridLayout ( this, 7, 2, 4, 2 );
layout->addWidget ( namelabel , 0, 0, Qt::AlignLeft );
layout->addWidget ( accountbox, 1, 0, Qt::AlignLeft );
layout->addWidget ( datelabel, 2, 0, Qt::AlignLeft );
layout->addWidget ( datebox, 3, 0, Qt::AlignLeft );
layout->addWidget ( childcheckbox, 4, 0, Qt::AlignLeft );
layout->addWidget ( childlabel, 5, 0, Qt::AlignLeft );
layout->addWidget ( childbox, 6, 0, Qt::AlignLeft );
layout->addWidget ( balancelabel, 0, 1, Qt::AlignLeft );
layout->addWidget ( balancebox, 1, 1, Qt::AlignLeft );
layout->addWidget ( creditlimitlabel, 2, 1, Qt::AlignLeft );
layout->addWidget ( creditlimitbox, 3, 1, Qt::AlignLeft );
layout->addWidget ( currencybox, 4, 1, Qt::AlignLeft );
layout->addWidget ( typelabel, 5, 1, Qt::AlignLeft );
layout->addWidget ( accounttype, 6, 1, Qt::AlignLeft );
connect ( childcheckbox, SIGNAL ( clicked () ), this, SLOT ( showChildPulldownMenu() ) );
connect ( balancecalculator, SIGNAL ( released() ), this, SLOT ( showCalculator() ) );
connect ( creditlimitcalculator, SIGNAL ( released() ), this, SLOT ( showCreditLimitCalculator() ) );
connect ( accounttype, SIGNAL ( activated ( int ) ), this, SLOT ( activateCreditLimit ( int ) ) );
connect ( datebutton, SIGNAL ( released () ), this, SLOT ( showCalendar () ) );
connect ( descriptionbutton, SIGNAL ( released () ), this, SLOT ( addAccountDescription() ) );
}
NewAccount::~NewAccount ()
{
}
void NewAccount::showChildPulldownMenu ()
{
if ( childcheckbox->isChecked() == TRUE )
{
childlabel->setEnabled ( TRUE );
childbox->setEnabled ( TRUE );
}
else
hideChildPulldownMenu();
}
void NewAccount::hideChildPulldownMenu ()
{
childlabel->setEnabled ( FALSE );
childbox->setEnabled ( FALSE );
}
void NewAccount::showCalculator ()
{
Calculator *calculator = new Calculator ( this );
calculator->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
if ( calculator->exec () == QDialog::Accepted )
accountbalance->setText ( calculator->display->text() );
}
void NewAccount::showCreditLimitCalculator ()
{
Calculator *calculator = new Calculator ( this );
calculator->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
if ( calculator->exec () == QDialog::Accepted )
creditlimit->setText ( calculator->display->text() );
}
void NewAccount::activateCreditLimit ( int index )
{
if ( index == 2 || index == 5 )
creditlimitbox->setEnabled ( TRUE );
else
{
creditlimit->clear ();
creditlimitbox->setEnabled ( FALSE );
}
}
void NewAccount::showCalendar ()
{
QDate newDate = QDate::currentDate ();
DatePicker *dp = new DatePicker ( newDate );
dp->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
int response = dp->exec();
if ( response == QDialog::Accepted )
{
// Set date integers
year = dp->getYear();
month = dp->getMonth();
day = dp->getDay();
// Set dateedited to TRUE
// This tells the accountdisplay object that the user edited an account
// and did change the date
dateedited = TRUE;
// Display date with our selected format
startdate->setText ( preferences->getDate ( year, month, day ) );
}
}
bool NewAccount::getDateEdited ()
{
return dateedited;
}
int NewAccount::getDay ()
{
return day;
}
int NewAccount::getMonth ()
{
return month;
}
int NewAccount::getYear ()
{
return year;
}
QString NewAccount::getDescription ()
{
return accountdescription;
}
void NewAccount::setDescription ( QString description )
{
accountdescription = description;
}
void NewAccount::addAccountDescription ()
{
// Function for adding or editing an account description.
QDialog *description = new QDialog ( this, "description", TRUE );
description->setCaption ( "Notes" );
QMultiLineEdit *enter = new QMultiLineEdit ( description );
enter->setFixedSize ( ( int ) (this->width() * 0.75 ), ( int ) ( this->height() * 0.5 ) );
enter->setWrapColumnOrWidth ( ( int ) (this->width() * 0.75 ) );
enter->setWordWrap ( QMultiLineEdit::WidgetWidth );
if ( accountdescription != "(NULL)" )
enter->setText ( accountdescription );
if ( description->exec () == QDialog::Accepted )
accountdescription = enter->text ();
}
diff --git a/noncore/apps/qashmoney/newtransaction.cpp b/noncore/apps/qashmoney/newtransaction.cpp
index 630a8b8..5c78139 100755
--- a/noncore/apps/qashmoney/newtransaction.cpp
+++ b/noncore/apps/qashmoney/newtransaction.cpp
@@ -1,276 +1,274 @@
#include "newtransaction.h"
#include "calculator.h"
#include "datepicker.h"
-#include "memory.h"
#include "budget.h"
-#include <qdatetime.h>
#include <qmultilineedit.h>
extern Budget *budget;
extern Preferences *preferences;
NewTransaction::NewTransaction ( QWidget* parent ) : QDialog ( parent, 0, TRUE )
{
transactiondescription = "";
currentlineitem = -1;
currentbudget = -1;
dateedited = FALSE;
setCaption( tr( "Transaction" ) );
// START FIRST COLUMN
namelabel = new QLabel ( "Transaction", this );
transactionnamebox = new QHBox ( this );
transactionname = new QComboBox ( transactionnamebox );
transactionname->setEditable ( TRUE );
descriptionbutton = new QPushButton ( transactionnamebox );
descriptionbutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/info.png" ) );
connect ( descriptionbutton, SIGNAL ( released () ), this, SLOT ( addTransactionDescription() ) );
amountlabel = new QLabel ( "Amount", this );
transactionamountbox = new QHBox ( this );
transactionamount = new QLineEdit ( transactionamountbox );
transactionamount->setAlignment ( Qt::AlignRight );
transactionamount->setText ( "0.00" );
calculatorbutton = new QPushButton( transactionamountbox );
calculatorbutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/kcalc.png" ) );
connect ( calculatorbutton, SIGNAL ( released() ), this, SLOT ( showCalculator() ) );
datelabel = new QLabel ( "Date", this );
transactiondatebox = new QHBox ( this );
transactiondate = new QLineEdit ( transactiondatebox );
transactiondate->setAlignment ( Qt::AlignRight );
transactiondate->setDisabled ( TRUE );
datebutton = new QPushButton( transactiondatebox );
datebutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/date.png" ) );
connect ( datebutton, SIGNAL ( released () ), this, SLOT ( showCalendar () ) );
clearedcheckbox = new QCheckBox ( "Cleared", this );
depositbox = new QCheckBox ( "Credit", this );
// START SECOND COLUMN
numberlabel = new QLabel ( "Number", this );
transactionnumber = new QLineEdit ( this );
budgetlabel = new QLabel ( "Budget", this );
budgetbox = new QComboBox ( FALSE, this );
lineitemlabel = new QLabel ( "LineItem", this );
lineitembox = new QComboBox ( FALSE, this );
layout = new QGridLayout ( this, 7, 2, 2, 2 );
layout->addWidget ( namelabel, 0, 0, Qt::AlignLeft );
layout->addWidget ( transactionnamebox, 1, 0, Qt::AlignLeft );
layout->addWidget ( amountlabel, 2, 0, Qt::AlignLeft );
layout->addWidget ( transactionamountbox, 3, 0, Qt::AlignLeft );
layout->addWidget ( datelabel, 4, 0, Qt::AlignLeft );
layout->addWidget ( transactiondatebox, 5, 0, Qt::AlignLeft );
layout->addWidget ( clearedcheckbox, 6, 0, Qt::AlignLeft );
layout->addWidget ( numberlabel, 0, 1, Qt::AlignLeft );
layout->addWidget ( transactionnumber, 1, 1, Qt::AlignLeft );
layout->addWidget ( budgetlabel, 2, 1, Qt::AlignLeft );
layout->addWidget ( budgetbox, 3, 1, Qt::AlignLeft );
layout->addWidget ( lineitemlabel, 4, 1, Qt::AlignLeft );
layout->addWidget ( lineitembox, 5, 1, Qt::AlignLeft );
layout->addWidget ( depositbox, 6, 1, Qt::AlignLeft );
if ( budget->getNumberOfBudgets() != 0 )
{
budgetnameslist = budget->getBudgetNames();
budgetidslist = budget->getBudgetIDs();
budgetbox->insertStringList ( *budgetnameslist );
lineitemlabel->setEnabled ( FALSE );
lineitembox->setEnabled ( FALSE );
connect ( budgetbox, SIGNAL ( activated ( int ) ), this, SLOT ( setCurrentBudget ( int ) ) );
connect ( lineitembox, SIGNAL ( activated ( int ) ), this, SLOT ( setCurrentLineItem ( int ) ) );
}
else
{
budgetlabel->setEnabled ( FALSE );
budgetbox->setEnabled ( FALSE );
lineitemlabel->setEnabled ( FALSE );
lineitembox->setEnabled ( FALSE );
}
}
NewTransaction::~NewTransaction ()
{
}
void NewTransaction::showCalculator ()
{
Calculator *calculator = new Calculator ( this );
calculator->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
if ( calculator->exec () == QDialog::Accepted )
transactionamount->setText ( calculator->display->text() );
}
void NewTransaction::showCalendar ()
{
QDate newDate = QDate::currentDate ();
DatePicker *dp = new DatePicker ( newDate );
dp->setMaximumWidth ( ( int ) ( this->size().width() * 0.9 ) );
int response = dp->exec();
if ( response == QDialog::Accepted )
{
// Set date integers
year = dp->getYear();
month = dp->getMonth();
day = dp->getDay();
// Set dateedited to TRUE
// This tells the transactiondisplay object that the user edited an transaction
// and did change the date3
dateedited = TRUE;
// Display date with our selected format
transactiondate->setText ( preferences->getDate ( year, month, day ) );
}
}
bool NewTransaction::getDateEdited ()
{
return dateedited;
}
int NewTransaction::getDay ()
{
return day;
}
int NewTransaction::getMonth ()
{
return month;
}
int NewTransaction::getYear ()
{
return year;
}
QString NewTransaction::getDescription ()
{
return transactiondescription;
}
void NewTransaction::setDescription ( QString description )
{
transactiondescription = description;
}
void NewTransaction::addTransactionDescription ()
{
// Function for adding or editing an transaction description.
QDialog *description = new QDialog ( this, "description", TRUE );
description->setCaption ( "Notes" );
QMultiLineEdit *enter = new QMultiLineEdit ( description );
enter->setFixedSize ( ( int ) (this->width() * 0.75 ), ( int ) ( this->height() * 0.5 ) );
enter->setWrapColumnOrWidth ( ( int ) (this->width() * 0.75 ) );
enter->setWordWrap ( QMultiLineEdit::WidgetWidth );
if ( transactiondescription != "(NULL)" )
enter->setText ( transactiondescription );
if ( description->exec () == QDialog::Accepted )
transactiondescription = enter->text ();
}
int NewTransaction::getNameIndex ( QString name )
{
int counter;
int items = transactionname->count();
for ( counter = 0; ( items - 1 ); counter++ )
{
if ( name == transactionname->text ( counter ) )
{
return counter;
break;
}
}
return 0;
}
void NewTransaction::setCurrentBudget ( int index )
{
if ( index != 0 )
{
currentbudget = budgetidslist->operator[] ( index - 1 ).toInt();
lineitemslist = budget->getLineItems ( currentbudget );
lineitemidslist = budget->getLineItemIDs ( currentbudget );
lineitemlabel->setEnabled ( TRUE );
lineitembox->setEnabled ( TRUE );
lineitembox->clear();
lineitembox->insertStringList ( lineitemslist );
setCurrentLineItem ( 0 );
}
else
{
lineitembox->clear();
lineitemlabel->setEnabled ( FALSE );
lineitembox->setEnabled ( FALSE );
currentlineitem = -1;
currentbudget = -1;
}
}
void NewTransaction::setCurrentLineItem ( int index )
{
currentlineitem = ( lineitemidslist.operator[] ( index ).toInt() );
}
int NewTransaction::getCurrentBudget ()
{
return currentbudget;
}
int NewTransaction::getBudgetIndex ( int budgetid )
{
currentbudget = budgetid;
const QString budget = QString::number ( budgetid );
return budgetidslist->findIndex ( budget );
}
int NewTransaction::getLineItemIndex ( int lineitemid )
{
currentlineitem = lineitemid;
const QString lineitem = QString::number ( lineitemid );
return lineitemidslist.findIndex ( lineitem );
}
void NewTransaction::setLineItems ()
{
lineitemslist = budget->getLineItems ( currentbudget );
lineitemidslist = budget->getLineItemIDs ( currentbudget );
lineitemlabel->setEnabled ( TRUE );
lineitembox->setEnabled ( TRUE );
lineitembox->clear();
lineitembox->insertStringList ( lineitemslist );
}
int NewTransaction::getCurrentLineItem ()
{
return currentlineitem;
}
void NewTransaction::setComboBoxes ( int budgetid, int lineitemid )
{
const QString budgetname = QString::number ( budgetid );
budgetbox->setCurrentItem ( ( budgetidslist->findIndex ( budgetname ) ) );
currentbudget = budgetidslist->operator[] ( budgetbox->currentItem() - 1 ).toInt();
lineitemslist = budget->getLineItems ( currentbudget );
lineitemidslist = budget->getLineItemIDs ( currentbudget );
lineitemlabel->setEnabled ( TRUE );
lineitembox->setEnabled ( TRUE );
lineitembox->clear();
lineitembox->insertStringList ( lineitemslist );
const QString lineitem = QString::number ( lineitemid );
lineitembox->setCurrentItem ( lineitemidslist.findIndex ( lineitem ) );
currentlineitem = ( lineitemidslist.operator[] ( lineitembox->currentItem() ).toInt() );
}
diff --git a/noncore/apps/qashmoney/preferencedialogs.cpp b/noncore/apps/qashmoney/preferencedialogs.cpp
index d7c66d3..5408a5b 100755
--- a/noncore/apps/qashmoney/preferencedialogs.cpp
+++ b/noncore/apps/qashmoney/preferencedialogs.cpp
@@ -1,217 +1,216 @@
#include "preferencedialogs.h"
#include "preferences.h"
-#include <qlabel.h>
extern Preferences *preferences;
DatePreferences::DatePreferences ( QWidget* parent ) : QDialog ( parent, 0, TRUE )
{
setCaption( tr( "Date" ) );
QLabel *datelabel = new QLabel ( "Format", this );
dateformat = new QComboBox ( this );
dateformat->setEditable ( FALSE );
dateformat->insertItem ( "yyyymmdd" );
dateformat->insertItem ( "yymmdd" );
dateformat->insertItem ( "mmddyyyy" );
dateformat->insertItem ( "mmddyy" );
dateformat->insertItem ( "yyyyddmm" );
dateformat->insertItem ( "yyddmm" );
dateformat->insertItem ( "ddmmyyyy" );
dateformat->insertItem ( "ddmmyy" );
connect ( dateformat, SIGNAL ( activated ( int ) ), this, SLOT ( changeDateFormat ( int ) ) );
QLabel *dateseparatorlabel = new QLabel ( "Separator", this );
dateseparator = new QComboBox ( this );
dateseparator->insertItem ( "/" );
dateseparator->insertItem ( "-" );
dateseparator->insertItem ( "." );
connect ( dateseparator, SIGNAL ( activated ( int ) ), this, SLOT ( changeDateSeparator ( int ) ) );
defaults = new QPushButton ( QPixmap ( "/opt/QtPalmtop/pics/defaults.png" ), "Defaults", this );
connect ( defaults, SIGNAL ( released () ), this, SLOT ( setDefaultDatePreferences () ) );
dateformat->setCurrentItem ( ( preferences->getPreference ( 1 ) ) - 1 );
dateseparator->setCurrentItem ( ( preferences->getPreference ( 2 ) ) - 1 );
layout = new QVBoxLayout ( this, 2, 2 );
layout->addWidget ( datelabel );
layout->addWidget ( dateformat );
layout->addWidget ( dateseparatorlabel );
layout->addWidget ( dateseparator );
layout->insertSpacing ( 4, 5 );
layout->addWidget ( defaults );
}
DatePreferences::~DatePreferences ()
{
}
void DatePreferences::changeDateFormat ( int index )
{
index ++;
preferences->changePreference ( 1, index );
}
void DatePreferences::changeDateSeparator ( int index )
{
index ++;
preferences->changePreference ( 2, index );
}
void DatePreferences::setDefaultDatePreferences ()
{
preferences->setDefaultDatePreferences ();
dateformat->setCurrentItem ( ( preferences->getPreference ( 1 ) ) - 1 );
dateseparator->setCurrentItem ( ( preferences->getPreference ( 2 ) ) - 1 );
}
// START TRANSACTION PREFERENCES
TransactionPreferences::TransactionPreferences ( QWidget* parent ) : QDialog ( parent, 0, TRUE )
{
setCaption( tr ( "Transaction" ) );
showclearedtransactions = new QCheckBox ( this );
showclearedtransactions->setText ( "Show Cleared Transactions" );
limittransactionsbox = new QHBox ( this );
limittransactionsbox->setSpacing ( 2 );
limittransactionslabel = new QLabel ( "Show ", limittransactionsbox );
limittransactions = new QComboBox ( limittransactionsbox );
QLabel *limittransactionslabel2 = new QLabel ( "of cleared transactions. ", limittransactionsbox );
limittransactions->insertItem ( "14 days" );
limittransactions->insertItem ( "30 days" );
limittransactions->insertItem ( "90 days" );
limittransactions->insertItem ( "180 days" );
limittransactions->insertItem ( "365 days" );
limittransactions->insertItem ( "All" );
limittransactions->setCurrentItem ( preferences->getPreference ( 7 ) );
excludetransfers = new QCheckBox ( this );
excludetransfers->setText ( "Include Transfers In Limit View" );
if ( preferences->getPreference ( 3 ) == 1 )
showclearedtransactions->setChecked ( TRUE );
else
showclearedtransactions->setChecked ( FALSE );
if ( preferences->getPreference ( 6 ) == 1 )
excludetransfers->setChecked ( TRUE );
else
excludetransfers->setChecked ( FALSE );
defaults = new QPushButton ( QPixmap ( "/opt/QtPalmtop/pics/defaults.png" ), "Defaults", this );
connect ( defaults, SIGNAL ( released () ), this, SLOT ( setDefaultTransactionPreferences () ) );
layout = new QVBoxLayout ( this, 2, 2 );
layout->addWidget ( showclearedtransactions );
layout->addWidget ( limittransactionsbox );
layout->addWidget ( excludetransfers );
layout->insertSpacing ( 3, 5 );
layout->addWidget ( defaults );
connect ( showclearedtransactions, SIGNAL ( toggled ( bool ) ), this, SLOT ( changeShowClearedPreference ( bool ) ) );
connect ( excludetransfers, SIGNAL ( toggled ( bool ) ), this, SLOT ( changeExcludeTranfersPreference ( bool ) ) );
connect ( limittransactions, SIGNAL ( activated ( int ) ), this, SLOT ( changeLimitTransactionsPreference ( int ) ) );
}
TransactionPreferences::~TransactionPreferences ()
{
}
void TransactionPreferences::changeLimitTransactionsPreference ( int pref )
{
preferences->changePreference ( 7, pref );
}
void TransactionPreferences::changeShowClearedPreference ( bool state )
{
if ( state == TRUE )
preferences->changePreference ( 3, 1 );
else
preferences->changePreference ( 3, 0 );
}
void TransactionPreferences::changeExcludeTranfersPreference ( bool state )
{
if ( state == TRUE )
preferences->changePreference ( 6, 1 );
else
preferences->changePreference ( 6, 0 );
}
void TransactionPreferences::setDefaultTransactionPreferences ()
{
preferences->changePreference ( 3, 0 );
preferences->changePreference ( 6, 0 );
preferences->changePreference ( 7, 0 );
showclearedtransactions->setChecked ( FALSE );
limittransactions->setCurrentItem ( 0 );
}
// START ACCOUNT PREFERNCES
AccountPreferences::AccountPreferences ( QWidget* parent ) : QDialog ( parent, 0, TRUE )
{
setCaption( tr ( "Account" ) );
currencysupport = new QCheckBox ( this );
currencysupport->setText ( "Enable Currency Support" );
onetouch = new QCheckBox ( this );
onetouch->setText ( "One Touch Account Viewing" );
if ( preferences->getPreference ( 4 ) == 1 )
currencysupport->setChecked ( TRUE );
else
currencysupport->setChecked ( FALSE );
if ( preferences->getPreference ( 5 ) == 1 )
onetouch->setChecked ( TRUE );
else
onetouch->setChecked ( FALSE );
defaults = new QPushButton ( QPixmap ( "/opt/QtPalmtop/pics/defaults.png" ), "Defaults", this );
connect ( defaults, SIGNAL ( released () ), this, SLOT ( setDefaultAccountPreferences () ) );
layout = new QVBoxLayout ( this, 2, 2 );
layout->addWidget ( currencysupport );
layout->addWidget ( onetouch );
layout->insertSpacing ( 2, 5 );
layout->addWidget ( defaults );
connect ( currencysupport, SIGNAL ( toggled ( bool ) ), this, SLOT ( changeCurrencySupport ( bool ) ) );
connect ( onetouch, SIGNAL ( toggled ( bool ) ), this, SLOT ( changeOneTouchViewing ( bool ) ) );
}
AccountPreferences::~AccountPreferences ()
{
}
void AccountPreferences::changeCurrencySupport ( bool state )
{
if ( state == TRUE )
preferences->changePreference ( 4, 1 );
else
preferences->changePreference ( 4, 0 );
}
void AccountPreferences::changeOneTouchViewing ( bool state )
{
if ( state == TRUE )
preferences->changePreference ( 5, 1 );
else
preferences->changePreference ( 5, 0 );
}
void AccountPreferences::setDefaultAccountPreferences ()
{
preferences->changePreference ( 4, 0 );
preferences->changePreference ( 5, 0 );
currencysupport->setChecked ( FALSE );
onetouch->setChecked ( FALSE );
}
diff --git a/noncore/apps/qashmoney/transactiondisplay.cpp b/noncore/apps/qashmoney/transactiondisplay.cpp
index 78b8a00..474f11e 100755
--- a/noncore/apps/qashmoney/transactiondisplay.cpp
+++ b/noncore/apps/qashmoney/transactiondisplay.cpp
@@ -1,628 +1,625 @@
#include "transactiondisplay.h"
#include "newtransaction.h"
#include "account.h"
#include "budget.h"
#include "memory.h"
#include "transfer.h"
-#include "preferences.h"
#include "calculator.h"
#include "datepicker.h"
-#include <qdatetime.h>
#include <qmessagebox.h>
#include <qheader.h>
#include <qmultilineedit.h>
-#include <qdatetime.h>
extern Transaction *transaction;
extern Budget *budget;
extern Account *account;
extern Preferences *preferences;
extern Memory *memory;
extern Transfer *transfer;
TransactionDisplay::TransactionDisplay ( QWidget* parent ) : QWidget ( parent )
{
// set transactiondisplay variables;
accountid = 0;
children = TRUE;
firstline = new QHBox ( this );
firstline->setSpacing ( 2 );
newtransaction = new QPushButton ( firstline );
newtransaction->setPixmap ( QPixmap ("/opt/QtPalmtop/pics/new.png") );
connect ( newtransaction, SIGNAL ( released () ), this, SLOT ( addTransaction () ) );
edittransaction = new QPushButton ( firstline );
edittransaction->setPixmap( QPixmap ("/opt/QtPalmtop/pics/edit.png") );
connect ( edittransaction, SIGNAL ( released () ), this, SLOT ( checkListViewEdit () ) );
deletetransaction = new QPushButton ( firstline );
deletetransaction->setPixmap( QPixmap ( "/opt/QtPalmtop/pics/delete.png") );
connect ( deletetransaction, SIGNAL ( released () ), this, SLOT ( checkListViewDelete () ) );
toggletransaction = new QPushButton ( firstline );
toggletransaction->setPixmap( QPixmap ( "/opt/QtPalmtop/pics/redo.png") );
connect ( toggletransaction, SIGNAL ( released () ), this, SLOT ( checkListViewToggle () ) );
viewtransactionnotes = new QPushButton ( firstline );
viewtransactionnotes->setPixmap( QPixmap ( "/opt/QtPalmtop/pics/info.png") );
connect ( viewtransactionnotes, SIGNAL ( released () ), this, SLOT ( showTransactionNotes () ) );
secondline = new QHBox ( this );
secondline->setSpacing ( 5 );
name = new QLabel ( secondline );
balance = new QLabel ( secondline );
QLabel *limit = new QLabel ( "Limit", secondline );
limitbox = new QLineEdit ( secondline );
limitbox->setMinimumWidth ( ( int ) ( this->width() / 6 ) );
connect ( limitbox, SIGNAL ( textChanged ( const QString & ) ), this, SLOT ( limitDisplay ( const QString & ) ) );
listview = new QListView ( this );
listview->setAllColumnsShowFocus ( TRUE );
listview->setShowSortIndicator ( TRUE );
listview->header()->setTracking ( FALSE );
connect ( listview->header(), SIGNAL ( sizeChange ( int, int, int ) ), this, SLOT ( saveColumnSize ( int, int, int ) ) );
connect ( listview->header(), SIGNAL ( clicked ( int ) ), this, SLOT ( saveSortingPreference ( int ) ) );
layout = new QVBoxLayout ( this, 2, 2 );
layout->addWidget ( firstline );
layout->addWidget ( secondline );
layout->addWidget ( listview );
}
void TransactionDisplay::addTransaction ()
{
// create local variables
int cleared = -1;
// create new transaction window
NewTransaction *newtransaction = new NewTransaction ( this );
int width = this->size().width();
newtransaction->transactionname->setMaximumWidth ( ( int ) ( width * 0.45 ) );
newtransaction->transactionname->setMinimumWidth ( ( int ) ( width * 0.35 ) );
newtransaction->lineitembox->setMaximumWidth ( ( int ) ( width * 0.45 ) );
newtransaction->transactiondatebox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newtransaction->transactionamountbox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newtransaction->transactionnumber->setMaximumWidth ( ( int ) ( width * 0.25 ) );
// enter today's date in the date box as defaul
QDate today = QDate::currentDate ();
int defaultday = today.day();
int defaultmonth = today.month();
int defaultyear = today.year();
newtransaction->transactiondate->setText ( preferences->getDate ( defaultyear, defaultmonth, defaultday ) );
// add memory items to the transactionname combobox
memory->displayMemoryItems ( newtransaction->transactionname );
newtransaction->transactionname->insertItem ( "", 0 );
if ( newtransaction->exec () == QDialog::Accepted )
{
if ( newtransaction->clearedcheckbox->isChecked () == TRUE ) // set a parent id and type for a child transaction
cleared = 1;
else
cleared = 0;
float amount = newtransaction->transactionamount->text().toFloat();
if ( newtransaction->depositbox->isChecked() == FALSE )
amount = amount * -1;
// add the transaction name to the memory items
memory->addMemoryItem ( newtransaction->transactionname->currentText() );
// add the transaction
if ( newtransaction->getDateEdited () == TRUE )
transaction->addTransaction ( newtransaction->getDescription(), newtransaction->transactionname->currentText(), accountid, account->getParentAccountID ( accountid ),
newtransaction->transactionnumber->text().toInt(), newtransaction->getDay(), newtransaction->getMonth(), newtransaction->getYear(), amount, cleared, newtransaction->getCurrentBudget(),
newtransaction->getCurrentLineItem() );
else
transaction->addTransaction ( newtransaction->getDescription(), newtransaction->transactionname->currentText(), accountid, account->getParentAccountID ( accountid ),
newtransaction->transactionnumber->text().toInt(), defaultday, defaultmonth, defaultyear, amount, cleared, newtransaction->getCurrentBudget(), newtransaction->getCurrentLineItem() );
// redisplay transactions
listview->clear();
QString displaytext = "%";
displaytext.prepend ( limitbox->text() );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
// redisplay transfers
if ( transfer->getNumberOfTransfers() > 0 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
// add the transaction amount to the account it's associated with
// and update its parent account balance if necessary
account->updateAccountBalance ( accountid );
if ( account->getParentAccountID ( accountid ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( accountid ) );
// format then reset the account balance
redisplayAccountBalance ();
}
}
void TransactionDisplay::checkListViewEdit ()
{
if ( listview->selectedItem() == 0 )
QMessageBox::warning ( this, "QashMoney", "Please select a transaction\nto edit.");
else if ( listview->currentItem()->text ( getIDColumn() ).toInt() < 0 )
editTransfer ();
else
editTransaction();
}
void TransactionDisplay::showCalculator ()
{
Calculator *calculator = new Calculator ( this );
if ( calculator->exec () == QDialog::Accepted )
amount->setText ( calculator->display->text() );
}
void TransactionDisplay::showCalendar ()
{
QDate newDate = QDate::currentDate ();
DatePicker *dp = new DatePicker ( newDate );
if ( dp->exec () == QDialog::Accepted )
{
year = dp->getYear();
month = dp->getMonth();
day = dp->getDay();
date->setText ( preferences->getDate ( year, month, day ) );
}
}
void TransactionDisplay::editTransfer ()
{
transferid = listview->currentItem()->text ( getIDColumn() ).toInt();
fromaccount = transfer->getFromAccountID ( transferid );
toaccount = transfer->getToAccountID ( transferid );
year = transfer->getYear ( transferid );
month = transfer->getMonth ( transferid );
day = transfer->getDay ( transferid );
QDialog *editransfer = new QDialog ( this, "edittransfer", TRUE );
editransfer->setCaption ( "Transfer" );
QStringList accountnames = account->getAccountNames();
QStringList accountids = account->getAccountIDs();
QLabel *fromaccountlabel = new QLabel ( "From Account:", editransfer );
QFont f = this->font();
f.setWeight ( QFont::Bold );
fromaccountlabel->setFont ( f );
QComboBox *fromaccountbox = new QComboBox ( editransfer );
fromaccountbox->insertStringList ( accountnames );
fromaccountbox->setCurrentItem ( accountids.findIndex ( QString::number ( fromaccount ) ) );
QLabel *toaccountlabel = new QLabel ( "To Account:", editransfer );
toaccountlabel->setFont ( f );
QComboBox *toaccountbox = new QComboBox ( editransfer );
toaccountbox->insertStringList ( accountnames );
toaccountbox->setCurrentItem ( accountids.findIndex ( QString::number ( toaccount ) ) );
QLabel *datelabel = new QLabel ( "Date", editransfer );
QHBox *datebox = new QHBox ( editransfer );
datebox->setSpacing ( 2 );
date = new QLineEdit ( datebox );
date->setAlignment ( Qt::AlignRight );
date->setDisabled ( TRUE );
date->setText ( preferences->getDate ( year, month, day ) );
QPushButton *datebutton = new QPushButton ( datebox );
datebutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/date.png" ) );
connect ( datebutton, SIGNAL ( released () ), this, SLOT ( showCalendar () ) );
QLabel *amounttlabel = new QLabel ( "Amount", editransfer );
QHBox *amountbox = new QHBox ( editransfer );
amountbox->setSpacing ( 2 );
amount = new QLineEdit ( amountbox );
amount->setAlignment ( Qt::AlignRight );
amount->setText ( transfer->getAmount ( transferid ) );
QPushButton *calculatorbutton = new QPushButton( amountbox );
calculatorbutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/kcalc.png" ) );
connect ( calculatorbutton, SIGNAL ( released() ), this, SLOT ( showCalculator() ) );
QCheckBox *clearedcheckbox = new QCheckBox ( "Cleared", editransfer );
QBoxLayout *layout = new QVBoxLayout ( editransfer, 4, 2 );
layout->addWidget ( fromaccountlabel, Qt::AlignLeft );
layout->addWidget ( fromaccountbox, Qt::AlignLeft );
layout->addWidget ( toaccountlabel, Qt::AlignLeft );
layout->addWidget ( toaccountbox, Qt::AlignLeft );
layout->addSpacing ( 5 );
layout->addWidget ( datelabel, Qt::AlignLeft );
layout->addWidget ( datebox, Qt::AlignLeft );
layout->addWidget ( amounttlabel, Qt::AlignLeft );
layout->addWidget ( amountbox, Qt::AlignLeft );
layout->addWidget ( clearedcheckbox, Qt::AlignLeft );
if ( editransfer->exec() == QDialog::Accepted )
{
//get fromaccount
fromaccount = ( accountids.operator[] ( fromaccountbox->currentItem() ) ).toInt();
//get to account
toaccount = ( accountids.operator[] ( toaccountbox->currentItem() ) ).toInt();
//set cleared flag
int cleared = 0;
if ( clearedcheckbox->isChecked() == TRUE )
cleared = 1;
//update transfer
transfer->updateTransfer ( fromaccount, account->getParentAccountID ( fromaccount ), toaccount, account->getParentAccountID ( toaccount ),
day, month, year, amount->text().toFloat(), cleared, transferid );
account->updateAccountBalance ( fromaccount );
if ( account->getParentAccountID ( fromaccount ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( fromaccount ) );
updateAndDisplay ( toaccount );
}
}
void TransactionDisplay::editTransaction ()
{
int cleared;
// set the transaction id and budgetid
int transactionid = listview->currentItem()->text ( getIDColumn() ).toInt();
int budgetid = transaction->getBudgetID ( transactionid );
int lineitemid = transaction->getLineItemID ( transactionid );
// create edit transaction window
NewTransaction *newtransaction = new NewTransaction ( this );
int width = this->width();
newtransaction->transactionname->setMaximumWidth ( ( int ) ( width * 0.45 ) );
newtransaction->transactionname->setMinimumWidth ( ( int ) ( width * 0.35 ) );
newtransaction->lineitembox->setMaximumWidth ( ( int ) ( width * 0.45 ) );
newtransaction->transactiondatebox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newtransaction->transactionamountbox->setMaximumWidth ( ( int ) ( width * 0.4 ) );
newtransaction->transactionnumber->setMaximumWidth ( ( int ) ( width * 0.25 ) );
// enter the date in the date box
newtransaction->year = transaction->getYear ( transactionid );
newtransaction->month = transaction->getMonth ( transactionid );
newtransaction->day = transaction->getDay ( transactionid );
newtransaction->transactiondate->setText ( preferences->getDate ( newtransaction->year, newtransaction->month, newtransaction->day ) );
// set the description
newtransaction->setDescription ( transaction->getTransactionDescription ( transactionid ) );
// add memory items to the transactionname combobox
memory->displayMemoryItems ( newtransaction->transactionname );
// add correct transaction name
newtransaction->transactionname->setEditText ( transaction->getPayee ( transactionid ) );
// add transaction number
newtransaction->transactionnumber->setText ( transaction->getNumber ( transactionid ) );
// add transaction amount
newtransaction->transactionamount->setText ( transaction->getAbsoluteAmount ( transactionid ) );
// check for and set the correct budget
if ( budgetid >= 1 ) // only do it if this transaction has a budget and line item
{
newtransaction->budgetbox->setCurrentItem ( newtransaction->getBudgetIndex ( budgetid ) + 1 );
if ( lineitemid >= 1 )
{
newtransaction->setLineItems ();
newtransaction->lineitembox->setCurrentItem ( newtransaction->getLineItemIndex ( lineitemid ) );
}
else
{
newtransaction->lineitemlabel->setEnabled ( FALSE );
newtransaction->lineitembox->setEnabled ( FALSE );
}
}
else
{
newtransaction->lineitemlabel->setEnabled ( FALSE );
newtransaction->lineitembox->setEnabled ( FALSE );
}
// check cleared checkbox if necessary
if ( transaction->getCleared ( transactionid ) == 1 )
newtransaction->clearedcheckbox->setChecked ( TRUE );
// check deposit box if necessary
if ( transaction->getAmount ( transactionid ).toFloat() > 0 )
newtransaction->depositbox->setChecked ( TRUE );
if ( newtransaction->exec () == QDialog::Accepted )
{
if ( newtransaction->clearedcheckbox->isChecked () == TRUE )
cleared = 1;
else
cleared = 0;
float amount = newtransaction->transactionamount->text().toFloat();
if ( newtransaction->depositbox->isChecked() == FALSE )
amount = amount * -1;
// add the transaction name to the memory items
memory->addMemoryItem ( newtransaction->transactionname->currentText() );
// update the transaction
transaction->updateTransaction ( newtransaction->getDescription(), newtransaction->transactionname->currentText(), newtransaction->transactionnumber->text().toInt(),
newtransaction->getDay(), newtransaction->getMonth(), newtransaction->getYear(),
amount, cleared, newtransaction->getCurrentBudget(), newtransaction->getCurrentLineItem(), transactionid );
updateAndDisplay ( transaction->getAccountID ( transactionid ) );
}
}
void TransactionDisplay::updateAndDisplay ( int id )
{
// redisplay transactions
listview->clear();
QString displaytext = "%";
displaytext.prepend ( limitbox->text() );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
// redisplay transfers
if ( transfer->getNumberOfTransfers() > 0 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
// add the transaction amount to the account it's associated with
// and update its parent account balance if necessary
account->updateAccountBalance ( id );
if ( account->getParentAccountID ( id ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( id ) );
// format then reset the account balance
redisplayAccountBalance ();
}
void TransactionDisplay::checkListViewDelete ()
{
if ( listview->selectedItem() == 0 )
QMessageBox::warning ( this, "QashMoney", "Please select a transaction to\ndelete.");
else
deleteTransaction ();
}
void TransactionDisplay::deleteTransaction ()
{
int transactionid = listview->currentItem()->text ( getIDColumn() ).toInt();
if ( transactionid > 0 ) // takes care of deleting transactions
{
// check if we are viewing child transactions through a parent
// in that case we will have to update balances for the parent
// which is represented by accountid and the child account
// which will be represented by childaccountid
int childaccountid = -1;
if ( listview->columns() == 5 )
childaccountid = transaction->getAccountID ( transactionid );
transaction->deleteTransaction ( transactionid );
listview->clear();
QString displaytext = "%";
displaytext.prepend ( limitbox->text() );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
if ( transfer->getNumberOfTransfers() > 0 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
// if we are viewing different child accounts through the parent account
// ie if there are five columns and the parentid is -1
// update the accountid ( which is the parent ) and update the child account
// balance. Get its accountid from the transactionid
account->updateAccountBalance ( accountid ); // will update either a parent or child
if ( account->getParentAccountID ( accountid ) != -1 ) // update its parent if there is one
account->changeParentAccountBalance ( account->getParentAccountID ( accountid ) );
if ( childaccountid != -1 ) // we've set childaccountid
account->updateAccountBalance ( childaccountid );
// format then reset the account balance
redisplayAccountBalance ();
}
else // takes care of deleting transfers
{
// get the accountids before we delete the transfer
int fromaccountid = transfer->getFromAccountID ( transactionid );
int toaccountid = transfer->getToAccountID ( transactionid );
// delete the transfer and redisplay transactions
transfer->deleteTransfer ( transactionid );
listview->clear();
QString displaytext = "%";
displaytext.prepend ( limitbox->text() );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
if ( transfer->getNumberOfTransfers() > 0 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
// for the from account
account->updateAccountBalance ( fromaccountid );
if ( account->getParentAccountID ( fromaccountid ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( fromaccountid ) );
// for the to account
account->updateAccountBalance ( toaccountid );
if ( account->getParentAccountID ( toaccountid ) != -1 )
account->changeParentAccountBalance ( account->getParentAccountID ( toaccountid ) );
// format then reset the account balance
redisplayAccountBalance ();
}
}
void TransactionDisplay::checkListViewToggle ()
{
if ( listview->selectedItem() == 0 )
QMessageBox::warning ( this, "QashMoney", "Please select a transaction to\nclear or reset.");
else
toggleTransaction ();
}
void TransactionDisplay::toggleTransaction ()
{
//get the transaction of the selected transaction to determine if its a transaction or transfer
int transactionid = listview->currentItem()->text ( getIDColumn() ).toInt();
if ( transactionid > 0 ) // if this is a transaction
{
if ( transaction->getCleared ( transactionid ) == 0 )
transaction->setCleared ( transactionid, 1 );
else
transaction->setCleared ( transactionid, 0 );
}
else
{
if ( transfer->getCleared ( transactionid ) == 0 )
transfer->setCleared ( transactionid, 1 );
else
transfer->setCleared ( transactionid, 0 );
}
listview->clear();
QString displaytext = "%";
displaytext.prepend ( limitbox->text() );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
if ( transfer->getNumberOfTransfers() != 0 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
}
void TransactionDisplay::redisplayAccountBalance ()
{
QString accountbalance = account->getAccountBalance ( accountid );
balance->setText ( accountbalance );
}
void TransactionDisplay::setChildren ( bool c )
{
children = c;
}
void TransactionDisplay::setAccountID ( int id )
{
accountid = id;
}
ColorListItem::ColorListItem ( QListView *parent ) : QListViewItem ( parent )
{
}
ColorListItem::ColorListItem ( QListView *parent, QString label1, QString label2, QString label3, QString label4 )
: QListViewItem ( parent, label1, label2, label3, label4 )
{
}
ColorListItem::ColorListItem ( QListView *parent, QString label1, QString label2, QString label3, QString label4, QString label5 )
: QListViewItem ( parent, label1, label2, label3, label4, label5 )
{
}
void ColorListItem::paintCell ( QPainter *p, const QColorGroup &cg, int column, int width, int alignment )
{
QColorGroup _cg ( cg );
_cg.setColor ( QColorGroup::Text, Qt::red );
QListViewItem::paintCell ( p, _cg, column, width, alignment );
}
void TransactionDisplay::saveColumnSize ( int column, int oldsize, int newsize )
{
if ( listview->columns() == 4 )
preferences->changeColumnPreference ( column + 3, newsize );
else if ( listview->columns() == 5 && column != 4 )
preferences->changeColumnPreference ( column + 6, newsize );
else
preferences->changeColumnPreference ( 9, newsize );
}
void TransactionDisplay::saveSortingPreference ( int column )
{
preferences->changeSortingPreference ( 2, column );
}
void TransactionDisplay::limitDisplay ( const QString &text )
{
listview->clear ();
QString displaytext = "%";
displaytext.prepend ( text );
setTransactionDisplayDate ();
if ( transaction->getNumberOfTransactions() > 0 )
transaction->displayTransactions ( listview, accountid, children, displaytext, displaydate );
if ( displaytext.length() == 1 || preferences->getPreference ( 6 ) == 1 )
transfer->displayTransfers ( listview, accountid, children, displaydate );
}
int TransactionDisplay::getIDColumn ()
{
int counter;
int columns = listview->columns();
for ( counter = 0; counter <= columns; counter++ )
if ( listview->header()->label ( counter ).length() == 0 )
return counter;
}
void TransactionDisplay::showTransactionNotes ()
{
if ( listview->selectedItem() == 0 || listview->currentItem()->text ( getIDColumn() ).toInt() < 0 )
QMessageBox::warning ( this, "QashMoney", "Please select a valid\ntransaction to view notes.");
else
{
int transactionid = listview->selectedItem()->text ( getIDColumn() ).toInt ();
QDialog *description = new QDialog ( this, "description", TRUE );
description->setCaption ( "Notes" );
QMultiLineEdit *notes = new QMultiLineEdit ( description );
notes->setFixedSize ( ( int ) (this->width() * 0.75 ), ( int ) ( this->height() * 0.5 ) );
notes->setWrapColumnOrWidth ( ( int ) (this->width() * 0.75 ) );
notes->setWordWrap ( QMultiLineEdit::WidgetWidth );
notes->setEnabled ( FALSE );
notes->setText ( transaction->getTransactionDescription ( transactionid ) );
description->show();
}
}
void TransactionDisplay::setTransactionDisplayDate ()
{
// determine how many days of transactions to show
int limittype = preferences->getPreference ( 7 );
if ( limittype != 5 ) // set today's date if we are not showing all transactions
{
QDate today = QDate::currentDate ();
switch ( limittype ) // if we are not showing all transactions
{
case 0: // viewing two weeks
displaydate = today.addDays ( -14 );
break;
case 1: // viewing one month
displaydate = today.addDays ( -30 );
break;
case 2: // three months
displaydate = today.addDays ( -90 );
break;
case 3: // six months
displaydate = today.addDays ( -180 );
break;
case 4: // one year
displaydate = today.addDays ( -365 );
break;
}
}
else
displaydate = QDate ( 1900, 1, 1 );
}
diff --git a/noncore/apps/qashmoney/transferdialog.cpp b/noncore/apps/qashmoney/transferdialog.cpp
index f85c740..558abec 100755
--- a/noncore/apps/qashmoney/transferdialog.cpp
+++ b/noncore/apps/qashmoney/transferdialog.cpp
@@ -1,114 +1,112 @@
#include "transferdialog.h"
#include "datepicker.h"
#include "calculator.h"
-#include <qdatetime.h>
-#include <qfont.h>
extern Preferences *preferences;
extern Account *account;
TransferDialog::TransferDialog ( QWidget *parent, int fromaccountid, int toaccountid ) : QDialog ( parent, 0, TRUE )
{
dateedited = FALSE;
setCaption ( "Transfer" );
fromaccountlabel = new QLabel ( "From account:", this );
QFont f = this->font();
f.setWeight ( QFont::Bold );
fromaccountlabel->setFont ( f );
fromaccount = new QLabel ( account->getAccountName ( fromaccountid ), this );
toaccountlabel = new QLabel ( "To Account:", this );
toaccountlabel->setFont ( f );
toaccount = new QLabel ( account->getAccountName ( toaccountid ), this );
datelabel = new QLabel ( "Date", this );
datebox = new QHBox ( this );
datebox->setSpacing ( 2 );
date = new QLineEdit ( datebox );
date->setAlignment ( Qt::AlignRight );
date->setDisabled ( TRUE );
datebutton = new QPushButton ( datebox );
datebutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/date.png" ) );
connect ( datebutton, SIGNAL ( released () ), this, SLOT ( showCalendar () ) );
amounttlabel = new QLabel ( "Amount", this );
amountbox = new QHBox ( this );
amountbox->setSpacing ( 2 );
amount = new QLineEdit ( amountbox );
amount->setAlignment ( Qt::AlignRight );
calculatorbutton = new QPushButton( amountbox );
calculatorbutton->setPixmap ( QPixmap ( "/opt/QtPalmtop/pics/kcalc.png" ) );
connect ( calculatorbutton, SIGNAL ( released() ), this, SLOT ( showCalculator() ) );
clearedcheckbox = new QCheckBox ( "Cleared", this );
layout = new QVBoxLayout ( this, 4, 2 );
layout->addWidget ( fromaccountlabel, Qt::AlignLeft );
layout->addWidget ( fromaccount, Qt::AlignLeft );
layout->addWidget ( toaccountlabel, Qt::AlignLeft );
layout->addWidget ( toaccount, Qt::AlignLeft );
layout->addSpacing ( 5 );
layout->addWidget ( datelabel, Qt::AlignLeft );
layout->addWidget ( datebox, Qt::AlignLeft );
layout->addWidget ( amounttlabel, Qt::AlignLeft );
layout->addWidget ( amountbox, Qt::AlignLeft );
layout->addWidget ( clearedcheckbox, Qt::AlignLeft );
}
bool TransferDialog::getDateEdited ()
{
return dateedited;
}
void TransferDialog::showCalendar ()
{
QDate newDate = QDate::currentDate ();
DatePicker *dp = new DatePicker ( newDate );
if ( dp->exec () == QDialog::Accepted )
{
// Set date integers
year = dp->getYear();
month = dp->getMonth();
day = dp->getDay();
// Set dateedited to TRUE
// This tells the accountdisplay object that the user edited an account
// and did change the date
dateedited = TRUE;
// Display date with our selected format
date->setText ( preferences->getDate ( year, month, day ) );
}
}
int TransferDialog::getDay ()
{
return day;
}
int TransferDialog::getMonth ()
{
return month;
}
int TransferDialog::getYear ()
{
return year;
}
void TransferDialog::showCalculator ()
{
Calculator *calculator = new Calculator ( this );
if ( calculator->exec () == QDialog::Accepted )
amount->setText ( calculator->display->text() );
}
diff --git a/noncore/apps/tableviewer/tableviewer.cpp b/noncore/apps/tableviewer/tableviewer.cpp
index 207172d..f35dfcd 100644
--- a/noncore/apps/tableviewer/tableviewer.cpp
+++ b/noncore/apps/tableviewer/tableviewer.cpp
@@ -1,481 +1,480 @@
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qtopia Environment.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
/* local includes */
#include "tableviewer.h"
#include "ui/tvbrowseview.h"
#include "ui/tvfilterview.h"
#include "ui/tvlistview.h"
#include "ui/tveditview.h"
#include "ui/tvkeyedit.h"
#include "db/datacache.h"
/* QPE includes */
#include <qpe/fileselector.h>
#include <qpe/resource.h>
#include <qpe/qpetoolbar.h>
/* QTE includes */
#include <qmenubar.h>
-#include <qpe/qpetoolbar.h>
#include <qpopupmenu.h>
#include <qapplication.h>
#include <qwidgetstack.h>
#include <qlayout.h>
#include <qbuffer.h>
/*!
\class TableViewerWindow
\brief The main window widget of the application
This is the main widget of the table viewer application.
It is the co-ordination point.
*/
/*!
Constructs a new TableViewerWindow
*/
TableViewerWindow::TableViewerWindow(QWidget *parent, const char *name, WFlags f)
: QMainWindow(parent, name, f)
{
setCaption(tr("Table Viewer"));
/* Build data */
ds = new DBStore();
doc.setType("text/x-xml-tableviewer");
doc.setName("table");
dirty = FALSE;
ts.current_column = 0;
ts.kRep = ds->getKeys();
/* build menus */
menu = new QMenuBar(this, 0);
QPopupMenu *file_menu = new QPopupMenu;
file_menu->insertItem("New", this, SLOT(newDocument()));
file_menu->insertItem("Open", this, SLOT(selectDocument()));
file_menu->insertSeparator();
file_menu->insertItem("Properties");
/* later will want to set this up to clean up first via this, SLOT(quit) */
menu->insertItem("Document", file_menu);
QPopupMenu *edit_menu = new QPopupMenu;
edit_menu->insertItem("Edit Item", this, SLOT(editItemSlot()));
edit_menu->insertItem("Edit Keys", this, SLOT(editKeysSlot()));
edit_menu->insertItem("Edit filters", this, SLOT(filterViewSlot()));
menu->insertItem("Edit", edit_menu);
QPopupMenu *view_menu = new QPopupMenu;
view_menu->insertItem("Browse View", this, SLOT(browseViewSlot()));
view_menu->insertItem("List View", this, SLOT(listViewSlot()));
menu->insertItem("View", view_menu);
QVBoxLayout *main_layout = new QVBoxLayout;
/* Build tool bar */
navigation = new QToolBar(this, "navigation");
QToolButton *newItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("new")), "New Item", QString::null,
this, SLOT(newItemSlot()), navigation, "New Item");
QToolButton *editItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("edit")), "Edit Item", QString::null,
this, SLOT(editItemSlot()), navigation, "Edit Item");
QToolButton *deleteItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("trash")), "Delete Item",
QString::null, this,
SLOT(deleteItemSlot()), navigation, "Delete Item");
navigation->addSeparator();
QToolButton *firstItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("fastback")), "First Item",
QString::null, this,
SLOT(firstItem()), navigation, "First Item");
QToolButton *previousItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("back")), "Previous Item",
QString::null, this,
SLOT(previousItem()), navigation, "Previous Item");
QToolButton *nextItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("forward")), "Next Item",
QString::null, this,
SLOT(nextItem()), navigation, "Next Item");
QToolButton *lastItemButton = new QToolButton(
QIconSet(Resource::loadPixmap("fastforward")), "Last Item",
QString::null, this,
SLOT(lastItem()), navigation, "Last Item");
navigation->addSeparator();
QToolButton *browseButton = new QToolButton(
QIconSet(Resource::loadPixmap("day")), "View Single Item",
QString::null, this,
SLOT(browseViewSlot()), navigation, "View Single Item");
QToolButton *listButton = new QToolButton(
QIconSet(Resource::loadPixmap("month")), "View Multiple Items",
QString::null, this,
SLOT(listViewSlot()), navigation, "View Multiple Items");
setToolBarsMovable(FALSE);
setToolBarsMovable(FALSE);
setToolBarsMovable(FALSE);
/* Build widgets */
browseView = new TVBrowseView(&ts, this, 0);
listView = new TVListView(&ts, this, 0);
filterView = new TVFilterView(&ts, this, 0);
fileSelector = new FileSelector("text/csv;text/x-xml-tableviewer",
this, "fileselector");
fileSelector->setNewVisible(FALSE);
fileSelector->setCloseVisible(FALSE);
cw = new QWidgetStack(this, 0);
cw->addWidget(listView, ListState);
cw->addWidget(browseView, BrowseState);
cw->addWidget(filterView, FilterState);
cw->addWidget(fileSelector, FileState);
current_view = FileState;
cw->raiseWidget(current_view);
fileSelector->reread();
connect(browseView, SIGNAL(searchOnKey(int, TVVariant)),
this, SLOT(searchOnKey(int, TVVariant)));
connect(browseView, SIGNAL(sortChanged(int)),
this, SLOT(setPrimaryKey(int)));
connect(fileSelector, SIGNAL(closeMe()), this, SLOT(browseViewSlot()));
connect(fileSelector, SIGNAL(fileSelected(const DocLnk &)),
this, SLOT(openDocument(const DocLnk &)));
main_layout->addWidget(menu);
main_layout->addWidget(cw);
setCentralWidget(cw);
}
/*!
Destroys the TableViewerWindow
*/
TableViewerWindow::~TableViewerWindow()
{
if(dirty)
saveDocument();
}
/*!
Opens a file dialog and loads the file specified by the dialog
*/
void TableViewerWindow::selectDocument()
{
if(dirty)
saveDocument();
current_view = FileState;
cw->raiseWidget(current_view);
fileSelector->reread();
}
void TableViewerWindow::saveDocument()
{
if(!dirty)
return;
FileManager fm;
QIODevice *dev = fm.saveFile(doc);
if(!ds->saveSource(dev, doc.type())){
qWarning("Save unsuccessful");
return;
}
dev->close();
dirty = FALSE;
}
void TableViewerWindow::newDocument()
{
DocLnk nf;
nf.setType("text/x-xml-tableviewer");
nf.setName("table");
delete ds;
ds = new DBStore();
ts.current_column = 0;
ts.kRep = ds->getKeys();
browseView->reset();
listView->reset();
filterView->reset();
doc = nf;
dirty = FALSE;
current_view = BrowseState;
cw->raiseWidget(current_view);
/* now set up for editing the keys */
ts.kRep->addKey("key", TVVariant::String);
editKeysSlot();
}
void TableViewerWindow::setDocument(const QString &f)
{
openDocument(DocLnk(f, TRUE));
}
void TableViewerWindow::openDocument(const DocLnk &f)
{
if (!f.isValid())
return;
FileManager fm;
QIODevice *dev = fm.openFile(f);
doc = f;
if(ds->openSource(dev, doc.type())) {
DataElem *d;
browseView->reset();
listView->reset();
filterView->reset();
current_view = BrowseState;
cw->raiseWidget(current_view);
/* set up new table state and ensure sub widgets have a reference */
ts.current_column = 0;
ts.kRep = ds->getKeys();
browseView->rebuildKeys();
listView->rebuildKeys();
filterView->rebuildKeys();
ds->first();
/* set up the list view */
listView->clearItems();
do {
d = ds->getCurrentData();
if(d)
listView->addItem(d);
} while(ds->next());
/* Set up browse view, Will be based of structure of listView */
listView->first();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
listView->rebuildData();
QString scratch = "Table Viewer";/* later take from constant */
scratch += " - ";
scratch += ds->getName();
setCaption(tr(scratch));
dirty = FALSE;
} else {
qWarning(tr("could not load Document"));
}
dev->close();
}
/*!
Moves to the first item of the current table
*/
void TableViewerWindow::firstItem()
{
listView->first();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
}
/*!
Moves to the lat item of the current table
*/
void TableViewerWindow::lastItem()
{
listView->last();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
}
/*!
Moves to the next item of the current table
*/
void TableViewerWindow::nextItem()
{
listView->next();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
}
/*!
Moves to the previous item of the current table
*/
void TableViewerWindow::previousItem()
{
listView->previous();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
}
/*!
Raises the List View. This is a mode change for the application.
*/
void TableViewerWindow::listViewSlot()
{
if(current_view == FilterState)
applyFilter();
current_view = ListState;
cw->raiseWidget(current_view);
}
void TableViewerWindow::applyFilter()
{
DataElem *d;
listView->clearItems();
ds->first();
do {
d = ds->getCurrentData();
if(d)
if(filterView->passesFilter(d))
listView->addItem(d);
} while(ds->next());
listView->first();
listView->rebuildData();
}
/*!
Raises the Browse View. This is a mode change for the application.
*/
void TableViewerWindow::browseViewSlot()
{
if(current_view == FilterState)
applyFilter();
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
current_view = BrowseState;
cw->raiseWidget(current_view);
}
/*!
Raises the List View. This is a mode change for the application.
*/
void TableViewerWindow::filterViewSlot()
{
current_view = FilterState;
cw->raiseWidget(current_view);
}
void TableViewerWindow::editItemSlot()
{
if(TVEditView::openEditItemDialog(&ts, ts.current_elem, this)) {
listView->rebuildData();
browseView->rebuildData();
dirty = TRUE;
}
}
void TableViewerWindow::newItemSlot()
{
DataElem *d = new DataElem(ds);
if (TVEditView::openEditItemDialog(&ts, d, this)) {
ds->addItem(d);
ts.current_elem = d;
applyFilter();
listView->rebuildData();
browseView->rebuildData();
dirty = TRUE;
}
}
void TableViewerWindow::deleteItemSlot()
{
/* delete the actual item, then do a 'filter' */
DataElem *to_remove = ts.current_elem;
if(!to_remove)
return;
listView->removeItem();
ds->removeItem(to_remove);
applyFilter();
listView->rebuildData();
browseView->rebuildData();
dirty = TRUE;
}
void TableViewerWindow::editKeysSlot()
{
DataElem *d;
KeyList *k = TVKeyEdit::openEditKeysDialog(&ts, this);
if(k) {
/* set as new keys */
ds->setKeys(k);
ts.current_column = 0;
ts.kRep = k;
browseView->reset();
listView->reset();
filterView->reset();
browseView->rebuildKeys();
listView->rebuildKeys();
filterView->rebuildKeys();
ds->first();
/* set up the list view */
listView->clearItems();
do {
d = ds->getCurrentData();
if(d)
listView->addItem(d);
} while(ds->next());
/* Set up browse view, Will be based of structure of listView */
dirty = TRUE;
}
}
/*!
A Slot that allows for widgets above to indicate a search should be
done on a specified key index for a specified value
*/
void TableViewerWindow::searchOnKey(int i, TVVariant v)
{
listView->findItem(i, v);
ts.current_elem = listView->getCurrentData();
browseView->rebuildData();
}
void TableViewerWindow::setPrimaryKey(int i)
{
ts.current_column = i;
listView->rebuildData();
browseView->rebuildData();
}