1
/* This file is part of the KDE project
2
Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
Boston, MA 02111-1307, USA.
23
#include "stylist.moc"
28
#include <qtabwidget.h>
30
#include <qpushbutton.h>
32
#include <qgroupbox.h>
35
#include <qlineedit.h>
41
#include <qcombobox.h>
42
#include <qcheckbox.h>
44
#include <kbuttonbox.h>
46
#include <kcolordlg.h>
48
#include <kwtextdocument.h>
52
/******************************************************************/
53
/* Class: KWStyleManager */
54
/******************************************************************/
56
/* keep 2 qlists with the styles.
57
1 of the origs, another with the changed ones (in order of the stylesList)
58
When an orig entry is empty and the other is not, a new one has to be made,
59
when the orig is present and the other is not, the orig has to be deleted.
60
Otherwise all changes are copied from the changed ones to the origs on OK.
61
OK also frees all the changed ones and updates the doc if styles are deleted.
64
KWStyleManager::KWStyleManager( QWidget *_parent, KWDocument *_doc )
65
: KDialogBase( _parent, "Stylist", true,
67
KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Apply )
69
//setWFlags(getWFlags() || WDestructiveClose);
73
m_origStyles.setAutoDelete(false);
74
m_changedStyles.setAutoDelete(false);
75
KWUnit::Unit unit = m_doc->getUnit();
77
setupWidget(); // build the widget with the buttons and the list selector.
81
KWStyleFontTab * fontTab = new KWStyleFontTab( m_tabs );
84
KWStyleParagTab *newTab = new KWStyleParagTab( m_tabs );
85
newTab->setWidget( new KWIndentSpacingWidget( unit, newTab ) );
88
newTab = new KWStyleParagTab( m_tabs );
89
newTab->setWidget( new KWParagAlignWidget( newTab ) );
92
newTab = new KWStyleParagTab( m_tabs );
93
newTab->setWidget( new KWParagBorderWidget( newTab ) );
96
newTab = new KWStyleParagTab( m_tabs );
97
newTab->setWidget( new KWParagCounterWidget( newTab ) );
100
newTab = new KWStyleParagTab( m_tabs );
101
newTab->setWidget( new KWParagTabulatorsWidget( unit, newTab ) );
104
m_stylesList->setCurrentItem( 0 );
108
setInitialSize( QSize( 600, 570 ) );
111
void KWStyleManager::addTab( KWStyleManagerTab * tab )
113
m_tabsList.append( tab );
114
m_tabs->insertTab( tab, tab->tabName() );
117
void KWStyleManager::setupWidget()
119
QFrame * frame1 = makeMainWidget();
120
QGridLayout *frame1Layout = new QGridLayout( frame1, 0, 0, // auto
121
KDialog::marginHint(), KDialog::spacingHint() );
123
QListIterator<KWStyle> style( m_doc->styleList() );
124
numStyles = m_doc->styleList().count();
125
m_stylesList = new QListBox( frame1, "stylesList" );
126
for ( ; style.current() ; ++style )
128
m_stylesList->insertItem( style.current()->translatedName() );
129
m_origStyles.append( style.current() );
130
m_changedStyles.append( style.current() );
133
frame1Layout->addMultiCellWidget( m_stylesList, 0, 0, 0, 1 );
135
m_deleteButton = new QPushButton( frame1, "deleteButton" );
136
m_deleteButton->setText( i18n( "&Delete" ) );
137
connect( m_deleteButton, SIGNAL( clicked() ), this, SLOT( deleteStyle() ) );
139
frame1Layout->addWidget( m_deleteButton, 1, 1 );
141
m_newButton = new QPushButton( frame1, "newButton" );
142
m_newButton->setText( i18n( "New" ) );
143
connect( m_newButton, SIGNAL( clicked() ), this, SLOT( addStyle() ) );
145
frame1Layout->addWidget( m_newButton, 1, 0 );
147
m_tabs = new QTabWidget( frame1 );
148
frame1Layout->addMultiCellWidget( m_tabs, 0, 1, 2, 2 );
150
connect( m_stylesList, SIGNAL( selectionChanged() ), this, SLOT( switchStyle() ) );
151
connect( m_tabs, SIGNAL( currentChanged ( QWidget * ) ), this, SLOT( switchTabs() ) );
154
void KWStyleManager::addGeneralTab() {
155
QWidget *tab = new QWidget( m_tabs );
157
QGridLayout *tabLayout = new QGridLayout( tab );
158
tabLayout->setSpacing( 6 );
159
tabLayout->setMargin( 11 );
161
preview = new KWStylePreview( i18n( "Preview" ), tab );
163
tabLayout->addMultiCellWidget( preview, 2, 2, 0, 1 );
165
m_nameString = new QLineEdit( tab );
166
m_nameString->resize(m_nameString->sizeHint() );
167
connect( m_nameString, SIGNAL( textChanged( const QString &) ), this, SLOT( renameStyle(const QString &) ) );
169
tabLayout->addWidget( m_nameString, 0, 1 );
171
QLabel *nameLabel = new QLabel( tab );
172
nameLabel->setText( i18n( "Name:" ) );
173
nameLabel->resize(nameLabel->sizeHint());
174
nameLabel->setAlignment( AlignRight | AlignVCenter );
176
tabLayout->addWidget( nameLabel, 0, 0 );
178
m_styleCombo = new QComboBox( FALSE, tab, "styleCombo" );
180
for ( unsigned int i = 0; i < m_stylesList->count(); i++ ) {
181
m_styleCombo->insertItem( m_stylesList->text(i));
184
tabLayout->addWidget( m_styleCombo, 1, 1 );
186
QLabel *nextStyleLabel = new QLabel( tab );
187
nextStyleLabel->setText( i18n( "Next style:" ) );
189
tabLayout->addWidget( nextStyleLabel, 1, 0 );
190
m_tabs->insertTab( tab, i18n( "General" ) );
193
void KWStyleManager::switchStyle() {
194
kdDebug() << "KWStyleManager::switchStyle noSignals=" << noSignals << endl;
195
if(noSignals) return;
198
if(m_currentStyle !=0L)
202
int num = styleIndex( m_stylesList->currentItem() );
203
kdDebug() << "KWStyleManager::switchStyle switching to " << num << endl;
204
if(m_origStyles.at(num) == m_changedStyles.at(num)) {
205
m_currentStyle = new KWStyle( *m_origStyles.at(num) );
206
m_changedStyles.take(num);
207
m_changedStyles.insert(num, m_currentStyle);
209
m_currentStyle = m_changedStyles.at(num);
216
void KWStyleManager::switchTabs()
218
// Called when the user switches tabs
219
// We call save() to update our style, for the preview on the 1st tab
224
// Return the index of the a style from its position in the GUI
225
// (e.g. in m_stylesList or m_styleCombo). This index is used in
226
// the m_origStyles and m_changedStyles lists.
227
// The reason for the difference is that a deleted style is removed
228
// from the GUI but not from the internal lists.
229
int KWStyleManager::styleIndex( int pos ) {
231
for(unsigned int i=0; i < m_changedStyles.count(); i++) {
232
// Skip deleted styles, they're no in m_stylesList anymore
233
KWStyle * style = m_changedStyles.at(i);
234
if ( !style ) continue;
239
kdWarning() << "KWStyleManager::styleIndex no style found at pos " << pos << endl;
243
void KWStyleManager::updateGUI() {
244
kdDebug() << "KWStyleManager::updateGUI m_currentStyle=" << m_currentStyle << " " << m_currentStyle->name() << endl;
245
QListIterator<KWStyleManagerTab> it( m_tabsList );
246
for ( ; it.current() ; ++it )
248
it.current()->setStyle( m_currentStyle );
249
it.current()->update();
252
m_nameString->setText(m_currentStyle->translatedName());
254
kdDebug() << "KWStyleManager::updateGUI updating combo to " << m_currentStyle->followingStyle()->name() << endl;
255
for ( int i = 0; i < m_styleCombo->count(); i++ ) {
256
if ( m_styleCombo->text( i ) == m_currentStyle->followingStyle()->translatedName() ) {
257
m_styleCombo->setCurrentItem( i );
258
kdDebug() << "found at " << i << endl;
263
// update delete button (can't delete first style);
264
m_deleteButton->setEnabled(m_stylesList->currentItem() != 0);
268
void KWStyleManager::updatePreview()
270
preview->setStyle(m_currentStyle);
271
preview->repaint(true);
274
void KWStyleManager::save() {
276
// save changes from UI to object.
277
QListIterator<KWStyleManagerTab> it( m_tabsList );
278
for ( ; it.current() ; ++it )
279
it.current()->save();
281
m_currentStyle->setName( m_nameString->text() );
283
int indexNextStyle = styleIndex( m_styleCombo->currentItem() );
284
m_currentStyle->setFollowingStyle( m_changedStyles.at( indexNextStyle ) );
288
void KWStyleManager::addStyle() {
291
QString str = i18n( "New Style Template (%1)" ).arg(numStyles++);
292
if ( m_currentStyle )
294
m_currentStyle = new KWStyle( *m_currentStyle ); // Create a new style, initializing from the current one
295
m_currentStyle->setName( str );
298
m_currentStyle = new KWStyle( str );
301
m_origStyles.append(0L);
302
m_changedStyles.append(m_currentStyle);
303
m_stylesList->insertItem( str );
304
m_styleCombo->insertItem( str );
305
m_stylesList->setCurrentItem( m_stylesList->count() - 1 );
311
void KWStyleManager::deleteStyle() {
313
unsigned int cur = styleIndex( m_stylesList->currentItem() );
314
unsigned int curItem = m_stylesList->currentItem();
315
KWStyle *s = m_changedStyles.at(cur);
316
ASSERT( s == m_currentStyle );
319
m_changedStyles.remove(cur);
320
m_changedStyles.insert(cur,0L);
322
// Done with noSignals still false, so that when m_stylesList changes the current item
323
// we display it automatically
324
m_stylesList->removeItem(curItem);
325
m_styleCombo->removeItem(curItem);
327
m_stylesList->setSelected( m_stylesList->currentItem(), true );
330
void KWStyleManager::slotOk() {
333
KDialogBase::slotOk();
336
void KWStyleManager::slotApply() {
339
KDialogBase::slotApply();
342
void KWStyleManager::apply() {
344
bool docIsChanged=false;
345
for (unsigned int i =0 ; m_origStyles.count() > i ; i++) {
346
if(m_origStyles.at(i) == 0) { // newly added style
347
kdDebug() << "adding new " << m_changedStyles.at(i)->name() << " (" << i << ")" << endl;
348
KWStyle *tmp = m_doc->addStyleTemplate(m_changedStyles.take(i));
349
m_changedStyles.insert(i, tmp);
351
} else if(m_changedStyles.at(i) == 0) { // deleted style
352
kdDebug() << "deleting orig " << m_origStyles.at(i)->name() << " (" << i << ")" << endl;
354
KWStyle *orig = m_origStyles.at(i);
355
m_doc->applyStyleChange( orig, -1, -1 );
356
m_doc->removeStyleTemplate( orig );
357
// Note that the style is never deleted (we'll need it for undo/redo purposes)
360
} else if(m_changedStyles.at(i) != m_origStyles.at(i)) {
361
kdDebug() << "update style " << m_changedStyles.at(i)->name() << " (" << i << ")" << endl;
362
// simply updated style
363
KWStyle *orig = m_origStyles.at(i);
364
KWStyle *changed = m_changedStyles.at(i);
366
int paragLayoutChanged = orig->paragLayout().compare( changed->paragLayout() );
367
int formatChanged = orig->format().compare( changed->format() );
369
bool followingStyleChanged=(orig->followingStyle()!=changed->followingStyle());
370
if(formatChanged || paragLayoutChanged ||followingStyleChanged ||orig->name().compare(changed->name())!=0)
373
//kdDebug() << "old format " << orig->format().key() << " pointsize " << orig->format().pointSizeFloat() << endl;
374
//kdDebug() << "new format " << changed->format().key() << " pointsize " << changed->format().pointSizeFloat() << endl;
376
// Copy everything from changed to orig
379
// Apply the change selectively - i.e. only what changed
380
m_doc->applyStyleChange( orig, paragLayoutChanged, formatChanged );
383
// kdDebug() << "has not changed " << m_changedStyles.at(i)->name() << " (" << i << ")" << endl;
387
m_doc->updateAllStyleLists();
388
m_doc->setModified(true);
393
void KWStyleManager::renameStyle(const QString &theText) {
394
if(noSignals) return;
397
int index = m_stylesList->currentItem();
398
kdDebug() << "KWStyleManager::renameStyle " << index << " to " << theText << endl;
400
// rename only in the GUI, not even in the underlying objects (save() does it).
401
kdDebug() << "KWStyleManager::renameStyle before " << m_styleCombo->currentText() << endl;
402
m_styleCombo->changeItem( theText, index );
403
kdDebug() << "KWStyleManager::renameStyle after " << m_styleCombo->currentText() << endl;
404
m_stylesList->changeItem( theText, index );
406
// Check how many styles with that name we have now
408
for ( int i = 0; i < m_styleCombo->count(); i++ ) {
409
if ( m_styleCombo->text( i ) == m_stylesList->currentText() )
412
ASSERT( synonyms > 0 ); // should have found 'index' at least !
414
// Can't close the dialog if two styles have the same name
415
bool state=!theText.isEmpty() && (synonyms == 1);
416
enableButtonOK(state );
417
enableButtonApply(state);
418
m_deleteButton->setEnabled(state&&(m_stylesList->currentItem() != 0));
419
m_newButton->setEnabled(state);
422
/******************************************************************/
423
/* Class: KWStylePreview */
424
/******************************************************************/
425
KWStylePreview::KWStylePreview( const QString &title, QWidget *parent )
426
: QGroupBox( title, parent, "" )
428
m_zoomHandler = new KoZoomHandler;
429
m_textdoc = new KWTextDocument( m_zoomHandler );
430
KWTextParag * parag = static_cast<KWTextParag *>(m_textdoc->firstParag());
431
parag->insert( 0, i18n( "KWord, KOffice's Word Processor" ) );
434
KWStylePreview::~KWStylePreview()
437
delete m_zoomHandler;
440
void KWStylePreview::setStyle( KWStyle *style )
442
KWTextParag * parag = static_cast<KWTextParag *>(m_textdoc->firstParag());
443
parag->applyStyle( style );
447
void KWStylePreview::drawContents( QPainter *painter )
449
// see also KWNumPreview::drawContents
451
QRect r = contentsRect();
452
//kdDebug() << "KWStylePreview::drawContents contentsRect=" << DEBUGRECT(r) << endl;
454
QRect whiteRect( r.x() + 10, r.y() + 10,
455
r.width() - 20, r.height() - 20 );
456
QColorGroup cg = QApplication::palette().active();
457
painter->fillRect( whiteRect, cg.brush( QColorGroup::Base ) );
459
KWTextParag * parag = static_cast<KWTextParag *>(m_textdoc->firstParag());
460
if ( m_textdoc->width() != whiteRect.width() )
462
// For centering to work, and to even get word wrapping when the thing is too big :)
463
m_textdoc->setWidth( whiteRect.width() );
464
parag->invalidate(0);
468
QRect textRect = parag->rect();
470
// Center vertically, but not horizontally, to keep the parag alignment working,
471
textRect.moveTopLeft( QPoint( whiteRect.x() + 10,
472
whiteRect.y() + ( whiteRect.height() - textRect.height() ) / 2 ) );
473
//kdDebug() << "KWStylePreview::drawContents textRect=" << DEBUGRECT(textRect)
474
// << " textSize=" << textSize.width() << "," << textSize.height() << endl;
475
painter->setClipRect( textRect.intersect( whiteRect ) );
476
painter->translate( textRect.x(), textRect.y() );
478
m_textdoc->draw( painter, 0, 0, textRect.width(), textRect.height(), cg );
484
void KWStyleParagTab::update()
486
m_widget->display( m_style->paragLayout() );
489
void KWStyleParagTab::save()
491
m_widget->save( m_style->paragLayout() );
494
void KWStyleParagTab::setWidget( KWParagLayoutWidget * widget )
499
void KWStyleParagTab::resizeEvent( QResizeEvent *e )
501
QWidget::resizeEvent( e );
502
if ( m_widget ) m_widget->resize( size() );
505
KWStyleFontTab::KWStyleFontTab( QWidget * parent )
506
: KWStyleManagerTab( parent )
508
m_chooser = new KWFontChooser( this );
511
void KWStyleFontTab::update()
513
bool subScript = m_style->format().vAlign() == QTextFormat::AlignSubScript;
514
bool superScript = m_style->format().vAlign() == QTextFormat::AlignSuperScript;
515
m_chooser->setFont( m_style->format().font(), subScript, superScript );
516
m_chooser->setColor( m_style->format().color() );
519
void KWStyleFontTab::save()
521
m_style->format().setFont( m_chooser->getNewFont() );
522
if ( m_chooser->getSubScript() )
523
m_style->format().setVAlign( QTextFormat::AlignSubScript );
524
else if ( m_chooser->getSuperScript() )
525
m_style->format().setVAlign( QTextFormat::AlignSuperScript );
527
m_style->format().setVAlign( QTextFormat::AlignNormal );
528
m_style->format().setColor( m_chooser->color() );
531
QString KWStyleFontTab::tabName()
536
void KWStyleFontTab::resizeEvent( QResizeEvent *e )
538
QWidget::resizeEvent( e );
539
if ( m_chooser ) m_chooser->resize( size() );