kspread

kspread_sheet.cpp
1/* This file is part of the KDE project
2 Copyright 1998, 1999 Torben Weis <weis@kde.org>
3 Copyright 1999- 2006 The KSpread Team
4 www.koffice.org/kspread
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include <assert.h>
23#include <ctype.h>
24#include <float.h>
25#include <math.h>
26#include <pwd.h>
27#include <stdlib.h>
28#include <unistd.h>
29
30#include <tqapplication.h>
31#include <tqcheckbox.h>
32#include <tqclipboard.h>
33#include <tqlabel.h>
34#include <tqlayout.h>
35#include <tqlineedit.h>
36#include <tqpicture.h>
37#include <tqregexp.h>
38#include <tqvbox.h>
39#include <tqmap.h>
40
41#include <kdebug.h>
42#include <kmdcodec.h>
43#include <kfind.h>
44#include <kfinddialog.h>
45#include <tdemessagebox.h>
46#include <kreplace.h>
47#include <kreplacedialog.h>
48#include <kprinter.h>
49#include <kurl.h>
50
51#include <koChart.h>
52#include <KoDom.h>
53#include <KoDocumentInfo.h>
54#include <KoOasisLoadingContext.h>
55#include <KoOasisSettings.h>
56#include <KoOasisStyles.h>
57#include <KoQueryTrader.h>
58#include <KoStyleStack.h>
59#include <KoUnit.h>
60#include <KoXmlNS.h>
61#include <KoXmlWriter.h>
62
63#include "commands.h"
64#include "dependencies.h"
65#include "selection.h"
66#include "ksploadinginfo.h"
67#include "ksprsavinginfo.h"
68#include "kspread_canvas.h"
69#include "kspread_cluster.h"
70#include "kspread_condition.h"
71#include "kspread_doc.h"
72#include "kspread_global.h"
73#include "kspread_locale.h"
74#include "kspread_map.h"
75#include "kspread_object.h"
76#include "kspread_sheetprint.h"
77#include "kspread_style.h"
78#include "kspread_style_manager.h"
79#include "kspread_undo.h"
80#include "kspread_util.h"
81#include "kspread_view.h"
82#include "manipulator.h"
83#include "manipulator_data.h"
84#include "KSpreadTableIface.h"
85
86#include "kspread_sheet.h"
87#include "kspread_sheet.moc"
88
89#define NO_MODIFICATION_POSSIBLE \
90do { \
91 KMessageBox::error( 0, i18n ( "You cannot change a protected sheet" ) ); return; \
92} while(0)
93
94namespace KSpread {
95
96/*****************************************************************************
97 *
98 * CellBinding
99 *
100 *****************************************************************************/
101
102CellBinding::CellBinding( Sheet *_sheet, const TQRect& _area )
103{
104 m_rctDataArea = _area;
105
106 m_pSheet = _sheet;
107 m_pSheet->addCellBinding( this );
108
109 m_bIgnoreChanges = false;
110}
111
112CellBinding::~CellBinding()
113{
114 m_pSheet->removeCellBinding( this );
115}
116
118{
119 if ( m_bIgnoreChanges )
120 return;
121
122 emit changed( _cell );
123}
124
125bool CellBinding::contains( int _x, int _y )
126{
127 return m_rctDataArea.contains( TQPoint( _x, _y ) );
128}
129
130/*****************************************************************************
131 *
132 * ChartBinding
133 *
134 *****************************************************************************/
135
136ChartBinding::ChartBinding( Sheet *_sheet, const TQRect& _area, EmbeddedChart *_child )
137 : CellBinding( _sheet, _area )
138{
139 m_child = _child;
140}
141
142ChartBinding::~ChartBinding()
143{
144}
145
146void ChartBinding::cellChanged( Cell* /*changedCell*/ )
147{
148 if ( m_bIgnoreChanges )
149 return;
150
151 //Ensure display gets updated by marking all cells underneath the chart as
152 //dirty
153
154 const TQRect chartGeometry = m_child->geometry().toTQRect();
155
156 double tmp;
157 int left = sheet()->leftColumn( chartGeometry.left() , tmp );
158 int top = sheet()->topRow( chartGeometry.top() , tmp );
159 int right = sheet()->rightColumn( chartGeometry.right() );
160 int bottom = sheet()->bottomRow( chartGeometry.bottom() );
161
162 sheet()->setRegionPaintDirty( TQRect(left,top,right-left,bottom-top) );
163
164 //kdDebug(36001) << m_rctDataArea << endl;
165
166 // Get the chart and resize its data if necessary.
167 //
168 // FIXME: Only do this if he data actually changed size.
169 KoChart::Part *chart = m_child->chart();
170 chart->resizeData( m_rctDataArea.height(), m_rctDataArea.width() );
171
172 // Reset all the data, i.e. retransfer them to the chart.
173 // This is definitely not the most efficient way to do this.
174 //
175 // FIXME: Find a way to do it with just the data that changed.
176 Cell* cell;
177 for ( int row = 0; row < m_rctDataArea.height(); row++ ) {
178 for ( int col = 0; col < m_rctDataArea.width(); col++ ) {
179 cell = m_pSheet->cellAt( m_rctDataArea.left() + col,
180 m_rctDataArea.top() + row );
181 if ( cell && cell->value().isNumber() )
182 chart->setCellData( row, col, cell->value().asFloat() );
183 else if ( cell )
184 chart->setCellData( row, col, cell->value().asString() );
185 else
186 chart->setCellData( row, col, KoChart::Value() );
187 }
188 }
189 chart->analyzeHeaders( );
190
191 // ######### Kalle may be interested in that, too
192#if 0
193 Chart::Range range;
194 range.top = m_rctDataArea.top();
195 range.left = m_rctDataArea.left();
196 range.right = m_rctDataArea.right();
197 range.bottom = m_rctDataArea.bottom();
198 range.sheet = m_pSheet->name(); */
199
200 //m_child->chart()->setData( matrix );
201
202 // Force a redraw of the chart on all views
203
205#endif
206 // sheet()->emit_polygonInvalidated( m_child->framePointArray() );
207}
208
209
210/******************************************************************/
211/* Class: TextDrag */
212/******************************************************************/
213
214
215TextDrag::TextDrag( TQWidget * dragSource, const char * name )
216 : TQTextDrag( dragSource, name )
217{
218}
219
220TextDrag::~TextDrag()
221{
222}
223
224
225TQByteArray TextDrag::encodedData( const char * mime ) const
226{
227 if ( strcmp( selectionMimeType(), mime ) == 0)
228 return m_kspread;
229 else
230 return TQTextDrag::encodedData( mime );
231}
232
233bool TextDrag::canDecode( TQMimeSource* e )
234{
235 if ( e->provides( selectionMimeType() ) )
236 return true;
237 return TQTextDrag::canDecode(e);
238}
239
240const char * TextDrag::format( int i ) const
241{
242 if ( i < 4 ) // HACK, but how to do otherwise ??
243 return TQTextDrag::format(i);
244 else if ( i == 4 )
245 return selectionMimeType();
246 else return 0;
247}
248
249const char * TextDrag::selectionMimeType()
250{
251 return "application/x-kspread-snippet";
252}
253
254/*****************************************************************************
255 *
256 * Sheet
257 *
258 *****************************************************************************/
259
260class Sheet::Private
261{
262public:
263
264 Map* workbook;
265
266 DCOPObject* dcop;
267
268 TQString name;
269 int id;
270
271 Sheet::LayoutDirection layoutDirection;
272
273 // true if sheet is hidden
274 bool hide;
275
276 // password of protected sheet
277 TQCString password;
278
279
280 bool showGrid;
281 bool showFormula;
282 bool showFormulaIndicator;
283 bool showCommentIndicator;
284 bool autoCalc;
285 bool lcMode;
286 bool showColumnNumber;
287 bool hideZero;
288 bool firstLetterUpper;
289
290 // clusters to hold objects
291 Cluster cells;
292 RowCluster rows;
293 ColumnCluster columns;
294
295 // default objects
296 Cell* defaultCell;
297 Format* defaultFormat;
298 RowFormat* defaultRowFormat;
299 ColumnFormat* defaultColumnFormat;
300
301 // hold the print object
302 SheetPrint* print;
303
304 // cells that need painting
305 Region paintDirtyList;
306
307 // to get font metrics
308 TQPainter *painter;
309 TQWidget *widget;
310
311 // List of all cell bindings. For example charts use bindings to get
312 // informed about changing cell contents.
313 TQPtrList<CellBinding> cellBindings;
314
315 // Indicates whether the sheet should paint the page breaks.
316 // Doing so costs some time, so by default it should be turned off.
317 bool showPageBorders;
318
319 // List of all embedded objects. FIXME unused ??
320 // TQPtrList<Child> m_lstChildren;
321
322 // The highest row and column ever accessed by the user.
323 int maxRow;
324 int maxColumn;
325
326 // Max range of canvas in x and ye direction.
327 // Depends on KS_colMax/KS_rowMax and the width/height of all columns/rows
328 double sizeMaxX;
329 double sizeMaxY;
330
331
332 bool scrollBarUpdates;
333
334 TQPen emptyPen;
335 TQBrush emptyBrush;
336 TQColor emptyColor;
337
338 int scrollPosX;
339 int scrollPosY;
340
341 KSpread::DependencyManager *dependencies;
342};
343
344int Sheet::s_id = 0L;
345TQIntDict<Sheet>* Sheet::s_mapSheets;
346
347Sheet* Sheet::find( int _id )
348{
349 if ( !s_mapSheets )
350 return 0L;
351
352 return (*s_mapSheets)[ _id ];
353}
354
355Sheet::Sheet (Map* map,
356 const TQString &sheetName, const char *_name )
357 : TQObject( map, _name )
358{
359 if ( s_mapSheets == 0L )
360 s_mapSheets = new TQIntDict<Sheet>;
361 d = new Private;
362
363 d->workbook = map;
364
365 d->id = s_id++;
366 s_mapSheets->insert( d->id, this );
367
368 d->layoutDirection = LeftToRight;
369
370 d->defaultFormat = new Format (this, d->workbook->doc()->styleManager()->defaultStyle());
371 d->emptyPen.setStyle( TQt::NoPen );
372 d->dcop = 0;
373 d->name = sheetName;
374
375 dcopObject();
376 d->cellBindings.setAutoDelete( false );
377
378 // m_lstChildren.setAutoDelete( true );
379
380 d->cells.setAutoDelete( true );
381 d->rows.setAutoDelete( true );
382 d->columns.setAutoDelete( true );
383
384 d->defaultCell = new Cell( this, d->workbook->doc()->styleManager()->defaultStyle(), 0, 0);
385 d->defaultRowFormat = new RowFormat( this, 0 );
386 d->defaultRowFormat->setDefault();
387 d->defaultColumnFormat = new ColumnFormat( this, 0 );
388 d->defaultColumnFormat->setDefault();
389
390 d->widget = new TQWidget();
391 d->painter = new TQPainter;
392 d->painter->begin( d->widget );
393
394 d->maxColumn = 256;
395 d->maxRow = 256;
396 d->sizeMaxX = KS_colMax * d->defaultColumnFormat->dblWidth(); // default is max cols * default width
397 d->sizeMaxY = KS_rowMax * d->defaultRowFormat->dblHeight(); // default is max rows * default height
398
399 d->scrollBarUpdates = true;
400
401 setHidden( false );
402 d->showGrid=true;
403 d->showFormula=false;
404 d->showFormulaIndicator=true;
405 d->showCommentIndicator=true;
406 d->showPageBorders = false;
407
408 d->lcMode=false;
409 d->showColumnNumber=false;
410 d->hideZero=false;
411 d->firstLetterUpper=false;
412 d->autoCalc=true;
413 // Get a unique name so that we can offer scripting
414 if ( !_name )
415 {
416 TQCString s;
417 s.sprintf("Sheet%i", s_id );
418 TQObject::setName( s.data() );
419 }
420 d->print = new SheetPrint( this );
421
422 // initialize dependencies
423 d->dependencies = new KSpread::DependencyManager (this);
424
425 // connect to named area slots
426 TQObject::connect( doc(), TQ_SIGNAL( sig_addAreaName( const TQString & ) ),
427 this, TQ_SLOT( slotAreaModified( const TQString & ) ) );
428
429 TQObject::connect( doc(), TQ_SIGNAL( sig_removeAreaName( const TQString & ) ),
430 this, TQ_SLOT( slotAreaModified( const TQString & ) ) );
431
432
433}
434
435TQString Sheet::sheetName() const
436{
437 return d->name;
438}
439
440Map* Sheet::workbook() const
441{
442 return d->workbook;
443}
444
445Doc* Sheet::doc() const
446{
447 return d->workbook->doc();
448}
449
450int Sheet::id() const
451{
452 return d->id;
453}
454
455Sheet::LayoutDirection Sheet::layoutDirection() const
456{
457 return d->layoutDirection;
458}
459
460void Sheet::setLayoutDirection( LayoutDirection dir )
461{
462 d->layoutDirection = dir;
463}
464
465bool Sheet::isRightToLeft() const
466{
467 return d->layoutDirection == RightToLeft;
468}
469
470bool Sheet::isHidden() const
471{
472 return d->hide;
473}
474
475void Sheet::setHidden( bool hidden )
476{
477 d->hide = hidden;
478}
479
480bool Sheet::getShowGrid() const
481{
482 return d->showGrid;
483}
484
485void Sheet::setShowGrid( bool _showGrid )
486{
487 d->showGrid=_showGrid;
488}
489
490bool Sheet::getShowFormula() const
491{
492 return d->showFormula;
493}
494
495void Sheet::setShowFormula( bool _showFormula )
496{
497 d->showFormula=_showFormula;
498}
499
500bool Sheet::getShowFormulaIndicator() const
501{
502 return d->showFormulaIndicator;
503}
504
505void Sheet::setShowFormulaIndicator( bool _showFormulaIndicator )
506{
507 d->showFormulaIndicator=_showFormulaIndicator;
508}
509
510bool Sheet::getShowCommentIndicator() const
511{
512 return d->showCommentIndicator;
513}
514
515void Sheet::setShowCommentIndicator(bool _indic)
516{
517 d->showCommentIndicator=_indic;
518}
519
520bool Sheet::getLcMode() const
521{
522 return d->lcMode;
523}
524
525void Sheet::setLcMode( bool _lcMode )
526{
527 d->lcMode=_lcMode;
528}
529
530bool Sheet::getAutoCalc() const
531{
532 return d->autoCalc;
533}
534
535void Sheet::setAutoCalc( bool _AutoCalc )
536{
537 //Avoid possible recalculation of dependancies if the auto calc setting hasn't changed
538 if (d->autoCalc == _AutoCalc)
539 return;
540
541 //If enabling automatic calculation, make sure that the dependencies are up-to-date
542 if (_AutoCalc == true)
543 {
544 updateAllDependencies();
545 recalc();
546 }
547
548 d->autoCalc=_AutoCalc;
549
550
551}
552
553bool Sheet::getShowColumnNumber() const
554{
555 return d->showColumnNumber;
556}
557
558void Sheet::setShowColumnNumber( bool _showColumnNumber )
559{
560 d->showColumnNumber=_showColumnNumber;
561}
562
563bool Sheet::getHideZero() const
564{
565 return d->hideZero;
566}
567
568void Sheet::setHideZero( bool _hideZero )
569{
570 d->hideZero=_hideZero;
571}
572
573bool Sheet::getFirstLetterUpper() const
574{
575 return d->firstLetterUpper;
576}
577
578void Sheet::setFirstLetterUpper( bool _firstUpper )
579{
580 d->firstLetterUpper=_firstUpper;
581}
582
583bool Sheet::isShowPageBorders() const
584{
585 return d->showPageBorders;
586}
587
588bool Sheet::isEmpty( unsigned long int x, unsigned long int y ) const
589{
590 const Cell* c = cellAt( x, y );
591 if ( !c || c->isEmpty() )
592 return true;
593
594 return false;
595}
596
597Cell* Sheet::defaultCell() const
598{
599 return d->defaultCell;
600}
601
602Format* Sheet::defaultFormat()
603{
604 return d->defaultFormat;
605}
606
607const Format* Sheet::defaultFormat() const
608{
609 return d->defaultFormat;
610}
611
612const ColumnFormat* Sheet::columnFormat( int _column ) const
613{
614 const ColumnFormat *p = d->columns.lookup( _column );
615 if ( p != 0L )
616 return p;
617
618 return d->defaultColumnFormat;
619}
620
621ColumnFormat* Sheet::columnFormat( int _column )
622{
623 ColumnFormat *p = d->columns.lookup( _column );
624 if ( p != 0L )
625 return p;
626
627 return d->defaultColumnFormat;
628}
629
630const RowFormat* Sheet::rowFormat( int _row ) const
631{
632 const RowFormat *p = d->rows.lookup( _row );
633 if ( p != 0L )
634 return p;
635
636 return d->defaultRowFormat;
637}
638
639RowFormat* Sheet::rowFormat( int _row )
640{
641 RowFormat *p = d->rows.lookup( _row );
642 if ( p != 0L )
643 return p;
644
645 return d->defaultRowFormat;
646}
647
648Value Sheet::value (int col, int row) const
649{
650 Cell *cell = d->cells.lookup (col, row);
651 if (cell)
652 return cell->value ();
653 Value empty;
654 return empty;
655}
656
657Value Sheet::valueRange (int col1, int row1,
658 int col2, int row2) const
659{
660 return d->cells.valueRange (col1, row1, col2, row2);
661}
662
663void Sheet::password( TQCString & passwd ) const
664{
665 passwd = d->password;
666}
667
668bool Sheet::isProtected() const
669{
670 return !d->password.isNull();
671}
672
673void Sheet::setProtected( TQCString const & passwd )
674{
675 d->password = passwd;
676}
677
678bool Sheet::checkPassword( TQCString const & passwd ) const
679{
680 return ( passwd == d->password );
681}
682
683SheetPrint* Sheet::print() const
684{
685 return d->print;
686}
687
688TQPainter& Sheet::painter()
689{
690 return *d->painter;
691}
692
693TQWidget* Sheet::widget()const
694{
695 return d->widget;
696}
697
698CellBinding* Sheet::firstCellBinding()
699{
700 return d->cellBindings.first();
701}
702
703CellBinding* Sheet::nextCellBinding()
704{
705 return d->cellBindings.next();
706}
707
708void Sheet::setDefaultHeight( double height )
709{
710 if ( isProtected() )
711 NO_MODIFICATION_POSSIBLE;
712
713 d->defaultRowFormat->setDblHeight( height );
714}
715
716void Sheet::setDefaultWidth( double width )
717{
718 if ( isProtected() )
719 NO_MODIFICATION_POSSIBLE;
720
721 d->defaultColumnFormat->setDblWidth( width );
722}
723
724double Sheet::sizeMaxX() const
725{
726 return d->sizeMaxX;
727}
728
729double Sheet::sizeMaxY() const
730{
731 return d->sizeMaxY;
732}
733
734int Sheet::maxColumn() const
735{
736 return d->maxColumn;
737}
738
739int Sheet::maxRow() const
740{
741 return d->maxRow;
742}
743
744const TQPen& Sheet::emptyPen() const
745{
746 return d->emptyPen;
747}
748
749const TQBrush& Sheet::emptyBrush() const
750{
751 return d->emptyBrush;
752}
753
754const TQColor& Sheet::emptyColor() const
755{
756 return d->emptyColor;
757}
758
759KSpread::DependencyManager *Sheet::dependencies ()
760{
761 return d->dependencies;
762}
763
764int Sheet::numSelected() const
765{
766 int num = 0;
767
768 TQPtrListIterator<EmbeddedObject> it( d->workbook->doc()->embeddedObjects() );
769 for ( ; it.current() ; ++it )
770 {
771 if( it.current()->sheet() == this && it.current()->isSelected() )
772 num++;
773 }
774
775 return num;
776}
777
778int Sheet::leftColumn( double _xpos, double &_left,
779 const Canvas *_canvas ) const
780{
781 if ( _canvas )
782 {
783 _xpos += _canvas->xOffset();
784 _left = -_canvas->xOffset();
785 }
786 else
787 _left = 0.0;
788
789 int col = 1;
790 double x = columnFormat( col )->dblWidth( _canvas );
791 while ( x < _xpos )
792 {
793 // Should never happen
794 if ( col >= KS_colMax )
795 {
796 kdDebug(36001) << "Sheet:leftColumn: invalid column (col: " << col + 1 << ")" << endl;
797 return KS_colMax + 1; //Return out of range value, so other code can react on this
798 }
799 _left += columnFormat( col )->dblWidth( _canvas );
800 col++;
801 x += columnFormat( col )->dblWidth( _canvas );
802 }
803
804 return col;
805}
806
807int Sheet::rightColumn( double _xpos, const Canvas *_canvas ) const
808{
809 if ( _canvas )
810 _xpos += _canvas->xOffset();
811
812 int col = 1;
813 double x = 0.0;
814 while ( x < _xpos )
815 {
816 // Should never happen
817 if ( col > KS_colMax )
818 {
819 kdDebug(36001) << "Sheet:rightColumn: invalid column (col: " << col << ")" << endl;
820 return KS_colMax + 1; //Return out of range value, so other code can react on this
821 }
822 x += columnFormat( col )->dblWidth( _canvas );
823 col++;
824 }
825
826 return col - 1;
827}
828
829TQRect Sheet::visibleRect( Canvas const * const _canvas ) const
830{
831 int top = 0;
832 int left = 0;
833
834 double x = 0;
835 double y = 0;
836 double width = 0;
837 double height = 0;
838
839 if ( _canvas )
840 {
841 y += _canvas->yOffset() * _canvas->zoom();
842 x += _canvas->xOffset() * _canvas->zoom();
843 width = _canvas->width();
844 height = _canvas->height();
845 }
846
847 double yn = rowFormat( top )->dblHeight( _canvas );
848 while ( yn < y )
849 {
850 if ( top >= KS_rowMax ) // Should never happen
851 break;
852
853 ++top;
854 yn += rowFormat( top )->dblHeight( _canvas );
855 }
856
857 int bottom = top + 1;
858
859 y += height;
860 while ( yn < y )
861 {
862 if ( bottom > KS_rowMax ) // Should never happen
863 break;
864
865 ++bottom;
866 yn += rowFormat( bottom )->dblHeight( _canvas );
867 }
868
869 double xn = columnFormat( left )->dblWidth( _canvas );
870 while ( xn < x )
871 {
872 if ( left >= KS_colMax ) // Should never happen
873 break;
874
875 ++left;
876 xn += columnFormat( left )->dblWidth( _canvas );
877 }
878 x += width;
879
880 int right = left + 1;
881
882 while ( xn < x )
883 {
884 if ( right > KS_colMax ) // Should never happen
885 break;
886
887 ++right;
888 xn += columnFormat( right )->dblWidth( _canvas );
889 }
890 x += width;
891
892 return TQRect( left, top, right - left + 1, bottom - top + 1 );
893}
894
895int Sheet::topRow( double _ypos, double & _top,
896 const Canvas *_canvas ) const
897{
898 if ( _canvas )
899 {
900 _ypos += _canvas->yOffset();
901 _top = -_canvas->yOffset();
902 }
903 else
904 _top = 0.0;
905
906 int row = 1;
907 double y = rowFormat( row )->dblHeight( _canvas );
908 while ( y < _ypos )
909 {
910 // Should never happen
911 if ( row >= KS_rowMax )
912 {
913 kdDebug(36001) << "Sheet:topRow: invalid row (row: " << row + 1 << ")" << endl;
914 return KS_rowMax + 1; //Return out of range value, so other code can react on this
915 }
916 _top += rowFormat( row )->dblHeight( _canvas );
917 row++;
918 y += rowFormat( row )->dblHeight( _canvas );
919 }
920
921 return row;
922}
923
924int Sheet::bottomRow( double _ypos, const Canvas *_canvas ) const
925{
926 if ( _canvas )
927 _ypos += _canvas->yOffset();
928
929 int row = 1;
930 double y = 0.0;
931 while ( y < _ypos )
932 {
933 // Should never happen
934 if ( row > KS_rowMax )
935 {
936 kdDebug(36001) << "Sheet:bottomRow: invalid row (row: " << row << ")" << endl;
937 return KS_rowMax + 1; //Return out of range value, so other code can react on this
938 }
939 y += rowFormat( row )->dblHeight( _canvas );
940 row++;
941 }
942
943 return row - 1;
944}
945
946double Sheet::dblColumnPos( int _col, const Canvas *_canvas ) const
947{
948 double x = 0.0;
949 if ( _canvas )
950 x -= _canvas->xOffset();
951 for ( int col = 1; col < _col; col++ )
952 {
953 // Should never happen
954 if ( col > KS_colMax )
955 {
956 kdDebug(36001) << "Sheet:columnPos: invalid column (col: " << col << ")" << endl;
957 return x;
958 }
959
960 x += columnFormat( col )->dblWidth( _canvas );
961 }
962
963 return x;
964}
965
966int Sheet::columnPos( int _col, const Canvas *_canvas ) const
967{
968 return (int)dblColumnPos( _col, _canvas );
969}
970
971
972double Sheet::dblRowPos( int _row, const Canvas *_canvas ) const
973{
974 double y = 0.0;
975 if ( _canvas )
976 y -= _canvas->yOffset();
977
978 for ( int row = 1 ; row < _row ; row++ )
979 {
980 // Should never happen
981 if ( row > KS_rowMax )
982 {
983 kdDebug(36001) << "Sheet:rowPos: invalid row (row: " << row << ")" << endl;
984 return y;
985 }
986
987 y += rowFormat( row )->dblHeight( _canvas );
988 }
989
990 return y;
991}
992
993int Sheet::rowPos( int _row, const Canvas *_canvas ) const
994{
995 return (int)dblRowPos( _row, _canvas );
996}
997
998
999void Sheet::adjustSizeMaxX ( double _x )
1000{
1001 d->sizeMaxX += _x;
1002}
1003
1004void Sheet::adjustSizeMaxY ( double _y )
1005{
1006 d->sizeMaxY += _y;
1007}
1008
1009Cell* Sheet::visibleCellAt( int _column, int _row, bool _scrollbar_update )
1010{
1011 Cell* cell = cellAt( _column, _row, _scrollbar_update );
1012 if ( cell->obscuringCells().isEmpty() )
1013 return cell;
1014 else
1015 return cell->obscuringCells().last();
1016}
1017
1018Cell* Sheet::firstCell() const
1019{
1020 return d->cells.firstCell();
1021}
1022
1023RowFormat* Sheet::firstRow() const
1024{
1025 return d->rows.first();
1026}
1027
1028ColumnFormat* Sheet::firstCol() const
1029{
1030 return d->columns.first();
1031}
1032
1033Cell* Sheet::cellAt( int _column, int _row ) const
1034{
1035 Cell *p = d->cells.lookup( _column, _row );
1036 if ( p != 0L )
1037 return p;
1038
1039 return d->defaultCell;
1040}
1041
1042Cell* Sheet::cellAt( int _column, int _row, bool _scrollbar_update )
1043{
1044 if ( _scrollbar_update && d->scrollBarUpdates )
1045 {
1046 checkRangeHBorder( _column );
1047 checkRangeVBorder( _row );
1048 }
1049
1050 Cell *p = d->cells.lookup( _column, _row );
1051 if ( p != 0L )
1052 return p;
1053
1054 return d->defaultCell;
1055}
1056
1057ColumnFormat* Sheet::nonDefaultColumnFormat( int _column, bool force_creation )
1058{
1059 ColumnFormat *p = d->columns.lookup( _column );
1060 if ( p != 0L || !force_creation )
1061 return p;
1062
1063 p = new ColumnFormat( this, _column );
1064 // TODO: copy the default ColumnFormat here!!
1065 p->setDblWidth( d->defaultColumnFormat->dblWidth() );
1066
1067 d->columns.insertElement( p, _column );
1068
1069 return p;
1070}
1071
1072RowFormat* Sheet::nonDefaultRowFormat( int _row, bool force_creation )
1073{
1074 RowFormat *p = d->rows.lookup( _row );
1075 if ( p != 0L || !force_creation )
1076 return p;
1077
1078 p = new RowFormat( this, _row );
1079 // TODO: copy the default RowLFormat here!!
1080 p->setDblHeight( d->defaultRowFormat->dblHeight() );
1081
1082 d->rows.insertElement( p, _row );
1083
1084 return p;
1085}
1086
1087Cell* Sheet::nonDefaultCell( int _column, int _row,
1088 bool _scrollbar_update, Style * _style )
1089{
1090 // NOTE Stefan: _scrollbar_update defaults to false and this function
1091 // is never called with it being true. So, this here is
1092 // actually never processed. I'll leave this in here for the
1093 // case I'm mistaken, but will remove it for 2.0.
1094 if ( _scrollbar_update && d->scrollBarUpdates )
1095 {
1096 checkRangeHBorder( _column );
1097 checkRangeVBorder( _row );
1098 }
1099
1100 Cell * p = d->cells.lookup( _column, _row );
1101 if ( p != 0L )
1102 return p;
1103
1104 Cell * cell = 0;
1105
1106 if ( _style )
1107 cell = new Cell( this, _style, _column, _row );
1108 else
1109 cell = new Cell( this, _column, _row );
1110
1111 insertCell( cell );
1112
1113 return cell;
1114}
1115
1116void Sheet::setText( int _row, int _column, const TQString& _text, bool asString )
1117{
1118 ProtectedCheck prot;
1119 prot.setSheet (this);
1120 prot.add (TQPoint (_column, _row));
1121 if (prot.check())
1122 NO_MODIFICATION_POSSIBLE;
1123
1124 DataManipulator *dm = new DataManipulator ();
1125 dm->setSheet (this);
1126 dm->setValue (_text);
1127 dm->setParsing (!asString);
1128 dm->add (TQPoint (_column, _row));
1129 dm->execute ();
1130
1131 /* PRE-MANIPULATOR CODE looked like this:
1132 TODO remove this after the new code works
1133 if ( !doc()->undoLocked() )
1134 {
1135 UndoSetText *undo = new UndoSetText( doc(), this, cell->text(), _column, _row,cell->formatType() );
1136 doc()->addCommand( undo );
1137 }
1138
1139 // The cell will force a display refresh itself, so we dont have to care here.
1140 cell->setCellText( _text, asString );
1141 */
1142
1143 //refresh anchor
1144 if(_text.at(0)=='!')
1145 emit sig_updateView( this, Region(_column,_row,_column,_row) );
1146}
1147
1148void Sheet::setArrayFormula (Selection *selectionInfo, const TQString &_text)
1149{
1150 // check protection
1151 ProtectedCheck prot;
1152 prot.setSheet (this);
1153 prot.add (*selectionInfo);
1154 if (prot.check())
1155 NO_MODIFICATION_POSSIBLE;
1156
1157 // create and call the manipulator
1158 ArrayFormulaManipulator *afm = new ArrayFormulaManipulator;
1159 afm->setSheet (this);
1160 afm->setText (_text);
1161 afm->add (*selectionInfo);
1162 afm->execute ();
1163
1164 /* PRE-MANIPULATOR CODE LOOKED LIKE THIS
1165 TODO remove this when the above code works
1166 // add undo
1167 if ( !doc()->undoLocked() )
1168 {
1169 UndoChangeAreaTextCell *undo =
1170 new UndoChangeAreaTextCell (doc(), this,
1171 TQRect (_column, _row, cols, rows));
1172 doc()->addCommand( undo );
1173 }
1174
1175 // fill in the cells ... top-left one gets the formula, the rest gets =INDEX
1176 // TODO: also fill in information about cells being a part of a range
1177 Cell *cell = nonDefaultCell (_column, _row);
1178 cell->setCellText (_text, false);
1179 TQString cellRef = cell->name();
1180 for (int row = 0; row < rows; ++row)
1181 for (int col = 0; col < cols; col++)
1182 if (col || row)
1183 {
1184 Cell *cell = nonDefaultCell (_column + col, _row + row);
1185 cell->setCellText ("=INDEX(" + cellRef + ";" + TQString::number (row+1)
1186 + ";" + TQString::number (col+1) + ")", false);
1187 }
1188 */
1189}
1190
1191void Sheet::setLayoutDirtyFlag()
1192{
1193 Cell * c = d->cells.firstCell();
1194 for( ; c; c = c->nextCell() )
1195 c->setLayoutDirtyFlag();
1196}
1197
1198void Sheet::setCalcDirtyFlag()
1199{
1200 Cell* c = d->cells.firstCell();
1201 for( ; c; c = c->nextCell() )
1202 {
1203 if ( !(c->isObscured() && c->isPartOfMerged()) )
1204 c->setCalcDirtyFlag();
1205 }
1206}
1207
1208void Sheet::updateAllDependencies()
1209{
1210 for (Cell* cell = d->cells.firstCell() ; cell ; cell = cell->nextCell())
1211 {
1212 Point cellLocation;
1213 cellLocation.setSheet(cell->sheet());
1214 cellLocation.setRow(cell->row());
1215 cellLocation.setColumn(cell->column());
1216 d->dependencies->cellChanged(cellLocation);
1217 }
1218}
1219
1220void Sheet::recalc()
1221{
1222 recalc(false);
1223}
1224
1225void Sheet::recalc( bool force )
1226{
1227 ElapsedTime et( "Recalculating " + d->name, ElapsedTime::PrintOnlyTime );
1228 // emitBeginOperation(true);
1229 // setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
1230 setCalcDirtyFlag();
1231
1232 //If automatic calculation is disabled, don't recalculate unless the force flag has been
1233 //set.
1234 if ( !getAutoCalc() && !force )
1235 return;
1236
1237 //If automatic calculation is disabled, the dependencies won't be up to date, so they need
1238 //to be recalculated.
1239 //FIXME: Tomas, is there a more efficient way to do this?
1240 if ( !getAutoCalc() )
1241 updateAllDependencies();
1242
1243
1244 // (Tomas): actually recalc each cell
1245 // this is FAR from being perfect, dependencies will cause some to be
1246 // recalculated a LOT, but it's still better than otherwise, where
1247 // we get no recalc if the result stored in a file differs from the
1248 // current one - then we only obtain the correct result AFTER we scroll
1249 // to the cell ... recalc should actually ... recalc :)
1250 Cell* c;
1251
1252 int count = 0;
1253 c = d->cells.firstCell();
1254 for( ; c; c = c->nextCell() )
1255 ++count;
1256
1257 int cur = 0;
1258 int percent = -1;
1259 c = d->cells.firstCell();
1260 for( ; c; c = c->nextCell() )
1261 {
1262 c->calc (false);
1263 cur++;
1264 // some debug output to get some idea how damn slow this is ...
1265 if (cur*100/count != percent) {
1266 percent = cur*100/count;
1267// kdDebug() << "Recalc: " << percent << "%" << endl;
1268 }
1269 }
1270
1271 // emitEndOperation();
1272 emit sig_updateView( this );
1273}
1274
1275void Sheet::valueChanged (Cell *cell)
1276{
1277
1278 //TODO: call cell updating, when cell damaging implemented
1279
1280 //prepare the Point structure
1281 Point c;
1282 c.setRow (cell->row());
1283 c.setColumn (cell->column());
1284 c.setSheet( this );
1285
1286 //update dependencies
1287 if ( getAutoCalc() )
1288 d->dependencies->cellChanged (c);
1289
1290 //REMOVED - modification change - this was causing modified flag to be set inappropriately.
1291 //nobody else seems to be setting the modified flag, so we do it here
1292// doc()->setModified (true);
1293}
1294
1295/*
1296 Methods working on selections:
1297
1298 TYPE A:
1299 { columns selected:
1300 for all rows with properties X,X':
1301 if default-cell create new cell
1302 }
1303 post undo object (always a UndoCellLayout; difference in title only)
1304 { rows selected:
1305 if condition Y clear properties X,X' of cells;
1306 set properties X,X' of rowformats
1307 emit complete update;
1308 }
1309 { columns selected:
1310 if condition Y clear properties X,X' of cells;
1311 set properties X,X' of columnformats;
1312 for all rows with properties X,X':
1313 create cells if necessary and set properties X,X'
1314 emit complete update;
1315 }
1316 { cells selected:
1317 for all cells with condition Y:
1318 create if necessary and set properties X,X' and do Z;
1319 emit update on selected region;
1320 }
1321
1322 USED in:
1323 setSelectionFont
1324 setSelectionSize
1325 setSelectionAngle
1326 setSelectionTextColor
1327 setSelectionBgColor
1328 setSelectionPercent
1329 borderAll
1330 borderRemove (exceptions: ### creates cells (why?), ### changes default cell if cell-regions selected?)
1331 setSelectionAlign
1332 setSelectionAlignY
1333 setSelectionMoneyFormat
1334 increaseIndent
1335 decreaseIndent
1336
1337 TYPE B:
1338 post undo object
1339 { rows selected:
1340 if condition Y do X with cells;
1341 emit update on selection;
1342 }
1343 { columns selected:
1344 if condition Y do X with cells;
1345 emit update on selection;
1346 }
1347 { cells selected:
1348 if condition Y do X with cells; create cell if non-default;
1349 emit update on selection;
1350 }
1351
1352 USED in:
1353 setSelectionUpperLower (exceptions: no undo; no create-if-default; ### modifies default-cell?)
1354 setSelectionFirstLetterUpper (exceptions: no undo; no create-if-default; ### modifies default-cell?)
1355 setSelectionVerticalText
1356 setSelectionComment
1357 setSelectionRemoveComment (exeception: no create-if-default and work only on non-default-cells for cell regions)
1358 setSelectionBorderColor (exeception: no create-if-default and work only on non-default-cells for cell regions)
1359 setSelectionMultiRow
1360 setSelectionPrecision
1361 clearTextSelection (exception: all only if !areaIsEmpty())
1362 clearValiditySelection (exception: all only if !areaIsEmpty())
1363 clearConditionalSelection (exception: all only if !areaIsEmpty())
1364 setConditional (exception: conditional after create-if-default for cell regions)
1365 setValidity (exception: conditional after create-if-default for cell regions)
1366
1367 OTHERS:
1368 borderBottom
1369 borderRight
1370 borderLeft
1371 borderTop
1372 borderOutline
1373 => these work only on some cells (at the border); undo only if cells affected; rest is similar to type A
1374 --> better not use CellWorker/workOnCells()
1375
1376 defaultSelection
1377 => similar to TYPE B, but works on columns/rows if complete columns/rows selected
1378 --> use emit_signal=false and return value of workOnCells to finish
1379
1380 getWordSpelling
1381 => returns text, no signal emitted, no cell-create, similar to TYPE B
1382 --> use emit_signal=false, create_if_default=false and type B
1383
1384 setWordSpelling
1385 => no signal emitted, no cell-create, similar to type B
1386 --> use emit_signal=false, create_if_default=false and type B
1387 */
1388
1389class UndoAction* Sheet::CellWorkerTypeA::createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
1390{
1391 TQString title = getUndoTitle();
1392 return new UndoCellFormat( doc, sheet, region, title );
1393}
1394
1395/*
1396Sheet::SelectionType Sheet::workOnCells( const TQPoint& _marker, CellWorker& worker )
1397{
1398 // see what is selected; if nothing, take marker position
1399 bool selected = ( m_rctSelection.left() != 0 );
1400 TQRect r( m_rctSelection );
1401 if ( !selected )
1402 r.setCoords( _marker.x(), _marker.y(), _marker.x(), _marker.y() );
1403
1404 // create cells in rows if complete columns selected
1405 Cell *cell;
1406 if ( !worker.type_B && selected && isColumnSelected() )
1407 {
1408 for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
1409 {
1410 if ( !rw->isDefault() && worker.testCondition( rw ) )
1411 {
1412 for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
1413 {
1414 cell = cellAt( i, rw->row() );
1415 if ( cell == d->defaultCell )
1416 // '&& worker.create_if_default' unnecessary as never used in type A
1417 {
1418 cell = new Cell( this, i, rw->row() );
1419 insertCell( cell );
1420 }
1421 }
1422 }
1423 }
1424 }
1425
1426 // create an undo action
1427 if ( !doc()->undoLocked() )
1428 {
1429 UndoAction *undo = worker.createUndoAction( doc(), this, r );
1430 // test if the worker has an undo action
1431 if ( undo != 0L )
1432 doc()->addCommand( undo );
1433 }
1434
1435 // complete rows selected ?
1436 if ( selected && isRowSelected() )
1437 {
1438 int row;
1439 for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
1440 {
1441 row = cell->row();
1442 if ( m_rctSelection.top() <= row && m_rctSelection.bottom() >= row
1443 && worker.testCondition( cell ) )
1444 if ( worker.type_B )
1445 worker.doWork( cell, false, cell->column(), row );
1446 else
1447 worker.prepareCell( cell );
1448 }
1449
1450 if ( worker.type_B ) {
1451 // for type B there's nothing left to do
1452 if ( worker.emit_signal )
1453 emit sig_updateView( this, r );
1454 } else {
1455 // for type A now work on row formats
1456 for ( int i=m_rctSelection.top(); i<=m_rctSelection.bottom(); i++ )
1457 {
1458 RowFormat *rw=nonDefaultRowFormat(i);
1459 worker.doWork( rw );
1460 }
1461 if ( worker.emit_signal )
1462 emit sig_updateView( this );
1463 }
1464 return CompleteRows;
1465 }
1466 // complete columns selected ?
1467 else if ( selected && isColumnSelected() )
1468 {
1469 int col;
1470 for ( Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell() )
1471 {
1472 col = cell->column();
1473 if ( m_rctSelection.left() <= col && m_rctSelection.right() >= col
1474 && worker.testCondition( cell ) )
1475 if ( worker.type_B )
1476 worker.doWork( cell, false, col, cell->row() );
1477 else
1478 worker.prepareCell( cell );
1479 }
1480
1481 if ( worker.type_B ) {
1482 if ( worker.emit_signal )
1483 emit sig_updateView( this, r );
1484 } else {
1485 // for type A now work on column formats
1486 for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
1487 {
1488 ColumnFormat *cl=nonDefaultColumnFormat(i);
1489 worker.doWork( cl );
1490 }
1491 Cell *cell;
1492 for ( RowFormat* rw =d->rows.first(); rw; rw = rw->next() )
1493 {
1494 if ( !rw->isDefault() && worker.testCondition( rw ) )
1495 {
1496 for ( int i=m_rctSelection.left(); i<=m_rctSelection.right(); i++ )
1497 {
1498 cell = cellAt( i, rw->row() );
1499 // ### this if should be not necessary; cells are created
1500 // before the undo object is created, aren't they?
1501 if ( cell == d->defaultCell )
1502 {
1503 cell = new Cell( this, i, rw->row() );
1504 insertCell( cell );
1505 }
1506 worker.doWork( cell, false, i, rw->row() );
1507 }
1508 }
1509 }
1510 if ( worker.emit_signal )
1511 emit sig_updateView( this );
1512 }
1513 return CompleteColumns;
1514 }
1515 // cell region selected
1516 else
1517 {
1518 Cell *cell;
1519 for ( int x = r.left(); x <= r.right(); x++ )
1520 for ( int y = r.top(); y <= r.bottom(); y++ )
1521 {
1522 cell = cellAt( x, y );
1523 if ( worker.testCondition( cell ) )
1524 {
1525 if ( worker.create_if_default && cell == d->defaultCell )
1526 {
1527 cell = new Cell( this, x, y );
1528 insertCell( cell );
1529 }
1530 if ( cell != d->defaultCell )
1531 worker.doWork( cell, true, x, y );
1532 }
1533 }
1534 if ( worker.emit_signal )
1535 emit sig_updateView( this, r );
1536 return CellRegion;
1537 }
1538}
1539
1540*/
1541
1542Sheet::SelectionType Sheet::workOnCells( Selection* selectionInfo, CellWorker & worker )
1543{
1544 Sheet::SelectionType result;
1545
1546 doc()->emitBeginOperation();
1547
1548 // see what is selected; if nothing, take marker position
1549 bool selected = !(selectionInfo->isSingular());
1550
1551 // create an undo action
1552 if ( !doc()->undoLocked() )
1553 {
1554 UndoAction* undo = worker.createUndoAction(doc(), this, *selectionInfo);
1555 // test if the worker has an undo action
1556 if ( undo != 0 )
1557 {
1558 doc()->addCommand( undo );
1559 }
1560 }
1561
1562 Region::ConstIterator endOfList(selectionInfo->constEnd());
1563 for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
1564 {
1565 // see what is selected; if nothing, take marker position
1566 TQRect range = (*it)->rect().normalize();
1567
1568 int top = range.top();
1569 int left = range.left();
1570 int bottom = range.bottom();
1571 int right = range.right();
1572
1573 // create cells in rows if complete columns selected
1574 Cell * cell;
1575 Style * s = doc()->styleManager()->defaultStyle();
1576
1577 if ( !worker.type_B && selected && util_isColumnSelected(range) )
1578 {
1579 for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
1580 {
1581 if ( worker.testCondition( rw ) )
1582 {
1583 for ( int col = left; col <= right; ++col )
1584 {
1585 cell = nonDefaultCell( col, rw->row(), false, s );
1586 }
1587 }
1588 }
1589 }
1590
1591 // complete rows selected ?
1592 if ( selected && util_isRowSelected(range) )
1593 {
1594 for ( int row = top; row <= bottom; ++row )
1595 {
1596 cell = getFirstCellRow( row );
1597 while ( cell )
1598 {
1599 if ( worker.testCondition( cell ) )
1600 {
1601 if ( worker.type_B )
1602 worker.doWork( cell, false, cell->column(), row );
1603 else
1604 worker.prepareCell( cell );
1605 }
1606 cell = getNextCellRight( cell->column(), row );
1607 }
1608 }
1609
1610 if ( worker.type_B )
1611 {
1612 // for type B there's nothing left to do
1613 ;
1614 }
1615 else
1616 {
1617 // for type A now work on row formats
1618 for ( int i = top; i <= bottom; ++i )
1619 {
1620 RowFormat * rw = nonDefaultRowFormat(i);
1621 worker.doWork( rw );
1622 }
1623
1624 for ( int row = top; row <= bottom; ++row )
1625 {
1626 cell = getFirstCellRow( row );
1627 while ( cell )
1628 {
1629 if ( worker.testCondition( cell ) )
1630 {
1631 worker.doWork( cell, false, cell->column(), row );
1632 }
1633 cell = getNextCellRight( cell->column(), row );
1634 }
1635 }
1636
1637 }
1638 result = CompleteRows;
1639 }
1640 // complete columns selected ?
1641 else if ( selected && util_isColumnSelected(range) )
1642 {
1643 for ( int col = range.left(); col <= right; ++col )
1644 {
1645 cell = getFirstCellColumn( col );
1646 while ( cell )
1647 {
1648 if ( worker.testCondition( cell ) )
1649 {
1650 if ( worker.type_B )
1651 worker.doWork( cell, false, col, cell->row() );
1652 else
1653 worker.prepareCell( cell );
1654 }
1655
1656 cell = getNextCellDown( col, cell->row() );
1657 }
1658 }
1659
1660 if ( worker.type_B )
1661 {
1662 ;
1663 }
1664 else
1665 {
1666 // for type A now work on column formats
1667 for ( int i = left; i <= right; ++i )
1668 {
1669 ColumnFormat * cl = nonDefaultColumnFormat( i );
1670 worker.doWork( cl );
1671 }
1672
1673 for ( RowFormat * rw = d->rows.first(); rw; rw = rw->next() )
1674 {
1675 if ( worker.testCondition( rw ) )
1676 {
1677 for ( int i = left; i <= right; ++i )
1678 {
1679 cell = nonDefaultCell( i, rw->row(), false, s );
1680 worker.doWork( cell, false, i, rw->row() );
1681 }
1682 }
1683 }
1684 }
1685 result = CompleteColumns;
1686 }
1687 // cell region selected
1688 else
1689 {
1690 for ( int x = left; x <= right; ++x )
1691 {
1692 enableScrollBarUpdates(false);
1693 for ( int y = top; y <= bottom; ++y )
1694 {
1695 cell = cellAt( x, y );
1696 if ( worker.testCondition( cell ) )
1697 {
1698 if ( cell == d->defaultCell && worker.create_if_default )
1699 {
1700 cell = new Cell( this, s, x, y );
1701 insertCell( cell );
1702 }
1703 if ( cell != d->defaultCell )
1704 {
1705 // kdDebug() << "not default" << endl;
1706 worker.doWork( cell, true, x, y );
1707 }
1708 }
1709 }
1710 enableScrollBarUpdates(true);
1711 checkRangeVBorder(bottom);
1712 }
1713 checkRangeHBorder(right);
1714 result = CellRegion;
1715 }
1716
1717 } // for Region::Elements
1718
1719 // emitEndOperation();
1720 emit sig_updateView( this );
1721
1722 if (worker.emit_signal)
1723 {
1724 emit sig_updateView( this, *selectionInfo );
1725 }
1726
1727 return result;
1728}
1729
1730void Sheet::setSelectionFont( Selection* selectionInfo,
1731 const char *_font, int _size,
1732 signed char _bold, signed char _italic,
1733 signed char _underline, signed char _strike)
1734{
1735 FontManipulator* manipulator = new FontManipulator();
1736 manipulator->setSheet(this);
1737 manipulator->setProperty(Format::PFont);
1738 manipulator->setFontFamily(_font);
1739 manipulator->setFontSize(_size);
1740 manipulator->setFontBold(_bold);
1741 manipulator->setFontItalic(_italic);
1742 manipulator->setFontStrike(_strike);
1743 manipulator->setFontUnderline(_underline);
1744 manipulator->add(*selectionInfo);
1745 manipulator->execute();
1746}
1747
1748void Sheet::setSelectionSize(Selection* selectionInfo,
1749 int _size)
1750{
1751 // TODO Stefan: Increase/Decrease font size still used?
1752 int size;
1753 Cell* c;
1754 TQPoint marker(selectionInfo->marker());
1755 c = cellAt(marker);
1756 size = c->format()->textFontSize(marker.x(), marker.y());
1757
1758 FontManipulator* manipulator = new FontManipulator();
1759 manipulator->setSheet(this);
1760 manipulator->setProperty(Format::PFont);
1761 manipulator->setFontSize(_size+size);
1762 manipulator->add(*selectionInfo);
1763 manipulator->execute();
1764}
1765
1766
1767struct SetSelectionUpperLowerWorker : public Sheet::CellWorker {
1768 int _type;
1769 Sheet * _s;
1770 SetSelectionUpperLowerWorker( int type, Sheet * s )
1771 : Sheet::CellWorker( false ), _type( type ), _s( s ) { }
1772
1773 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region )
1774 {
1775 return new UndoChangeAreaTextCell( doc, sheet, region );
1776 }
1777 bool testCondition( Cell* c ) {
1778 return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
1779 && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
1780 && !c->isPartOfMerged() );
1781 }
1782 void doWork( Cell* cell, bool, int, int )
1783 {
1784 cell->setDisplayDirtyFlag();
1785 if ( _type == -1 )
1786 cell->setCellText( (cell->text().lower()));
1787 else if ( _type == 1 )
1788 cell->setCellText( (cell->text().upper()));
1789 cell->clearDisplayDirtyFlag();
1790 }
1791};
1792
1793void Sheet::setSelectionUpperLower( Selection* selectionInfo,
1794 int _type )
1795{
1796 SetSelectionUpperLowerWorker w( _type, this );
1797 workOnCells( selectionInfo, w );
1798}
1799
1800
1801struct SetSelectionFirstLetterUpperWorker : public Sheet::CellWorker
1802{
1803 Changes * _c;
1804 Sheet * _s;
1805 SetSelectionFirstLetterUpperWorker( Sheet * s )
1806 : Sheet::CellWorker( false ), _s( s ) { }
1807
1808 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
1809 return new UndoChangeAreaTextCell( doc, sheet, region );
1810 }
1811 bool testCondition( Cell* c ) {
1812 return ( !c->value().isNumber() && !c->value().isBoolean() &&!c->isFormula() && !c->isDefault()
1813 && !c->text().isEmpty() && c->text()[0] != '*' && c->text()[0] != '!'
1814 && !c->isPartOfMerged() );
1815 }
1816 void doWork( Cell* cell, bool, int, int )
1817 {
1818
1819 cell->setDisplayDirtyFlag();
1820 TQString tmp = cell->text();
1821 int len = tmp.length();
1822 cell->setCellText( (tmp.at(0).upper()+tmp.right(len-1)) );
1823 cell->clearDisplayDirtyFlag();
1824 }
1825};
1826
1827void Sheet::setSelectionfirstLetterUpper( Selection* selectionInfo)
1828{
1829 SetSelectionFirstLetterUpperWorker w( this );
1830 workOnCells( selectionInfo, w );
1831}
1832
1833
1834struct SetSelectionVerticalTextWorker : public Sheet::CellWorker {
1835 bool _b;
1836 SetSelectionVerticalTextWorker( bool b ) : Sheet::CellWorker( ), _b( b ) { }
1837
1838 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
1839 TQString title=i18n("Vertical Text");
1840 return new UndoCellFormat( doc, sheet, region, title );
1841 }
1842 bool testCondition( Cell* cell ) {
1843 return ( !cell->isPartOfMerged() );
1844 }
1845 void doWork( Cell* cell, bool, int, int ) {
1846 cell->setDisplayDirtyFlag();
1847 cell->format()->setVerticalText( _b );
1848 cell->format()->setMultiRow( false );
1849 cell->format()->setAngle( 0 );
1850 cell->clearDisplayDirtyFlag();
1851 }
1852};
1853
1854void Sheet::setSelectionVerticalText( Selection* selectionInfo,
1855 bool _b )
1856{
1857 SetSelectionVerticalTextWorker w( _b );
1858 workOnCells( selectionInfo, w );
1859}
1860
1861
1862struct SetSelectionCommentWorker : public Sheet::CellWorker {
1863 TQString _comment;
1864 SetSelectionCommentWorker( TQString comment ) : Sheet::CellWorker( ), _comment( comment ) { }
1865
1866 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
1867 TQString title=i18n("Add Comment");
1868 return new UndoCellFormat( doc, sheet, region, title );
1869 }
1870 bool testCondition( Cell* cell ) {
1871 return ( !cell->isPartOfMerged() );
1872 }
1873 void doWork( Cell* cell, bool, int, int ) {
1874 cell->setDisplayDirtyFlag();
1875 cell->format()->setComment( _comment );
1876 cell->clearDisplayDirtyFlag();
1877 }
1878};
1879
1880void Sheet::setSelectionComment( Selection* selectionInfo,
1881 const TQString &_comment)
1882{
1883 SetSelectionCommentWorker w( _comment );
1884 workOnCells( selectionInfo, w );
1885}
1886
1887
1888void Sheet::setSelectionAngle( Selection* selectionInfo,
1889 int _value )
1890{
1891 AngleManipulator* manipulator = new AngleManipulator();
1892 manipulator->setSheet(this);
1893 manipulator->setProperty(Format::PAngle);
1894 manipulator->setAngle(_value);
1895 manipulator->add(*selectionInfo);
1896 manipulator->execute();
1897}
1898
1899struct SetSelectionRemoveCommentWorker : public Sheet::CellWorker {
1900 SetSelectionRemoveCommentWorker( ) : Sheet::CellWorker( false ) { }
1901
1902 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
1903 TQString title=i18n("Remove Comment");
1904 return new UndoCellFormat( doc, sheet, region, title );
1905 }
1906 bool testCondition( Cell* cell ) {
1907 return ( !cell->isPartOfMerged() );
1908 }
1909 void doWork( Cell* cell, bool, int, int ) {
1910 cell->setDisplayDirtyFlag();
1911 cell->format()->setComment( "" );
1912 cell->clearDisplayDirtyFlag();
1913 }
1914};
1915
1916void Sheet::setSelectionRemoveComment( Selection* selectionInfo )
1917{
1918 if (areaIsEmpty(*selectionInfo, Comment))
1919 return;
1920
1921 SetSelectionRemoveCommentWorker w;
1922 workOnCells( selectionInfo, w );
1923}
1924
1925
1926void Sheet::setSelectionTextColor( Selection* selectionInfo,
1927 const TQColor &tb_Color )
1928{
1929 FontColorManipulator* manipulator = new FontColorManipulator();
1930 manipulator->setSheet(this);
1931 manipulator->setProperty(Format::PTextPen);
1932 manipulator->setTextColor(tb_Color);
1933 manipulator->add(*selectionInfo);
1934 manipulator->execute();
1935}
1936
1937void Sheet::setSelectionbgColor( Selection* selectionInfo,
1938 const TQColor &bg_Color )
1939{
1940 BackgroundColorManipulator* manipulator = new BackgroundColorManipulator();
1941 manipulator->setSheet(this);
1942 manipulator->setProperty(Format::PBackgroundColor);
1943 manipulator->setBackgroundColor(bg_Color);
1944 manipulator->add(*selectionInfo);
1945 manipulator->execute();
1946}
1947
1948
1949struct SetSelectionBorderColorWorker : public Sheet::CellWorker {
1950 const TQColor& bd_Color;
1951 SetSelectionBorderColorWorker( const TQColor& _bd_Color ) : Sheet::CellWorker( false ), bd_Color( _bd_Color ) { }
1952
1953 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
1954 TQString title=i18n("Change Border Color");
1955 return new UndoCellFormat( doc, sheet, region, title );
1956 }
1957 bool testCondition( Cell* cell ) {
1958 return ( !cell->isPartOfMerged() );
1959 }
1960 void doWork( Cell* cell, bool, int, int ) {
1961 cell->setDisplayDirtyFlag();
1962 int it_Row = cell->row();
1963 int it_Col = cell->column();
1964 if ( cell->format()->topBorderStyle( it_Row, it_Col )!=TQt::NoPen )
1965 cell->format()->setTopBorderColor( bd_Color );
1966 if ( cell->format()->leftBorderStyle( it_Row, it_Col )!=TQt::NoPen )
1967 cell->format()->setLeftBorderColor( bd_Color );
1968 if ( cell->format()->fallDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
1969 cell->format()->setFallDiagonalColor( bd_Color );
1970 if ( cell->format()->goUpDiagonalStyle( it_Row, it_Col )!=TQt::NoPen )
1971 cell->format()->setGoUpDiagonalColor( bd_Color );
1972 if ( cell->format()->bottomBorderStyle( it_Row, it_Col )!=TQt::NoPen )
1973 cell->format()->setBottomBorderColor( bd_Color );
1974 if ( cell->format()->rightBorderStyle( it_Row, it_Col )!=TQt::NoPen )
1975 cell->format()->setRightBorderColor( bd_Color );
1976 cell->clearDisplayDirtyFlag();
1977 }
1978};
1979
1980void Sheet::setSelectionBorderColor( Selection* selectionInfo,
1981 const TQColor &bd_Color )
1982{
1983 SetSelectionBorderColorWorker w( bd_Color );
1984 workOnCells( selectionInfo, w );
1985}
1986
1987
1988void Sheet::setSeries( const TQPoint &_marker, double start, double end, double step, Series mode, Series type)
1989{
1990 doc()->emitBeginOperation();
1991
1992 TQString cellText;
1993
1994 int x,y; /* just some loop counters */
1995
1996 /* the actual number of columns or rows that the series will span.
1997 i.e. this will count 3 cells for a single cell that spans three rows
1998 */
1999 int numberOfCells;
2000 if (end > start)
2001 numberOfCells = (int) ((end - start) / step + 1); /*initialize for linear*/
2002 else if ( end <start )
2003 numberOfCells = (int) ((start - end) / step + 1); /*initialize for linear*/
2004 else //equal ! => one cell fix infini loop
2005 numberOfCells = 1;
2006 if (type == Geometric)
2007 {
2008 /* basically, A(n) = start ^ n
2009 * so when does end = start ^ n ??
2010 * when n = ln(end) / ln(start)
2011 */
2012 numberOfCells = (int)( (log((double)end) / log((double)start)) +
2013 DBL_EPSILON) + 1;
2014 }
2015
2016 Cell * cell = NULL;
2017
2018 /* markers for the top-left corner of the undo region. It'll probably
2019 * be the top left corner of where the series is, but if something in front
2020 * is obscuring the cell, then it needs to be part of the undo region */
2021 TQRect undoRegion;
2022
2023 undoRegion.setLeft(_marker.x());
2024 undoRegion.setTop(_marker.y());
2025
2026 /* this whole block is used to find the correct size for the undo region.
2027 We're checking for two different things (in these examples,
2028 mode==column):
2029
2030 1. cells are vertically merged. This means that one value in the
2031 series will span multiple cells.
2032
2033 2. a cell in the column is merged to a cell to its left. In this case
2034 the cell value will be stored in the left most cell so we need to
2035 extend the undo range to include that column.
2036 */
2037 if ( mode == Column )
2038 {
2039 for ( y = _marker.y(); y <= (_marker.y() + numberOfCells - 1) && y <= KS_rowMax; y++ )
2040 {
2041 cell = cellAt( _marker.x(), y );
2042
2043 if ( cell->isPartOfMerged() )
2044 {
2045 /* case 2. */
2046 cell = cell->obscuringCells().first();
2047 undoRegion.setLeft(TQMIN(undoRegion.left(), cell->column()));
2048 }
2049 /* case 1. Add the extra space to numberOfCells and then skip
2050 over the region. Note that because of the above if block 'cell'
2051 points to the correct cell in the case where both case 1 and 2
2052 are true
2053 */
2054 numberOfCells += cell->extraYCells();
2055 y += cell->extraYCells();
2056 }
2057 undoRegion.setRight( _marker.x() );
2058 undoRegion.setBottom( y - 1 );
2059
2060 checkRangeVBorder( undoRegion.bottom() );
2061 }
2062 else if(mode == Row)
2063 {
2064 for ( x = _marker.x(); x <=(_marker.x() + numberOfCells - 1) && x <= KS_colMax; x++ )
2065 {
2066 /* see the code above for a column series for a description of
2067 what is going on here. */
2068 cell = cellAt( x,_marker.y(), false );
2069
2070 if ( cell->isPartOfMerged() )
2071 {
2072 cell = cell->obscuringCells().first();
2073 undoRegion.setTop(TQMIN(undoRegion.top(), cell->row()));
2074 }
2075 numberOfCells += cell->extraXCells();
2076 x += cell->extraXCells();
2077 }
2078 undoRegion.setBottom( _marker.y() );
2079 undoRegion.setRight( x - 1 );
2080
2081 checkRangeHBorder( undoRegion.right() );
2082 }
2083
2084 kdDebug() << "Saving undo information" << endl;
2085
2086 if ( !doc()->undoLocked() )
2087 {
2088 UndoChangeAreaTextCell *undo = new
2089 UndoChangeAreaTextCell( doc(), this, undoRegion );
2090 doc()->addCommand( undo );
2091 }
2092
2093 kdDebug() << "Saving undo information done" << endl;
2094
2095 setRegionPaintDirty( undoRegion );
2096
2097 x = _marker.x();
2098 y = _marker.y();
2099
2100 /* now we're going to actually loop through and set the values */
2101 double incr;
2102 Style * s = doc()->styleManager()->defaultStyle();
2103 if (step >= 0 && start < end)
2104 {
2105 for ( incr = start; incr <= end; )
2106 {
2107 cell = nonDefaultCell( x, y, false, s );
2108
2109 if ( cell->isPartOfMerged() )
2110 {
2111 cell = cell->obscuringCells().first();
2112 }
2113
2114 // cell->setCellText(cellText.setNum( incr ));
2115
2116 cell->setNumber( incr );
2117 if (mode == Column)
2118 {
2119 ++y;
2120 if (cell->doesMergeCells())
2121 {
2122 y += cell->extraYCells();
2123 }
2124 if ( y > KS_rowMax )
2125 {
2126 break;
2127 }
2128 }
2129 else if (mode == Row)
2130 {
2131 ++x;
2132 if (cell->doesMergeCells())
2133 {
2134 x += cell->extraXCells();
2135 }
2136 if ( x > KS_colMax )
2137 {
2138 break;
2139 }
2140 }
2141 else
2142 {
2143 kdDebug(36001) << "Error in Series::mode" << endl;
2144 return;
2145 }
2146
2147 if (type == Linear)
2148 incr = incr + step;
2149 else if (type == Geometric)
2150 incr = incr * step;
2151 else
2152 {
2153 kdDebug(36001) << "Error in Series::type" << endl;
2154 return;
2155 }
2156 }
2157 }
2158 else
2159 if (step >= 0 && start > end)
2160 {
2161 for ( incr = start; incr >= end; )
2162 {
2163 cell = nonDefaultCell( x, y, false, s );
2164
2165 if (cell->isPartOfMerged())
2166 {
2167 cell = cell->obscuringCells().first();
2168 }
2169
2170 // cell->setCellText(cellText.setNum( incr ));
2171 cell->setNumber( incr );
2172 if (mode == Column)
2173 {
2174 ++y;
2175 if (cell->doesMergeCells())
2176 {
2177 y += cell->extraYCells();
2178 }
2179 if ( y > KS_rowMax )
2180 {
2181 break;
2182 }
2183 }
2184 else if (mode == Row)
2185 {
2186 ++x;
2187 if (cell->doesMergeCells())
2188 {
2189 x += cell->extraXCells();
2190 }
2191 if ( x > KS_colMax )
2192 {
2193 break;
2194 }
2195 }
2196 else
2197 {
2198 kdDebug(36001) << "Error in Series::mode" << endl;
2199 return;
2200 }
2201
2202 if (type == Linear)
2203 incr = incr + step;
2204 else if (type == Geometric)
2205 incr = incr * step;
2206 else
2207 {
2208 kdDebug(36001) << "Error in Series::type" << endl;
2209 return;
2210 }
2211 }
2212 }
2213 else
2214 {
2215 for ( incr = start; incr <= end; )
2216 {
2217 cell = nonDefaultCell( x, y, false, s );
2218
2219 if (cell->isPartOfMerged())
2220 {
2221 cell = cell->obscuringCells().first();
2222 }
2223
2224 //cell->setCellText(cellText.setNum( incr ));
2225 cell->setNumber( incr );
2226 if (mode == Column)
2227 {
2228 ++y;
2229 if (cell->doesMergeCells())
2230 {
2231 y += cell->extraYCells();
2232 }
2233 if ( y > KS_rowMax )
2234 {
2235 break;
2236 }
2237 }
2238 else if (mode == Row)
2239 {
2240 ++x;
2241 if (cell->doesMergeCells())
2242 {
2243 x += cell->extraXCells();
2244 }
2245 if ( x > KS_colMax )
2246 {
2247 break;
2248 }
2249 }
2250 else
2251 {
2252 kdDebug(36001) << "Error in Series::mode" << endl;
2253 return;
2254 }
2255
2256 if (type == Linear)
2257 incr = incr + step;
2258 else if (type == Geometric)
2259 {
2260
2261 incr = incr * step;
2262 //a step = 1 into geometric serie is not good
2263 //we don't increase value => infini loop
2264 if (step == 1)
2265 return;
2266 }
2267 else
2268 {
2269 kdDebug(36001) << "Error in Series::type" << endl;
2270 return;
2271 }
2272 }
2273 }
2274
2275
2276 // doc()->emitEndOperation();
2277 emit sig_updateView( this );
2278}
2279
2280
2281struct SetSelectionPercentWorker : public Sheet::CellWorkerTypeA
2282{
2283 bool b;
2284 SetSelectionPercentWorker( bool _b ) : b( _b ) { }
2285
2286 TQString getUndoTitle() { return i18n("Format Percent"); }
2287 bool testCondition( RowFormat* ) {
2288 //TODO: no idea what to put here, now that factor's gone :(
2289 return ( true );
2290 }
2291 void doWork( RowFormat* rw ) {
2292 //rw->setPrecision( 0 );
2293 rw->setFormatType( b ? Percentage_format : Generic_format);
2294 }
2295 void doWork( ColumnFormat* cl ) {
2296 cl->setFormatType( b ? Percentage_format : Generic_format);
2297 }
2298 void prepareCell( Cell* cell ) {
2299 cell->format()->clearProperty(Format::PFormatType);
2300 cell->format()->clearNoFallBackProperties( Format::PFormatType );
2301 }
2302 bool testCondition( Cell* cell ) {
2303 return ( !cell->isPartOfMerged() );
2304 }
2305 void doWork( Cell* cell, bool cellRegion, int, int ) {
2306 if ( cellRegion )
2307 cell->setDisplayDirtyFlag();
2308 cell->format()->setFormatType( b ? Percentage_format : Generic_format);
2309 if ( cellRegion )
2310 cell->clearDisplayDirtyFlag();
2311 }
2312};
2313
2314void Sheet::setSelectionPercent( Selection* selectionInfo, bool b )
2315{
2316 SetSelectionPercentWorker w( b );
2317 workOnCells( selectionInfo, w );
2318}
2319
2320void Sheet::slotAreaModified (const TQString &name)
2321{
2322 d->dependencies->areaModified (name);
2323}
2324
2325
2326void Sheet::refreshRemoveAreaName(const TQString & _areaName)
2327{
2328 Cell * c = d->cells.firstCell();
2329 TQString tmp = "'" + _areaName + "'";
2330 for( ;c ; c = c->nextCell() )
2331 {
2332 if ( c->isFormula() )
2333 {
2334 if (c->text().find(tmp) != -1)
2335 {
2336 if ( !c->makeFormula() )
2337 kdError(36001) << "ERROR: Syntax ERROR" << endl;
2338 }
2339 }
2340 }
2341}
2342
2343void Sheet::refreshChangeAreaName(const TQString & _areaName)
2344{
2345 Cell * c = d->cells.firstCell();
2346 TQString tmp = "'" + _areaName + "'";
2347 for( ;c ; c = c->nextCell() )
2348 {
2349 if ( c->isFormula() )
2350 {
2351 if (c->text().find(tmp) != -1)
2352 {
2353 if ( !c->makeFormula() )
2354 kdError(36001) << "ERROR: Syntax ERROR" << endl;
2355 else
2356 {
2357 /* setting a cell calc dirty also sets it paint dirty */
2358 c->setCalcDirtyFlag();
2359 }
2360 }
2361 }
2362 }
2363}
2364
2365void Sheet::changeCellTabName( TQString const & old_name, TQString const & new_name )
2366{
2367 Cell* c = d->cells.firstCell();
2368 for( ;c; c = c->nextCell() )
2369 {
2370 if( c->isFormula() )
2371 {
2372 if(c->text().find(old_name)!=-1)
2373 {
2374 int nb = c->text().contains(old_name+"!");
2375 TQString tmp=old_name+"!";
2376 int len = tmp.length();
2377 tmp=c->text();
2378
2379 for( int i=0; i<nb; i++ )
2380 {
2381 int pos = tmp.find( old_name+"!" );
2382 tmp.replace( pos, len, new_name+"!" );
2383 }
2384 c->setCellText(tmp);
2385 }
2386 }
2387 }
2388}
2389
2390bool Sheet::shiftRow( const TQRect &rect,bool makeUndo )
2391{
2392 UndoInsertCellRow * undo = 0;
2393 if ( !doc()->undoLocked() &&makeUndo)
2394 {
2395 undo = new UndoInsertCellRow( doc(), this, rect );
2396 doc()->addCommand( undo );
2397 }
2398
2399 bool res=true;
2400 bool result;
2401 for( int i=rect.top(); i<=rect.bottom(); i++ )
2402 {
2403 for( int j=0; j<=(rect.right()-rect.left()); j++ )
2404 {
2405 result = d->cells.shiftRow( TQPoint(rect.left(),i) );
2406 if( !result )
2407 res=false;
2408 }
2409 }
2410 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2411 for( ; it.current(); ++it )
2412 {
2413 for(int i = rect.top(); i <= rect.bottom(); i++ )
2414 it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
2415 Sheet::ColumnInsert, name(),
2416 ( rect.right() - rect.left() + 1),
2417 undo);
2418 }
2419 refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnInsert);
2420 refreshMergedCell();
2421 recalc();
2422 emit sig_updateView( this );
2423
2424 return res;
2425}
2426
2427bool Sheet::shiftColumn( const TQRect& rect,bool makeUndo )
2428{
2429 UndoInsertCellCol * undo = 0;
2430 if ( !doc()->undoLocked() &&makeUndo)
2431 {
2432 undo = new UndoInsertCellCol( doc(), this,rect);
2433 doc()->addCommand( undo );
2434 }
2435
2436 bool res=true;
2437 bool result;
2438 for( int i =rect.left(); i<=rect.right(); i++ )
2439 {
2440 for( int j=0; j<=(rect.bottom()-rect.top()); j++ )
2441 {
2442 result = d->cells.shiftColumn( TQPoint(i,rect.top()) );
2443 if(!result)
2444 res=false;
2445 }
2446 }
2447
2448 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2449 for( ; it.current(); ++it )
2450 {
2451 for(int i=rect.left();i<=rect.right();i++)
2452 it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
2453 Sheet::RowInsert, name(),
2454 ( rect.bottom() - rect.top() + 1 ),
2455 undo );
2456 }
2457 refreshChart(/*marker*/TQPoint(rect.left(),rect.top()), false, Sheet::RowInsert);
2458 refreshMergedCell();
2459 recalc();
2460 emit sig_updateView( this );
2461
2462 return res;
2463}
2464
2465void Sheet::unshiftColumn( const TQRect & rect,bool makeUndo )
2466{
2467 UndoRemoveCellCol * undo = 0;
2468 if ( !doc()->undoLocked() && makeUndo )
2469 {
2470 undo = new UndoRemoveCellCol( doc(), this, rect );
2471 doc()->addCommand( undo );
2472 }
2473
2474 for(int i =rect.top();i<=rect.bottom();i++)
2475 for(int j=rect.left();j<=rect.right();j++)
2476 d->cells.remove(j,i);
2477
2478 for(int i =rect.left();i<=rect.right();i++)
2479 for(int j=0;j<=(rect.bottom()-rect.top());j++)
2480 d->cells.unshiftColumn( TQPoint(i,rect.top()) );
2481
2482 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2483 for( ; it.current(); ++it )
2484 for(int i=rect.left();i<=rect.right();i++)
2485 it.current()->changeNameCellRef( TQPoint( i, rect.top() ), false,
2486 Sheet::RowRemove, name(),
2487 ( rect.bottom() - rect.top() + 1 ),
2488 undo );
2489
2490 refreshChart( TQPoint(rect.left(),rect.top()), false, Sheet::RowRemove );
2491 refreshMergedCell();
2492 recalc();
2493 emit sig_updateView( this );
2494}
2495
2496void Sheet::unshiftRow( const TQRect & rect,bool makeUndo )
2497{
2498 UndoRemoveCellRow * undo = 0;
2499 if ( !doc()->undoLocked() && makeUndo )
2500 {
2501 undo = new UndoRemoveCellRow( doc(), this, rect );
2502 doc()->addCommand( undo );
2503 }
2504 for(int i =rect.top();i<=rect.bottom();i++)
2505 for(int j=rect.left();j<=rect.right();j++)
2506 d->cells.remove(j,i);
2507
2508 for(int i =rect.top();i<=rect.bottom();i++)
2509 for(int j=0;j<=(rect.right()-rect.left());j++)
2510 d->cells.unshiftRow( TQPoint(rect.left(),i) );
2511
2512 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2513 for( ; it.current(); ++it )
2514 for(int i=rect.top();i<=rect.bottom();i++)
2515 it.current()->changeNameCellRef( TQPoint( rect.left(), i ), false,
2516 Sheet::ColumnRemove, name(),
2517 ( rect.right() - rect.left() + 1 ),
2518 undo);
2519
2520 refreshChart(TQPoint(rect.left(),rect.top()), false, Sheet::ColumnRemove );
2521 refreshMergedCell();
2522 recalc();
2523 emit sig_updateView( this );
2524}
2525
2526bool Sheet::insertColumn( int col, int nbCol, bool makeUndo )
2527{
2528 UndoInsertColumn * undo = 0;
2529 if ( !doc()->undoLocked() && makeUndo)
2530 {
2531 undo = new UndoInsertColumn( doc(), this, col, nbCol );
2532 doc()->addCommand( undo );
2533 }
2534
2535 bool res=true;
2536 bool result;
2537 for( int i=0; i<=nbCol; i++ )
2538 {
2539 // Recalculate range max (minus size of last column)
2540 d->sizeMaxX -= columnFormat( KS_colMax )->dblWidth();
2541
2542 result = d->cells.insertColumn( col );
2543 d->columns.insertColumn( col );
2544 if(!result)
2545 res = false;
2546
2547 //Recalculate range max (plus size of new column)
2548 d->sizeMaxX += columnFormat( col+i )->dblWidth();
2549 }
2550
2551 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2552 for( ; it.current(); ++it )
2553 it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
2554 Sheet::ColumnInsert, name(),
2555 nbCol + 1, undo );
2556
2557 //update print settings
2558 d->print->insertColumn( col, nbCol );
2559
2560 refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnInsert );
2561 refreshMergedCell();
2562 recalc();
2563 emit sig_updateHBorder( this );
2564 emit sig_updateView( this );
2565
2566 return res;
2567}
2568
2569bool Sheet::insertRow( int row, int nbRow, bool makeUndo )
2570{
2571 UndoInsertRow *undo = 0;
2572 if ( !doc()->undoLocked() && makeUndo)
2573 {
2574 undo = new UndoInsertRow( doc(), this, row, nbRow );
2575 doc()->addCommand( undo );
2576 }
2577
2578 bool res=true;
2579 bool result;
2580 for( int i=0; i<=nbRow; i++ )
2581 {
2582 // Recalculate range max (minus size of last row)
2583 d->sizeMaxY -= rowFormat( KS_rowMax )->dblHeight();
2584
2585 result = d->cells.insertRow( row );
2586 d->rows.insertRow( row );
2587 if( !result )
2588 res = false;
2589
2590 //Recalculate range max (plus size of new row)
2591 d->sizeMaxY += rowFormat( row )->dblHeight();
2592 }
2593
2594 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2595 for( ; it.current(); ++it )
2596 it.current()->changeNameCellRef( TQPoint( 1, row ), true,
2597 Sheet::RowInsert, name(),
2598 nbRow + 1, undo );
2599
2600 //update print settings
2601 d->print->insertRow( row, nbRow );
2602
2603 refreshChart( TQPoint( 1, row ), true, Sheet::RowInsert );
2604 refreshMergedCell();
2605 recalc();
2606 emit sig_updateVBorder( this );
2607 emit sig_updateView( this );
2608
2609 return res;
2610}
2611
2612void Sheet::removeColumn( int col, int nbCol, bool makeUndo )
2613{
2614 UndoRemoveColumn *undo = 0;
2615 if ( !doc()->undoLocked() && makeUndo)
2616 {
2617 undo = new UndoRemoveColumn( doc(), this, col, nbCol );
2618 doc()->addCommand( undo );
2619 }
2620
2621 for ( int i = 0; i <= nbCol; ++i )
2622 {
2623 // Recalculate range max (minus size of removed column)
2624 d->sizeMaxX -= columnFormat( col )->dblWidth();
2625
2626 d->cells.removeColumn( col );
2627 d->columns.removeColumn( col );
2628
2629 //Recalculate range max (plus size of new column)
2630 d->sizeMaxX += columnFormat( KS_colMax )->dblWidth();
2631 }
2632
2633 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2634 for( ; it.current(); ++it )
2635 it.current()->changeNameCellRef( TQPoint( col, 1 ), true,
2636 Sheet::ColumnRemove, name(),
2637 nbCol + 1, undo );
2638
2639 //update print settings
2640 d->print->removeColumn( col, nbCol );
2641
2642 refreshChart( TQPoint( col, 1 ), true, Sheet::ColumnRemove );
2643 refreshMergedCell();
2644 recalc();
2645 emit sig_updateHBorder( this );
2646 emit sig_updateView( this );
2647}
2648
2649void Sheet::removeRow( int row, int nbRow, bool makeUndo )
2650{
2651 UndoRemoveRow *undo = 0;
2652 if ( !doc()->undoLocked() && makeUndo )
2653 {
2654 undo = new UndoRemoveRow( doc(), this, row, nbRow );
2655 doc()->addCommand( undo );
2656 }
2657
2658 for( int i=0; i<=nbRow; i++ )
2659 {
2660 // Recalculate range max (minus size of removed row)
2661 d->sizeMaxY -= rowFormat( row )->dblHeight();
2662
2663 d->cells.removeRow( row );
2664 d->rows.removeRow( row );
2665
2666 //Recalculate range max (plus size of new row)
2667 d->sizeMaxY += rowFormat( KS_rowMax )->dblHeight();
2668 }
2669
2670 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
2671 for( ; it.current(); ++it )
2672 it.current()->changeNameCellRef( TQPoint( 1, row ), true,
2673 Sheet::RowRemove, name(),
2674 nbRow + 1, undo );
2675
2676 //update print settings
2677 d->print->removeRow( row, nbRow );
2678
2679 refreshChart( TQPoint( 1, row ), true, Sheet::RowRemove );
2680 refreshMergedCell();
2681 recalc();
2682 emit sig_updateVBorder( this );
2683 emit sig_updateView( this );
2684}
2685
2686void Sheet::hideRow(const Region& region)
2687{
2688 HideShowManipulator* manipulator = new HideShowManipulator();
2689 manipulator->setSheet(this);
2690 manipulator->setManipulateRows(true);
2691 manipulator->add(region);
2692 manipulator->execute();
2693}
2694
2695void Sheet::emitHideRow()
2696{
2697 emit sig_updateVBorder( this );
2698 emit sig_updateView( this );
2699}
2700
2701void Sheet::showRow(const Region& region)
2702{
2703 HideShowManipulator* manipulator = new HideShowManipulator();
2704 manipulator->setSheet(this);
2705 manipulator->setManipulateRows(true);
2706 manipulator->setReverse(true);
2707 manipulator->add(region);
2708 manipulator->execute();
2709}
2710
2711
2712void Sheet::hideColumn(const Region& region)
2713{
2714 HideShowManipulator* manipulator = new HideShowManipulator();
2715 manipulator->setSheet(this);
2716 manipulator->setManipulateColumns(true);
2717 manipulator->add(region);
2718 manipulator->execute();
2719}
2720
2721void Sheet::emitHideColumn()
2722{
2723 emit sig_updateHBorder( this );
2724 emit sig_updateView( this );
2725}
2726
2727void Sheet::showColumn(const Region& region)
2728{
2729 HideShowManipulator* manipulator = new HideShowManipulator();
2730 manipulator->setSheet(this);
2731 manipulator->setManipulateColumns(true);
2732 manipulator->setReverse(true);
2733 manipulator->add(region);
2734 manipulator->execute();
2735}
2736
2737
2738void Sheet::refreshChart(const TQPoint & pos, bool fullRowOrColumn, ChangeRef ref)
2739{
2740 Cell * c = d->cells.firstCell();
2741 for( ;c; c = c->nextCell() )
2742 {
2743 if ( (ref == ColumnInsert || ref == ColumnRemove) && fullRowOrColumn
2744 && c->column() >= (pos.x() - 1))
2745 {
2746 if (c->updateChart())
2747 return;
2748 }
2749 else if ( (ref == ColumnInsert || ref == ColumnRemove )&& !fullRowOrColumn
2750 && c->column() >= (pos.x() - 1) && c->row() == pos.y() )
2751 {
2752 if (c->updateChart())
2753 return;
2754 }
2755 else if ((ref == RowInsert || ref == RowRemove) && fullRowOrColumn
2756 && c->row() >= (pos.y() - 1))
2757 {
2758 if (c->updateChart())
2759 return;
2760 }
2761 else if ( (ref == RowInsert || ref == RowRemove) && !fullRowOrColumn
2762 && c->column() == pos.x() && c->row() >= (pos.y() - 1) )
2763 {
2764 if (c->updateChart())
2765 return;
2766 }
2767 }
2768
2769 //refresh chart when there is a chart and you remove
2770 //all cells
2771 if (c == 0L)
2772 {
2773 CellBinding * bind;
2774 for ( bind = firstCellBinding(); bind != 0L; bind = nextCellBinding() )
2775 {
2776 bind->cellChanged( 0 );
2777 }
2778 // CellBinding * bind = firstCellBinding();
2779 // if ( bind != 0L )
2780 // bind->cellChanged( 0 );
2781 }
2782
2783}
2784
2785void Sheet::refreshMergedCell()
2786{
2787 Cell* c = d->cells.firstCell();
2788 for( ;c; c = c->nextCell() )
2789 {
2790 if(c->doesMergeCells())
2791 c->mergeCells( c->column(), c->row(), c->extraXCells(), c->extraYCells() );
2792 }
2793}
2794
2795
2796void Sheet::changeNameCellRef( const TQPoint & pos, bool fullRowOrColumn,
2797 ChangeRef ref, TQString tabname, int nbCol,
2798 UndoInsertRemoveAction * undo )
2799{
2800 bool correctDefaultSheetName = (tabname == name()); // for cells without sheet ref (eg "A1")
2801 Cell* c = d->cells.firstCell();
2802 for( ;c; c = c->nextCell() )
2803 {
2804 if( c->isFormula() )
2805 {
2806 TQString origText = c->text();
2807 unsigned int i = 0;
2808 bool error = false;
2809 TQString newText;
2810
2811 bool correctSheetName = correctDefaultSheetName;
2812 //bool previousCorrectSheetName = false;
2813 TQChar origCh;
2814 for ( ; i < origText.length(); ++i )
2815 {
2816 origCh = origText[i];
2817 if ( origCh != ':' && origCh != '$' && !origCh.isLetter() )
2818 {
2819 newText += origCh;
2820 // Reset the "correct table indicator"
2821 correctSheetName = correctDefaultSheetName;
2822 }
2823 else // Letter or dollar : maybe start of cell name/range
2824 // (or even ':', like in a range - note that correctSheet is kept in this case)
2825 {
2826 // Collect everything that forms a name (cell name or sheet name)
2827 TQString str;
2828 bool sheetNameFound = false; //Sheet names need spaces
2829 for( ; ( i < origText.length() ) && // until the end
2830 ( ( origText[i].isLetter() || origText[i].isDigit() || origText[i] == '$' ) || // all text and numbers are welcome
2831 ( sheetNameFound && origText[i].isSpace() ) ) //in case of a sheet name, we include spaces too
2832 ; ++i )
2833 {
2834 str += origText[i];
2835 if ( origText[i] == '!' )
2836 sheetNameFound = true;
2837 }
2838 // Was it a sheet name ?
2839 if ( origText[i] == '!' )
2840 {
2841 newText += str + '!'; // Copy it (and the '!')
2842 // Look for the sheet name right before that '!'
2843 correctSheetName = ( newText.right( tabname.length()+1 ) == tabname+"!" );
2844 }
2845 else // It must be a cell identifier
2846 {
2847 // Parse it
2848 Point point( str );
2849 if ( point.isValid() )
2850 {
2851 int col = point.pos().x();
2852 int row = point.pos().y();
2853 TQString newPoint;
2854
2855 // Update column
2856 if ( point.columnFixed() )
2857 newPoint = '$';
2858
2859 if( ref == ColumnInsert
2860 && correctSheetName
2861 && col + nbCol <= KS_colMax
2862 && col >= pos.x() // Column after the new one : +1
2863 && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
2864 {
2865 newPoint += Cell::columnName( col + nbCol );
2866 }
2867 else if( ref == ColumnRemove
2868 && correctSheetName
2869 && col > pos.x() // Column after the deleted one : -1
2870 && ( fullRowOrColumn || row == pos.y() ) ) // All rows or just one
2871 {
2872 newPoint += Cell::columnName( col - nbCol );
2873 }
2874 else
2875 newPoint += Cell::columnName( col );
2876
2877 // Update row
2878 if ( point.rowFixed() )
2879 newPoint += '$';
2880
2881 if( ref == RowInsert
2882 && correctSheetName
2883 && row + nbCol <= KS_rowMax
2884 && row >= pos.y() // Row after the new one : +1
2885 && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
2886 {
2887 newPoint += TQString::number( row + nbCol );
2888 }
2889 else if( ref == RowRemove
2890 && correctSheetName
2891 && row > pos.y() // Row after the deleted one : -1
2892 && ( fullRowOrColumn || col == pos.x() ) ) // All columns or just one
2893 {
2894 newPoint += TQString::number( row - nbCol );
2895 }
2896 else
2897 newPoint += TQString::number( row );
2898
2899 if( correctSheetName &&
2900 ( ( ref == ColumnRemove
2901 && col == pos.x() // Column is the deleted one : error
2902 && ( fullRowOrColumn || row == pos.y() ) ) ||
2903 ( ref == RowRemove
2904 && row == pos.y() // Row is the deleted one : error
2905 && ( fullRowOrColumn || col == pos.x() ) ) ||
2906 ( ref == ColumnInsert
2907 && col + nbCol > KS_colMax
2908 && col >= pos.x() // Column after the new one : +1
2909 && ( fullRowOrColumn || row == pos.y() ) ) ||
2910 ( ref == RowInsert
2911 && row + nbCol > KS_rowMax
2912 && row >= pos.y() // Row after the new one : +1
2913 && ( fullRowOrColumn || col == pos.x() ) ) ) )
2914 {
2915 newPoint = "#" + i18n("Dependency") + "!";
2916 error = true;
2917 }
2918
2919 newText += newPoint;
2920 }
2921 else // Not a cell ref
2922 {
2923 kdDebug(36001) << "Copying (unchanged) : '" << str << "'" << endl;
2924 newText += str;
2925 }
2926 // Copy the char that got us to stop
2927 if ( i < origText.length() ) {
2928 newText += origText[i];
2929 if( origText[i] != ':' )
2930 correctSheetName = correctDefaultSheetName;
2931 }
2932 }
2933 }
2934 }
2935
2936 if ( error && undo != 0 ) //Save the original formula, as we cannot calculate the undo of broken formulas
2937 {
2938 TQString formulaText = c->text();
2939 int origCol = c->column();
2940 int origRow = c->row();
2941
2942 if ( ref == ColumnInsert && origCol >= pos.x() )
2943 origCol -= nbCol;
2944 if ( ref == RowInsert && origRow >= pos.y() )
2945 origRow -= nbCol;
2946
2947 if ( ref == ColumnRemove && origCol >= pos.x() )
2948 origCol += nbCol;
2949 if ( ref == RowRemove && origRow >= pos.y() )
2950 origRow += nbCol;
2951
2952 undo->saveFormulaReference( this, origCol, origRow, formulaText );
2953 }
2954
2955 c->setCellText( newText );
2956 }
2957 }
2958}
2959
2960#if 0
2961void Sheet::replace( const TQString &_find, const TQString &_replace, long options,
2962 Canvas *canvas )
2963{
2964 Selection* selectionInfo = canvas->view()->selectionInfo();
2965
2966 // Identify the region of interest.
2967 TQRect region( selectionInfo->selection() );
2968 TQPoint marker( selectionInfo->marker() );
2969
2970 if (options & KReplaceDialog::SelectedText)
2971 {
2972
2973 // Complete rows selected ?
2974 if ( util_isRowSelected(region) )
2975 {
2976 }
2977 // Complete columns selected ?
2978 else if ( util_isColumnSelected(region) )
2979 {
2980 }
2981 }
2982 else
2983 {
2984 // All cells.
2985 region.setCoords( 1, 1, d->maxRow, d->maxColumn );
2986 }
2987
2988 // Create the class that handles all the actual replace stuff, and connect it to its
2989 // local slots.
2990 KReplace dialog( _find, _replace, options );
2991 TQObject::connect(
2992 &dialog, TQ_SIGNAL( highlight( const TQString &, int, int, const TQRect & ) ),
2993 canvas, TQ_SLOT( highlight( const TQString &, int, int, const TQRect & ) ) );
2994 TQObject::connect(
2995 &dialog, TQ_SIGNAL( replace( const TQString &, int, int,int, const TQRect & ) ),
2996 canvas, TQ_SLOT( replace( const TQString &, int, int,int, const TQRect & ) ) );
2997
2998 // Now do the replacing...
2999 if ( !doc()->undoLocked() )
3000 {
3001 UndoChangeAreaTextCell *undo = new UndoChangeAreaTextCell( doc(), this, region );
3002 doc()->addCommand( undo );
3003 }
3004
3005 TQRect cellRegion( 0, 0, 0, 0 );
3006 bool bck = options & KFindDialog::FindBackwards;
3007
3008 int colStart = !bck ? region.left() : region.right();
3009 int colEnd = !bck ? region.right() : region.left();
3010 int rowStart = !bck ? region.top() :region.bottom();
3011 int rowEnd = !bck ? region.bottom() : region.top();
3012 if ( options & KFindDialog::FromCursor ) {
3013 colStart = marker.x();
3014 rowStart = marker.y();
3015 }
3016 Cell *cell;
3017 for (int row = rowStart ; !bck ? row < rowEnd : row > rowEnd ; !bck ? ++row : --row )
3018 {
3019 for(int col = colStart ; !bck ? col < colEnd : col > colEnd ; !bck ? ++col : --col )
3020 {
3021 cell = cellAt( col, row );
3022 if ( !cell->isDefault() && !cell->isObscured() && !cell->isFormula() )
3023 {
3024 TQString text = cell->text();
3025 cellRegion.setTop( row );
3026 cellRegion.setLeft( col );
3027 if (!dialog.replace( text, cellRegion ))
3028 return;
3029 }
3030 }
3031 }
3032}
3033#endif
3034
3035void Sheet::borderBottom( Selection* selectionInfo, const TQColor &_color )
3036{
3037 BorderManipulator* manipulator = new BorderManipulator();
3038 manipulator->setSheet(this);
3039 manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
3040 manipulator->add(*selectionInfo);
3041 manipulator->execute();
3042}
3043
3044void Sheet::borderRight( Selection* selectionInfo, const TQColor &_color )
3045{
3046 BorderManipulator* manipulator = new BorderManipulator();
3047 manipulator->setSheet(this);
3048 manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
3049 manipulator->add(*selectionInfo);
3050 manipulator->execute();
3051}
3052
3053void Sheet::borderLeft( Selection* selectionInfo, const TQColor &_color )
3054{
3055 BorderManipulator* manipulator = new BorderManipulator();
3056 manipulator->setSheet(this);
3057 manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
3058 manipulator->add(*selectionInfo);
3059 manipulator->execute();
3060}
3061
3062void Sheet::borderTop( Selection* selectionInfo, const TQColor &_color )
3063{
3064 BorderManipulator* manipulator = new BorderManipulator();
3065 manipulator->setSheet(this);
3066 manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
3067 manipulator->add(*selectionInfo);
3068 manipulator->execute();
3069}
3070
3071void Sheet::borderOutline( Selection* selectionInfo, const TQColor &_color )
3072{
3073 BorderManipulator* manipulator = new BorderManipulator();
3074 manipulator->setSheet(this);
3075 manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
3076 manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
3077 manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
3078 manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
3079 manipulator->add(*selectionInfo);
3080 manipulator->execute();
3081}
3082
3083void Sheet::borderAll( Selection * selectionInfo,
3084 const TQColor & _color )
3085{
3086 BorderManipulator* manipulator = new BorderManipulator();
3087 manipulator->setSheet(this);
3088 manipulator->setTopBorderPen(TQPen(_color, 1, TQt::SolidLine));
3089 manipulator->setBottomBorderPen(TQPen(_color, 1, TQt::SolidLine));
3090 manipulator->setLeftBorderPen(TQPen(_color, 1, TQt::SolidLine));
3091 manipulator->setRightBorderPen(TQPen(_color, 1, TQt::SolidLine));
3092 manipulator->setHorizontalPen(TQPen(_color, 1, TQt::SolidLine));
3093 manipulator->setVerticalPen(TQPen(_color, 1, TQt::SolidLine));
3094 manipulator->add(*selectionInfo);
3095 manipulator->execute();
3096}
3097
3098void Sheet::borderRemove( Selection* selectionInfo )
3099{
3100 BorderManipulator* manipulator = new BorderManipulator();
3101 manipulator->setSheet(this);
3102 manipulator->setTopBorderPen(TQPen(TQt::NoPen));
3103 manipulator->setBottomBorderPen(TQPen(TQt::NoPen));
3104 manipulator->setLeftBorderPen(TQPen(TQt::NoPen));
3105 manipulator->setRightBorderPen(TQPen(TQt::NoPen));
3106 manipulator->setHorizontalPen(TQPen(TQt::NoPen));
3107 manipulator->setVerticalPen(TQPen(TQt::NoPen));
3108 manipulator->add(*selectionInfo);
3109 manipulator->execute();
3110}
3111
3112
3113void Sheet::sortByRow( const TQRect &area, int ref_row, SortingOrder mode )
3114{
3115 Point point;
3116 point.setSheet(this);
3117 point.setSheetName (d->name);
3118 point.setPos(area.topLeft());
3119 point.setColumnFixed(false);
3120 point.setRowFixed(false);
3121
3122 sortByRow( area, ref_row, 0, 0, mode, mode, mode, 0, false, false, point,true );
3123}
3124
3125void Sheet::sortByColumn( const TQRect &area, int ref_column, SortingOrder mode )
3126{
3127 Point point;
3128 point.setSheet(this);
3129 point.setSheetName(d->name);
3130 point.setPos(area.topLeft());
3131 point.setColumnFixed(false);
3132 point.setRowFixed(false);
3133
3134 sortByColumn( area, ref_column, 0, 0, mode, mode, mode, 0, false, false,
3135 point,true );
3136}
3137
3138void Sheet::checkCellContent(Cell * cell1, Cell * cell2, int & ret)
3139{
3140 if ( cell1->isEmpty() )
3141 {
3142 ret = 1;
3143 return;
3144 }
3145 else if ( cell1->isObscured() && cell1->isPartOfMerged() )
3146 {
3147 ret = 1;
3148 return;
3149 }
3150 else if ( cell2->isEmpty() )
3151 {
3152 ret = 2;
3153 return;
3154 }
3155 ret = 0;
3156}
3157
3158void Sheet::sortByRow( const TQRect &area, int key1, int key2, int key3,
3159 SortingOrder order1, SortingOrder order2,
3160 SortingOrder order3,
3161 TQStringList const * firstKey, bool copyFormat,
3162 bool headerRow, Point const & outputPoint, bool respectCase )
3163{
3164 TQRect r( area );
3165 Map::respectCase = respectCase;
3166 Q_ASSERT( order1 == Increase || order1 == Decrease );
3167
3168 // It may not happen that entire columns are selected.
3169 Q_ASSERT( util_isColumnSelected(r) == false );
3170
3171 // Are entire rows selected ?
3172 if ( util_isRowSelected(r) )
3173 {
3174 r.setLeft( KS_colMax );
3175 r.setRight( 0 );
3176
3177 // Determine a correct left and right.
3178 // Iterate over all cells to find out which cells are
3179 // located in the selected rows.
3180 for ( int row = r.top(); row <= r.bottom(); ++row )
3181 {
3182 Cell * c = getFirstCellRow( row );
3183 int col;
3184 while ( c )
3185 {
3186 col = c->column();
3187 if ( !c->isEmpty() )
3188 {
3189 if ( col > r.right() )
3190 r.rRight() = col;
3191 if ( col < r.left() )
3192 r.rLeft() = col;
3193 }
3194 c = getNextCellRight( col, row );
3195 }
3196 }
3197
3198 // Any cells to sort here ?
3199 if ( r.right() < r.left() )
3200 {
3201 Map::respectCase = true;
3202 return;
3203 }
3204 }
3205
3206 TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
3207
3208 doc()->emitBeginOperation();
3209
3210 if ( !doc()->undoLocked() )
3211 {
3212 UndoSort *undo = new UndoSort( doc(), this, target );
3213 doc()->addCommand( undo );
3214 }
3215
3216 if (target.topLeft() != r.topLeft())
3217 {
3218 int targetLeft = target.left();
3219 int targetTop = target.top();
3220 int sourceTop = r.top();
3221 int sourceLeft = r.left();
3222
3223 key1 = key1 - sourceTop + targetTop;
3224 key2 = key2 - sourceTop + targetTop;
3225 key3 = key3 - sourceTop + targetTop;
3226
3227 for ( int x = 0; x < r.width(); ++x)
3228 {
3229 for ( int y = 0; y < r.height(); ++y )
3230 {
3231 // from - to
3232 copyCells( sourceLeft + x, sourceTop + y,
3233 targetLeft + x, targetTop + y, copyFormat );
3234 }
3235 }
3236 }
3237
3238 // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
3239 // For each column, we look for all cells right hand of it and we find the one to swap with it.
3240 // Much faster than the awful bubbleSort...
3241 Cell * cell;
3242 Cell * cell1;
3243 Cell * cell2;
3244 Cell * bestCell;
3245 int status = 0;
3246
3247 for ( int d = target.left(); d <= target.right(); ++d )
3248 {
3249 cell1 = cellAt( d, key1 );
3250 if ( cell1->isObscured() && cell1->isPartOfMerged() )
3251 {
3252 Cell* obscuring = cell1->obscuringCells().first();
3253 cell = cellAt( obscuring->column(), key1 );
3254 cell1 = cellAt( obscuring->column() + cell->extraXCells() + 1,
3255 obscuring->column());
3256 d = obscuring->column() + cell->extraXCells() + 1;
3257 }
3258
3259 // Look for which column we want to swap with the one number d
3260 bestCell = cell1;
3261 int bestX = d;
3262 for ( int x = d + 1 ; x <= target.right(); x++ )
3263 {
3264 cell2 = cellAt( x, key1 );
3265
3266 checkCellContent(cell2, bestCell, status);
3267 if (status == 1)
3268 continue;
3269 else if (status == 2)
3270 {
3271 // empty cells are always shifted to the end
3272 bestCell = cell2;
3273 bestX = x;
3274 continue;
3275 }
3276
3277 if ( firstKey )
3278 {
3279 int i1 = firstKey->findIndex( cell2->text() );
3280 int i2 = firstKey->findIndex( bestCell->text() );
3281
3282 if ( i1 != -1 && i2 != -1 )
3283 {
3284 if ( (order1 == Increase && i1 < i2 )
3285 || (order1 == Decrease && i1 > i2) )
3286 {
3287 bestCell = cell2;
3288 bestX = x;
3289 continue;
3290 }
3291
3292 if ( i1 == i2 )
3293 {
3294 // check 2nd key
3295 if (key2 <= 0)
3296 continue;
3297
3298 Cell * cell22 = cellAt( x, key2 );
3299 Cell * bestCell2 = cellAt( bestX, key2 );
3300
3301 if ( cell22->isEmpty() )
3302 {
3303 /* No need to swap */
3304 continue;
3305 }
3306 else if ( cell22->isObscured() && cell22->isPartOfMerged() )
3307 {
3308 /* No need to swap */
3309 continue;
3310 }
3311 else if ( bestCell2->isEmpty() )
3312 {
3313 // empty cells are always shifted to the end
3314 bestCell = cell2;
3315 bestX = x;
3316 continue;
3317 }
3318
3319 if ( (order2 == Increase && *cell22 < *bestCell2)
3320 || (order2 == Decrease && *cell22 > *bestCell2) )
3321 {
3322 bestCell = cell2;
3323 bestX = x;
3324 continue;
3325 }
3326 else if ( (order2 == Increase && *cell22 > *bestCell2)
3327 || (order2 == Decrease && *cell22 < *bestCell2) )
3328 {
3329 // already in right order
3330 continue;
3331 }
3332 else
3333 {
3334 // they are equal, check 3rd key
3335 if (key3 <= 0)
3336 continue;
3337
3338 Cell * cell23 = cellAt( x, key3 );
3339 Cell * bestCell3 = cellAt( bestX, key3 );
3340
3341 if ( cell23->isEmpty() )
3342 {
3343 /* No need to swap */
3344 continue;
3345 }
3346 else if ( cell23->isObscured() && cell23->isPartOfMerged() )
3347 {
3348 /* No need to swap */
3349 continue;
3350 }
3351 else if ( bestCell3->isEmpty() )
3352 {
3353 // empty cells are always shifted to the end
3354 bestCell = cell2;
3355 bestX = x;
3356 continue;
3357 }
3358 if ( (order3 == Increase && *cell23 < *bestCell3)
3359 || (order3 == Decrease && *cell23 > *bestCell3) )
3360 {
3361 // they are really equal or in the right order
3362 // no swap necessary
3363 continue;
3364 }
3365 else
3366 {
3367 bestCell = cell2;
3368 bestX = x;
3369 continue;
3370 }
3371 }
3372 }
3373 continue;
3374 }
3375 else if ( i1 != -1 && i2 == -1 )
3376 {
3377 // if not in the key list, the cell is shifted to the end - always
3378 bestCell = cell2;
3379 bestX = x;
3380 continue;
3381 }
3382 else if ( i2 != -1 && i1 == -1 )
3383 {
3384 // only text of cell2 is in the list so it is smaller than bestCell
3385 /* No need to swap */
3386 continue;
3387 }
3388
3389 // if i1 and i2 are equals -1 go on:
3390 } // end if (firstKey)
3391
3392 // Here we use the operators < and > for cells, which do it all.
3393 if ( (order1 == Increase && *cell2 < *bestCell)
3394 || (order1 == Decrease && *cell2 > *bestCell) )
3395 {
3396 bestCell = cell2;
3397 bestX = x;
3398 continue;
3399 }
3400 else if ( (order1 == Increase && *cell2 > *bestCell)
3401 || (order1 == Decrease && *cell2 < *bestCell) )
3402 {
3403 // no change necessary
3404 continue;
3405 }
3406 else
3407 {
3408 // *cell2 equals *bestCell
3409 // check 2nd key
3410 if (key2 <= 0)
3411 continue;
3412 Cell * cell22 = cellAt( d, key2 );
3413 Cell * bestCell2 = cellAt( x, key2 );
3414
3415 checkCellContent(cell2, bestCell, status);
3416 if (status == 1)
3417 continue;
3418 else if (status == 2)
3419 {
3420 // empty cells are always shifted to the end
3421 bestCell = cell2;
3422 bestX = x;
3423 continue;
3424 }
3425
3426 if ( (order2 == Increase && *cell22 > *bestCell2)
3427 || (order2 == Decrease && *cell22 < *bestCell2) )
3428 {
3429 bestCell = cell2;
3430 bestX = x;
3431 continue;
3432 }
3433 else
3434 if ( (order2 == Increase && *cell22 > *bestCell2)
3435 || (order2 == Decrease && *cell22 < *bestCell2) )
3436 {
3437 // already in right order
3438 continue;
3439 }
3440 else
3441 {
3442 // they are equal, check 3rd key
3443 if (key3 == 0)
3444 continue;
3445 Cell * cell23 = cellAt( d, key3 );
3446 Cell * bestCell3 = cellAt( x, key3 );
3447
3448 checkCellContent(cell2, bestCell, status);
3449 if (status == 1)
3450 continue;
3451 else if (status == 2)
3452 {
3453 // empty cells are always shifted to the end
3454 bestCell = cell2;
3455 bestX = x;
3456 continue;
3457 }
3458 if ( (order3 == Increase && *cell23 > *bestCell3)
3459 || (order3 == Decrease && *cell23 < *bestCell3) )
3460 {
3461 bestCell = cell2;
3462 bestX = x;
3463 continue;
3464 }
3465 else
3466 {
3467 // they are really equal
3468 // no swap necessary
3469 continue;
3470 }
3471 }
3472 }
3473 }
3474
3475 // Swap columns cell1 and bestCell (i.e. d and bestX)
3476 if ( d != bestX )
3477 {
3478 int top = target.top();
3479 if (headerRow)
3480 ++top;
3481
3482 for( int y = target.bottom(); y >= top; --y )
3483 {
3484 if ( y != key1 && y != key2 && y != key3 )
3485 swapCells( d, y, bestX, y, copyFormat );
3486 }
3487 if (key3 > 0)
3488 swapCells( d, key3, bestX, key3, copyFormat );
3489 if (key2 > 0)
3490 swapCells( d, key2, bestX, key2, copyFormat );
3491 swapCells( d, key1, bestX, key1, copyFormat );
3492 }
3493 } // for (d = ...; ...; ++d)
3494 Map::respectCase = true;
3495 // doc()->emitEndOperation();
3496 emit sig_updateView( this );
3497}
3498
3499void Sheet::sortByColumn( const TQRect &area, int key1, int key2, int key3,
3500 SortingOrder order1, SortingOrder order2,
3501 SortingOrder order3,
3502 TQStringList const * firstKey, bool copyFormat,
3503 bool headerRow,
3504 Point const & outputPoint, bool respectCase )
3505{
3506 TQRect r( area );
3507 Map::respectCase = respectCase;
3508
3509 Q_ASSERT( order1 == Increase || order1 == Decrease );
3510
3511 // It may not happen that entire rows are selected.
3512 Q_ASSERT( util_isRowSelected(r) == false );
3513
3514 // Are entire columns selected ?
3515 if ( util_isColumnSelected(r) )
3516 {
3517 r.setTop( KS_rowMax );
3518 r.setBottom( 0 );
3519
3520 // Determine a correct top and bottom.
3521 // Iterate over all cells to find out which cells are
3522 // located in the selected columns.
3523 for ( int col = r.left(); col <= r.right(); ++col )
3524 {
3525 Cell * c = getFirstCellColumn( col );
3526 int row;
3527 while ( c )
3528 {
3529 row = c->row();
3530 if ( !c->isEmpty() )
3531 {
3532 if ( row > r.bottom() )
3533 r.rBottom() = row;
3534 if ( row < r.top() )
3535 r.rTop() = row;
3536 }
3537 c = getNextCellDown( col, row );
3538 }
3539 }
3540
3541 // Any cells to sort here ?
3542 if ( r.bottom() < r.top() )
3543 {
3544 Map::respectCase = true;
3545 return;
3546 }
3547 }
3548 TQRect target( outputPoint.pos().x(), outputPoint.pos().y(), r.width(), r.height() );
3549
3550 if ( !doc()->undoLocked() )
3551 {
3552 UndoSort *undo = new UndoSort( doc(), this, target );
3553 doc()->addCommand( undo );
3554 }
3555
3556 doc()->emitBeginOperation();
3557
3558 if (target.topLeft() != r.topLeft())
3559 {
3560 int targetLeft = target.left();
3561 int targetTop = target.top();
3562 int sourceTop = r.top();
3563 int sourceLeft = r.left();
3564
3565 key1 = key1 - sourceLeft + targetLeft;
3566 key2 = key2 - sourceLeft + targetLeft;
3567 key3 = key3 - sourceLeft + targetLeft;
3568
3569 for ( int x = 0; x < r.width(); ++x)
3570 {
3571 for ( int y = 0; y < r.height(); ++y )
3572 {
3573 // from - to
3574 copyCells( sourceLeft + x, sourceTop + y,
3575 targetLeft + x, targetTop + y, copyFormat );
3576 }
3577 }
3578 }
3579
3580 // Sorting algorithm: David's :). Well, I guess it's called minmax or so.
3581 // For each row, we look for all rows under it and we find the one to swap with it.
3582 // Much faster than the awful bubbleSort...
3583 // Torben: Asymptotically it is alltogether O(n^2) :-)
3584
3585 Cell * cell;
3586 Cell * cell1;
3587 Cell * cell2;
3588 Cell * bestCell;
3589 int status = 0;
3590
3591 int d = target.top();
3592
3593 if (headerRow)
3594 ++d;
3595
3596 for ( ; d <= target.bottom(); ++d )
3597 {
3598 // Look for which row we want to swap with the one number d
3599 cell1 = cellAt( key1, d );
3600 if ( cell1->isObscured() && cell1->isPartOfMerged() )
3601 {
3602 Cell* obscuring = cell1->obscuringCells().first();
3603 cell = cellAt( key1, obscuring->row() );
3604 cell1 = cellAt( key1, obscuring->row() + cell->extraYCells() + 1 );
3605 d = obscuring->row() + cell->extraYCells() + 1;
3606 }
3607
3608 bestCell = cell1;
3609 int bestY = d;
3610
3611 for ( int y = d + 1 ; y <= target.bottom(); ++y )
3612 {
3613 cell2 = cellAt( key1, y );
3614
3615 if ( cell2->isEmpty() )
3616 {
3617 /* No need to swap */
3618 continue;
3619 }
3620 else if ( cell2->isObscured() && cell2->isPartOfMerged() )
3621 {
3622 /* No need to swap */
3623 continue;
3624 }
3625 else if ( bestCell->isEmpty() )
3626 {
3627 // empty cells are always shifted to the end
3628 bestCell = cell2;
3629 bestY = y;
3630 continue;
3631 }
3632
3633 if ( firstKey )
3634 {
3635 int i1 = firstKey->findIndex( cell2->text() );
3636 int i2 = firstKey->findIndex( bestCell->text() );
3637
3638 if ( i1 != -1 && i2 != -1 )
3639 {
3640 if ( (order1 == Increase && i1 < i2 )
3641 || (order1 == Decrease && i1 > i2) )
3642 {
3643 bestCell = cell2;
3644 bestY = y;
3645 continue;
3646 }
3647
3648 if ( i1 == i2 )
3649 {
3650 // check 2nd key
3651 if (key2 <= 0)
3652 continue;
3653 Cell * cell22 = cellAt( key2, d );
3654 Cell * bestCell2 = cellAt( key2, y );
3655
3656 if ( cell22->isEmpty() )
3657 {
3658 /* No need to swap */
3659 continue;
3660 }
3661 else if ( cell22->isObscured() && cell22->isPartOfMerged() )
3662 {
3663 /* No need to swap */
3664 continue;
3665 }
3666 else if ( bestCell2->isEmpty() )
3667 {
3668 // empty cells are always shifted to the end
3669 bestCell = cell2;
3670 bestY = y;
3671 continue;
3672 }
3673
3674 if ( (order2 == Increase && *cell22 > *bestCell2)
3675 || (order2 == Decrease && *cell22 < *bestCell2) )
3676 {
3677 bestCell = cell2;
3678 bestY = y;
3679 continue;
3680 }
3681 else if ( (order2 == Increase && *cell22 < *bestCell2)
3682 || (order2 == Decrease && *cell22 > *bestCell2) )
3683 {
3684 // already in right order
3685 continue;
3686 }
3687 else
3688 {
3689 // they are equal, check 3rd key
3690 if (key3 <= 0)
3691 continue;
3692 Cell * cell23 = cellAt( key3, d );
3693 Cell * bestCell3 = cellAt( key3, y );
3694
3695 checkCellContent(cell2, bestCell, status);
3696 if (status == 1)
3697 continue;
3698 else if (status == 2)
3699 {
3700 // empty cells are always shifted to the end
3701 bestCell = cell2;
3702 bestY = y;
3703 continue;
3704 }
3705
3706 if ( (order3 == Increase && *cell23 < *bestCell3)
3707 || (order3 == Decrease && *cell23 > *bestCell3) )
3708 {
3709 bestCell = cell2;
3710 bestY = y;
3711 continue;
3712 }
3713 else
3714 {
3715 // they are really equal or in the correct order
3716 // no swap necessary
3717 continue;
3718 }
3719 }
3720 }
3721 continue;
3722 }
3723 else if ( i1 != -1 && i2 == -1 )
3724 {
3725 // if not in the key list, the cell is shifted to the end - always
3726 bestCell = cell2;
3727 bestY = y;
3728 continue;
3729 }
3730 else if ( i2 != -1 && i1 == -1 )
3731 {
3732 // only text of cell2 is in the list so it is smaller than bestCell
3733 /* No need to swap */
3734 continue;
3735 }
3736
3737 // if i1 and i2 are equals -1 go on:
3738 } // if (firstKey)
3739
3740
3741 // Here we use the operators < and > for cells, which do it all.
3742 if ( (order1 == Increase && *cell2 < *bestCell)
3743 || (order1 == Decrease && *cell2 > *bestCell) )
3744 {
3745 bestCell = cell2;
3746 bestY = y;
3747 }
3748 else if ( (order1 == Increase && *cell2 > *bestCell)
3749 || (order1 == Decrease && *cell2 < *bestCell) )
3750 {
3751 // no change necessary
3752 continue;
3753 }
3754 else
3755 {
3756 // *cell2 equals *bestCell
3757 // check 2nd key
3758 if (key2 == 0)
3759 continue;
3760 Cell * cell22 = cellAt( key2, y );
3761 Cell * bestCell2 = cellAt( key2, bestY );
3762
3763 if ( cell22->isEmpty() )
3764 {
3765 /* No need to swap */
3766 continue;
3767 }
3768 else if ( cell22->isObscured() && cell22->isPartOfMerged() )
3769 {
3770 /* No need to swap */
3771 continue;
3772 }
3773 else if ( bestCell2->isEmpty() )
3774 {
3775 // empty cells are always shifted to the end
3776 bestCell = cell2;
3777 bestY = y;
3778 continue;
3779 }
3780
3781 if ( (order2 == Increase && *cell22 < *bestCell2)
3782 || (order2 == Decrease && *cell22 > *bestCell2) )
3783 {
3784 bestCell = cell2;
3785 bestY = y;
3786 continue;
3787 }
3788 else if ( (order2 == Increase && *cell22 > *bestCell2)
3789 || (order2 == Decrease && *cell22 < *bestCell2) )
3790 {
3791 continue;
3792 }
3793 else
3794 {
3795 // they are equal, check 3rd key
3796 if (key3 == 0)
3797 continue;
3798 Cell * cell23 = cellAt( key3, y );
3799 Cell * bestCell3 = cellAt( key3, bestY );
3800
3801 if ( cell23->isEmpty() )
3802 {
3803 /* No need to swap */
3804 continue;
3805 }
3806 else if ( cell23->isObscured() && cell23->isPartOfMerged() )
3807 {
3808 /* No need to swap */
3809 continue;
3810 }
3811 else if ( bestCell3->isEmpty() )
3812 {
3813 // empty cells are always shifted to the end
3814 bestCell = cell2;
3815 bestY = y;
3816 continue;
3817 }
3818
3819 if ( (order3 == Increase && *cell23 < *bestCell3)
3820 || (order3 == Decrease && *cell23 > *bestCell3) )
3821 {
3822 bestCell = cell2;
3823 bestY = y;
3824 continue;
3825 }
3826 else
3827 {
3828 // they are really equal or already in the correct order
3829 // no swap necessary
3830 continue;
3831 }
3832 }
3833 }
3834 }
3835
3836 // Swap rows cell1 and bestCell (i.e. d and bestY)
3837 if ( d != bestY )
3838 {
3839 for (int x = target.left(); x <= target.right(); ++x)
3840 {
3841 if ( x != key1 && x != key2 && x != key3)
3842 swapCells( x, d, x, bestY, copyFormat );
3843 }
3844 if (key3 > 0)
3845 swapCells( key3, d, key3, bestY, copyFormat );
3846 if (key2 > 0)
3847 swapCells( key2, d, key2, bestY, copyFormat );
3848 swapCells( key1, d, key1, bestY, copyFormat );
3849 }
3850 } // for (d = ...; ...; ++d)
3851 // doc()->emitEndOperation();
3852 Map::respectCase = true;
3853 emit sig_updateView( this );
3854}
3855
3856// from - to - copyFormat
3857void Sheet::copyCells( int x1, int y1, int x2, int y2, bool cpFormat )
3858{
3859 Cell * sourceCell = cellAt( x1, y1 );
3860 Cell * targetCell = cellAt( x2, y2 );
3861
3862 if ( sourceCell->isDefault() && targetCell->isDefault())
3863 {
3864 // if the source and target is default there is nothing to copy
3865 return;
3866 }
3867
3868 targetCell = nonDefaultCell(x2, y2);
3869
3870 // TODO: check if this enough
3871 targetCell->copyContent( sourceCell );
3872
3873 /*
3874 if ( !sourceCell->isFormula() )
3875 {
3876 targetCell->copyContent( sourceCell );
3877 }
3878 else
3879 {
3880 targetCell->setCellText( targetCell->decodeFormula( sourceCell->encodeFormula() ) );
3881 targetCell->setCalcDirtyFlag();
3882 targetCell->calc(false);
3883 }
3884 */
3885
3886 if (cpFormat)
3887 {
3888 targetCell->copyFormat( sourceCell );
3889 /*
3890 targetCell->setAlign( sourceCell->format()->align( x1, y1 ) );
3891 targetCell->setAlignY( sourceCell->format()->alignY( x1, y1 ) );
3892 targetCell->setTextFont( sourceCell->format()->textFont( x1, y1 ) );
3893 targetCell->setTextColor( sourceCell->textColor( x1, y1 ) );
3894 targetCell->setBgColor( sourceCell->bgColor( x1, y1 ) );
3895 targetCell->setLeftBorderPen( sourceCell->leftBorderPen( x1, y1 ) );
3896 targetCell->setTopBorderPen( sourceCell->topBorderPen( x1, y1 ) );
3897 targetCell->setBottomBorderPen( sourceCell->bottomBorderPen( x1, y1 ) );
3898 targetCell->setRightBorderPen( sourceCell->rightBorderPen( x1, y1 ) );
3899 targetCell->setFallDiagonalPen( sourceCell->fallDiagonalPen( x1, y1 ) );
3900 targetCell->setGoUpDiagonalPen( sourceCell->goUpDiagonalPen( x1, y1 ) );
3901 targetCell->setBackGroundBrush( sourceCell->backGroundBrush( x1, y1 ) );
3902 targetCell->setPrecision( sourceCell->precision( x1, y1 ) );
3903 targetCell->format()->setPrefix( sourceCell->prefix( x1, y1 ) );
3904 targetCell->format()->setPostfix( sourceCell->postfix( x1, y1 ) );
3905 targetCell->setFloatFormat( sourceCell->floatFormat( x1, y1 ) );
3906 targetCell->setFloatColor( sourceCell->floatColor( x1, y1 ) );
3907 targetCell->setMultiRow( sourceCell->multiRow( x1, y1 ) );
3908 targetCell->setVerticalText( sourceCell->verticalText( x1, y1 ) );
3909 targetCell->setStyle( sourceCell->style() );
3910 targetCell->setDontPrintText( sourceCell->getDontprintText( x1, y1 ) );
3911 targetCell->setIndent( sourceCell->getIndent( x1, y1 ) );
3912 targetCell->SetConditionList(sourceCell->GetConditionList());
3913 targetCell->setComment( sourceCell->comment( x1, y1 ) );
3914 targetCell->setAngle( sourceCell->getAngle( x1, y1 ) );
3915 targetCell->setFormatType( sourceCell->getFormatType( x1, y1 ) );
3916 */
3917 }
3918}
3919
3920void Sheet::swapCells( int x1, int y1, int x2, int y2, bool cpFormat )
3921{
3922 Cell * ref1 = cellAt( x1, y1 );
3923 Cell * ref2 = cellAt( x2, y2 );
3924
3925 if ( ref1->isDefault() )
3926 {
3927 if ( !ref2->isDefault() )
3928 {
3929 ref1 = nonDefaultCell( x1, y1 );
3930 // TODO : make ref2 default instead of copying a default cell into it
3931 }
3932 else
3933 return; // nothing to do
3934 }
3935 else
3936 if ( ref2->isDefault() )
3937 {
3938 ref2 = nonDefaultCell( x2, y2 );
3939 // TODO : make ref1 default instead of copying a default cell into it
3940 }
3941
3942 // Dummy cell used for swapping cells.
3943 // In fact we copy only content and no layout
3944 // information. Imagine sorting in a sheet. Swapping
3945 // the format while sorting is not what you would expect
3946 // as a user.
3947 if (!ref1->isFormula() && !ref2->isFormula())
3948 {
3949 Cell *tmp = new Cell( this, -1, -1 );
3950
3951 tmp->copyContent( ref1 );
3952 ref1->copyContent( ref2 );
3953 ref2->copyContent( tmp );
3954
3955 delete tmp;
3956 }
3957 else
3958 if ( ref1->isFormula() && ref2->isFormula() )
3959 {
3960 TQString d = ref1->encodeFormula();
3961 ref1->setCellText( ref1->decodeFormula( ref2->encodeFormula( ) ) );
3962 ref1->setCalcDirtyFlag();
3963 ref1->calc(false);
3964 ref2->setCellText( ref2->decodeFormula( d ) );
3965 ref2->setCalcDirtyFlag();
3966 ref2->calc(false);
3967 }
3968 else
3969 if (ref1->isFormula() && !ref2->isFormula() )
3970 {
3971 TQString d = ref1->encodeFormula();
3972 ref1->setCellText(ref2->text());
3973 ref2->setCellText(ref2->decodeFormula(d));
3974 ref2->setCalcDirtyFlag();
3975 ref2->calc(false);
3976 }
3977 else
3978 if (!ref1->isFormula() && ref2->isFormula() )
3979 {
3980 TQString d = ref2->encodeFormula();
3981 ref2->setCellText(ref1->text());
3982 ref1->setCellText(ref1->decodeFormula(d));
3983 ref1->setCalcDirtyFlag();
3984 ref1->calc(false);
3985 }
3986
3987 if (cpFormat)
3988 {
3989 Format::Align a = ref1->format()->align( ref1->column(), ref1->row() );
3990 ref1->format()->setAlign( ref2->format()->align( ref2->column(), ref2->row() ) );
3991 ref2->format()->setAlign(a);
3992
3993 Format::AlignY ay = ref1->format()->alignY( ref1->column(), ref1->row() );
3994 ref1->format()->setAlignY( ref2->format()->alignY( ref2->column(), ref2->row() ) );
3995 ref2->format()->setAlignY(ay);
3996
3997 TQFont textFont = ref1->format()->textFont( ref1->column(), ref1->row() );
3998 ref1->format()->setTextFont( ref2->format()->textFont( ref2->column(), ref2->row() ) );
3999 ref2->format()->setTextFont(textFont);
4000
4001 TQColor textColor = ref1->format()->textColor( ref1->column(), ref1->row() );
4002 ref1->format()->setTextColor( ref2->format()->textColor( ref2->column(), ref2->row() ) );
4003 ref2->format()->setTextColor(textColor);
4004
4005 TQColor bgColor = ref1->bgColor( ref1->column(), ref1->row() );
4006 ref1->format()->setBgColor( ref2->bgColor( ref2->column(), ref2->row() ) );
4007 ref2->format()->setBgColor(bgColor);
4008
4009 TQPen lbp = ref1->leftBorderPen( ref1->column(), ref1->row() );
4010 ref1->setLeftBorderPen( ref2->leftBorderPen( ref2->column(), ref2->row() ) );
4011 ref2->setLeftBorderPen(lbp);
4012
4013 TQPen tbp = ref1->topBorderPen( ref1->column(), ref1->row() );
4014 ref1->setTopBorderPen( ref2->topBorderPen( ref2->column(), ref2->row() ) );
4015 ref2->setTopBorderPen(tbp);
4016
4017 TQPen bbp = ref1->bottomBorderPen( ref1->column(), ref1->row() );
4018 ref1->setBottomBorderPen( ref2->bottomBorderPen( ref2->column(), ref2->row() ) );
4019 ref2->setBottomBorderPen(bbp);
4020
4021 TQPen rbp = ref1->rightBorderPen( ref1->column(), ref1->row() );
4022 ref1->setRightBorderPen( ref2->rightBorderPen( ref2->column(), ref2->row() ) );
4023 ref2->setRightBorderPen(rbp);
4024
4025 TQPen fdp = ref1->format()->fallDiagonalPen( ref1->column(), ref1->row() );
4026 ref1->format()->setFallDiagonalPen( ref2->format()->fallDiagonalPen( ref2->column(), ref2->row() ) );
4027 ref2->format()->setFallDiagonalPen(fdp);
4028
4029 TQPen udp = ref1->format()->goUpDiagonalPen( ref1->column(), ref1->row() );
4030 ref1->format()->setGoUpDiagonalPen( ref2->format()->goUpDiagonalPen( ref2->column(), ref2->row() ) );
4031 ref2->format()->setGoUpDiagonalPen(udp);
4032
4033 TQBrush bgBrush = ref1->backGroundBrush( ref1->column(), ref1->row() );
4034 ref1->format()->setBackGroundBrush( ref2->backGroundBrush( ref2->column(), ref2->row() ) );
4035 ref2->format()->setBackGroundBrush(bgBrush);
4036
4037 int pre = ref1->format()->precision( ref1->column(), ref1->row() );
4038 ref1->format()->setPrecision( ref2->format()->precision( ref2->column(), ref2->row() ) );
4039 ref2->format()->setPrecision(pre);
4040
4041 TQString prefix = ref1->format()->prefix( ref1->column(), ref1->row() );
4042 ref1->format()->setPrefix( ref2->format()->prefix( ref2->column(), ref2->row() ) );
4043 ref2->format()->setPrefix(prefix);
4044
4045 TQString postfix = ref1->format()->postfix( ref1->column(), ref1->row() );
4046 ref1->format()->setPostfix( ref2->format()->postfix( ref2->column(), ref2->row() ) );
4047 ref2->format()->setPostfix(postfix);
4048
4049 Format::FloatFormat f = ref1->format()->floatFormat( ref1->column(), ref1->row() );
4050 ref1->format()->setFloatFormat( ref2->format()->floatFormat( ref2->column(), ref2->row() ) );
4051 ref2->format()->setFloatFormat(f);
4052
4053 Format::FloatColor c = ref1->format()->floatColor( ref1->column(), ref1->row() );
4054 ref1->format()->setFloatColor( ref2->format()->floatColor( ref2->column(), ref2->row() ) );
4055 ref2->format()->setFloatColor(c);
4056
4057 bool multi = ref1->format()->multiRow( ref1->column(), ref1->row() );
4058 ref1->format()->setMultiRow( ref2->format()->multiRow( ref2->column(), ref2->row() ) );
4059 ref2->format()->setMultiRow(multi);
4060
4061 bool vert = ref1->format()->verticalText( ref1->column(), ref1->row() );
4062 ref1->format()->setVerticalText( ref2->format()->verticalText( ref2->column(), ref2->row() ) );
4063 ref2->format()->setVerticalText(vert);
4064
4065 bool print = ref1->format()->getDontprintText( ref1->column(), ref1->row() );
4066 ref1->format()->setDontPrintText( ref2->format()->getDontprintText( ref2->column(), ref2->row() ) );
4067 ref2->format()->setDontPrintText(print);
4068
4069 double ind = ref1->format()->getIndent( ref1->column(), ref1->row() );
4070 ref1->format()->setIndent( ref2->format()->getIndent( ref2->column(), ref2->row() ) );
4071 ref2->format()->setIndent( ind );
4072
4073 TQValueList<Conditional> conditionList = ref1->conditionList();
4074 ref1->setConditionList(ref2->conditionList());
4075 ref2->setConditionList(conditionList);
4076
4077 TQString com = ref1->format()->comment( ref1->column(), ref1->row() );
4078 ref1->format()->setComment( ref2->format()->comment( ref2->column(), ref2->row() ) );
4079 ref2->format()->setComment(com);
4080
4081 int angle = ref1->format()->getAngle( ref1->column(), ref1->row() );
4082 ref1->format()->setAngle( ref2->format()->getAngle( ref2->column(), ref2->row() ) );
4083 ref2->format()->setAngle(angle);
4084
4085 FormatType form = ref1->format()->getFormatType( ref1->column(), ref1->row() );
4086 ref1->format()->setFormatType( ref2->format()->getFormatType( ref2->column(), ref2->row() ) );
4087 ref2->format()->setFormatType(form);
4088 }
4089}
4090
4091void Sheet::refreshPreference()
4092{
4093 if ( getAutoCalc() )
4094 recalc();
4095
4096 emit sig_updateHBorder( this );
4097 emit sig_updateView( this );
4098}
4099
4100
4101bool Sheet::areaIsEmpty(const Region& region, TestType _type)
4102{
4103 Region::ConstIterator endOfList = region.constEnd();
4104 for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
4105 {
4106 TQRect range = (*it)->rect().normalize();
4107 // Complete rows selected ?
4108 if ((*it)->isRow())
4109 {
4110 for ( int row = range.top(); row <= range.bottom(); ++row )
4111 {
4112 Cell * c = getFirstCellRow( row );
4113 while ( c )
4114 {
4115 if ( !c->isPartOfMerged())
4116 {
4117 switch( _type )
4118 {
4119 case Text :
4120 if ( !c->text().isEmpty())
4121 return false;
4122 break;
4123 case Validity:
4124 if ( c->getValidity(0))
4125 return false;
4126 break;
4127 case Comment:
4128 if ( !c->format()->comment(c->column(), row).isEmpty())
4129 return false;
4130 break;
4131 case ConditionalCellAttribute:
4132 if ( c->conditionList().count()> 0)
4133 return false;
4134 break;
4135 }
4136 }
4137
4138 c = getNextCellRight( c->column(), row );
4139 }
4140 }
4141 }
4142 // Complete columns selected ?
4143 else if ((*it)->isColumn())
4144 {
4145 for ( int col = range.left(); col <= range.right(); ++col )
4146 {
4147 Cell * c = getFirstCellColumn( col );
4148 while ( c )
4149 {
4150 if ( !c->isPartOfMerged() )
4151 {
4152 switch( _type )
4153 {
4154 case Text :
4155 if ( !c->text().isEmpty())
4156 return false;
4157 break;
4158 case Validity:
4159 if ( c->getValidity(0))
4160 return false;
4161 break;
4162 case Comment:
4163 if ( !c->format()->comment(col, c->row()).isEmpty())
4164 return false;
4165 break;
4166 case ConditionalCellAttribute:
4167 if ( c->conditionList().count()> 0)
4168 return false;
4169 break;
4170 }
4171 }
4172
4173 c = getNextCellDown( col, c->row() );
4174 }
4175 }
4176 }
4177 else
4178 {
4179 Cell * cell;
4180
4181 int right = range.right();
4182 int bottom = range.bottom();
4183 for ( int x = range.left(); x <= right; ++x )
4184 for ( int y = range.top(); y <= bottom; ++y )
4185 {
4186 cell = cellAt( x, y );
4187 if (!cell->isPartOfMerged() )
4188 {
4189 switch( _type )
4190 {
4191 case Text :
4192 if ( !cell->text().isEmpty())
4193 return false;
4194 break;
4195 case Validity:
4196 if ( cell->getValidity(0))
4197 return false;
4198 break;
4199 case Comment:
4200 if ( !cell->format()->comment(x, y).isEmpty())
4201 return false;
4202 break;
4203 case ConditionalCellAttribute:
4204 if ( cell->conditionList().count()> 0)
4205 return false;
4206 break;
4207 }
4208 }
4209 }
4210 }
4211 }
4212 return true;
4213}
4214
4215struct SetSelectionMultiRowWorker : public Sheet::CellWorker
4216{
4217 bool enable;
4218 SetSelectionMultiRowWorker( bool _enable )
4219 : Sheet::CellWorker( ), enable( _enable ) { }
4220
4221 class UndoAction* createUndoAction( Doc * doc, Sheet * sheet, const KSpread::Region& region )
4222 {
4223 TQString title = i18n("Multirow");
4224 return new UndoCellFormat( doc, sheet, region, title );
4225 }
4226
4227 bool testCondition( Cell * cell )
4228 {
4229 return ( !cell->isPartOfMerged() );
4230 }
4231
4232 void doWork( Cell * cell, bool, int, int )
4233 {
4234 cell->setDisplayDirtyFlag();
4235 cell->format()->setMultiRow( enable );
4236 cell->format()->setVerticalText( false );
4237 cell->format()->setAngle( 0 );
4238 cell->clearDisplayDirtyFlag();
4239 }
4240};
4241
4242void Sheet::setSelectionMultiRow( Selection* selectionInfo,
4243 bool enable )
4244{
4245 SetSelectionMultiRowWorker w( enable );
4246 workOnCells( selectionInfo, w );
4247}
4248
4249TQString Sheet::guessColumnTitle(TQRect& area, int col)
4250{
4251 //Verify range
4252 Range rg;
4253 rg.setRange(area);
4254 rg.setSheet(this);
4255
4256 if ( (!rg.isValid()) || (col < area.left()) || (col > area.right()))
4257 return TQString();
4258
4259 //The current guess logic is fairly simple - if the top row of the given area
4260 //appears to contain headers (ie. there is text in each column) the text in the column at
4261 //the top row of the area is returned.
4262
4263/* for (int i=area.left();i<=area.right();i++)
4264 {
4265 Value cellValue=value(i,area.top());
4266
4267 if (!cellValue.isString())
4268 return TQString();
4269 }*/
4270
4271 Value cellValue=value(col,area.top());
4272 return cellValue.asString();
4273}
4274
4275TQString Sheet::guessRowTitle(TQRect& area, int row)
4276{
4277 //Verify range
4278 Range rg;
4279 rg.setRange(area);
4280 rg.setSheet(this);
4281
4282 if ( (!rg.isValid()) || (row < area.top()) || (row > area.bottom()) )
4283 return TQString();
4284
4285 //The current guess logic is fairly simple - if the leftmost column of the given area
4286 //appears to contain headers (ie. there is text in each row) the text in the row at
4287 //the leftmost column of the area is returned.
4288 /*for (int i=area.top();i<=area.bottom();i++)
4289 {
4290 Value cellValue=value(area.left(),i);
4291
4292 if (!cellValue.isString())
4293 return TQString();
4294 }*/
4295
4296 Value cellValue=value(area.left(),row);
4297 return cellValue.asString();
4298}
4299
4300void Sheet::setSelectionAlign( Selection* selectionInfo,
4301 Format::Align _align )
4302{
4303 HorAlignManipulator* manipulator = new HorAlignManipulator();
4304 manipulator->setSheet(this);
4305 manipulator->setProperty(Format::PAlign);
4306 manipulator->setHorizontalAlignment(_align);
4307 manipulator->add(*selectionInfo);
4308 manipulator->execute();
4309}
4310
4311void Sheet::setSelectionAlignY( Selection* selectionInfo,
4312 Format::AlignY _alignY )
4313{
4314 VerAlignManipulator* manipulator = new VerAlignManipulator();
4315 manipulator->setSheet(this);
4316 manipulator->setProperty(Format::PAlignY);
4317 manipulator->setVerticalAlignment(_alignY);
4318 manipulator->add(*selectionInfo);
4319 manipulator->execute();
4320}
4321
4322
4323struct SetSelectionPrecisionWorker : public Sheet::CellWorker {
4324 int _delta;
4325 SetSelectionPrecisionWorker( int delta ) : Sheet::CellWorker( ), _delta( delta ) { }
4326
4327 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4328 TQString title=i18n("Change Precision");
4329 return new UndoCellFormat( doc, sheet, region, title );
4330 }
4331 bool testCondition( Cell* cell ) {
4332 return ( !cell->isPartOfMerged() );
4333 }
4334 void doWork( Cell* cell, bool, int, int ) {
4335 cell->setDisplayDirtyFlag();
4336 if ( _delta == 1 )
4337 cell->incPrecision();
4338 else
4339 cell->decPrecision();
4340 cell->clearDisplayDirtyFlag();
4341 }
4342};
4343
4344void Sheet::setSelectionPrecision( Selection* selectionInfo,
4345 int _delta )
4346{
4347 SetSelectionPrecisionWorker w( _delta );
4348 workOnCells( selectionInfo, w );
4349}
4350
4351struct SetSelectionStyleWorker : public Sheet::CellWorkerTypeA
4352{
4353 Style * m_style;
4354 SetSelectionStyleWorker( Style * style )
4355 : m_style( style )
4356 {
4357 }
4358
4359 TQString getUndoTitle()
4360 {
4361 return i18n("Apply Style");
4362 }
4363
4364 void doWork( RowFormat* rw )
4365 {
4366 rw->setStyle( m_style );
4367 }
4368
4369 void doWork( ColumnFormat* cl )
4370 {
4371 cl->setStyle( m_style );
4372 }
4373
4374 bool testCondition( Cell* cell )
4375 {
4376 return ( !cell->isPartOfMerged() && cell->format()->style() != m_style );
4377 }
4378
4379 void doWork( Cell* cell, bool cellRegion, int, int )
4380 {
4381 if ( cellRegion )
4382 cell->setDisplayDirtyFlag();
4383
4384 cell->format()->setStyle( m_style );
4385
4386 if ( cellRegion )
4387 cell->clearDisplayDirtyFlag();
4388 }
4389};
4390
4391
4392void Sheet::setSelectionStyle( Selection * selectionInfo, Style * style )
4393{
4394 SetSelectionStyleWorker w( style );
4395 workOnCells( selectionInfo, w );
4396}
4397
4398struct SetSelectionMoneyFormatWorker : public Sheet::CellWorkerTypeA
4399{
4400 bool b;
4401 Doc *m_pDoc;
4402 SetSelectionMoneyFormatWorker( bool _b,Doc* _doc ) : b( _b ), m_pDoc(_doc) { }
4403 TQString getUndoTitle() { return i18n("Format Money"); }
4404 bool testCondition( RowFormat* rw ) {
4405 return ( rw->hasProperty( Format::PFormatType )
4406 || rw->hasProperty( Format::PPrecision ) );
4407 }
4408 void doWork( RowFormat* rw ) {
4409 rw->setFormatType( b ? Money_format : Generic_format );
4410 rw->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
4411 }
4412 void doWork( ColumnFormat* cl ) {
4413 cl->setFormatType( b ? Money_format : Generic_format );
4414 cl->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
4415 }
4416 void prepareCell( Cell* c ) {
4417 c->format()->clearProperty( Format::PPrecision );
4418 c->format()->clearNoFallBackProperties( Format::PPrecision );
4419 c->format()->clearProperty( Format::PFormatType );
4420 c->format()->clearNoFallBackProperties( Format::PFormatType );
4421 }
4422 bool testCondition( Cell* cell ) {
4423 return ( !cell->isPartOfMerged() );
4424 }
4425 void doWork( Cell* cell, bool cellRegion, int, int ) {
4426 if ( cellRegion )
4427 cell->setDisplayDirtyFlag();
4428 cell->format()->setFormatType( b ? Money_format : Generic_format );
4429 cell->format()->setPrecision( b ? m_pDoc->locale()->fracDigits() : 0 );
4430 if ( cellRegion )
4431 cell->clearDisplayDirtyFlag();
4432 }
4433};
4434
4435
4436void Sheet::setSelectionMoneyFormat( Selection* selectionInfo,
4437 bool b )
4438{
4439 SetSelectionMoneyFormatWorker w( b,doc() );
4440 workOnCells( selectionInfo, w );
4441}
4442
4443
4444struct IncreaseIndentWorker : public Sheet::CellWorkerTypeA {
4445 double tmpIndent;
4446 double valIndent;
4447
4448 IncreaseIndentWorker( double _tmpIndent, double _valIndent )
4449 : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
4450
4451 TQString getUndoTitle() { return i18n("Increase Indent"); }
4452 bool testCondition( RowFormat* rw ) {
4453 return ( rw->hasProperty( Format::PIndent ) );
4454 }
4455
4456 void doWork( RowFormat* rw ) {
4457 rw->setIndent( tmpIndent+valIndent );
4458 //rw->setAlign( Format::Left );
4459 }
4460 void doWork( ColumnFormat* cl ) {
4461 cl->setIndent( tmpIndent+valIndent );
4462 //cl->setAlign( Format::Left );
4463 }
4464 void prepareCell( Cell* c ) {
4465 c->format()->clearProperty( Format::PIndent );
4466 c->format()->clearNoFallBackProperties( Format::PIndent );
4467 //c->format()->clearProperty( Format::PAlign );
4468 //c->format()->clearNoFallBackProperties( Format::PAlign );
4469 }
4470 bool testCondition( Cell* cell ) {
4471 return ( !cell->isPartOfMerged() );
4472 }
4473 void doWork( Cell* cell, bool cellRegion, int x, int y ) {
4474 if ( cellRegion ) {
4475 if(cell->format()->align(x,y)!=Format::Left)
4476 {
4477 //cell->setAlign(Format::Left);
4478 //cell->format()->setIndent( 0.0 );
4479 }
4480 cell->setDisplayDirtyFlag();
4481 cell->format()->setIndent( /* ### ??? --> */ cell->format()->getIndent(x,y) /* <-- */ +valIndent );
4482 cell->clearDisplayDirtyFlag();
4483 } else {
4484 cell->format()->setIndent( tmpIndent+valIndent);
4485 //cell->setAlign( Format::Left);
4486 }
4487 }
4488};
4489
4490
4491void Sheet::increaseIndent(Selection* selectionInfo)
4492{
4493 TQPoint marker(selectionInfo->marker());
4494 double valIndent = doc()->getIndentValue();
4495 Cell *c = cellAt( marker );
4496 double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
4497
4498 IncreaseIndentWorker w( tmpIndent, valIndent );
4499 workOnCells( selectionInfo, w );
4500}
4501
4502
4503struct DecreaseIndentWorker : public Sheet::CellWorkerTypeA {
4504 double tmpIndent, valIndent;
4505 DecreaseIndentWorker( double _tmpIndent, double _valIndent ) : tmpIndent( _tmpIndent ), valIndent( _valIndent ) { }
4506 TQString getUndoTitle() { return i18n("Decrease Indent"); }
4507 bool testCondition( RowFormat* rw ) {
4508 return ( rw->hasProperty( Format::PIndent ) );
4509 }
4510 void doWork( RowFormat* rw ) {
4511 rw->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
4512 }
4513 void doWork( ColumnFormat* cl ) {
4514 cl->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
4515 }
4516 void prepareCell( Cell* c ) {
4517 c->format()->clearProperty( Format::PIndent );
4518 c->format()->clearNoFallBackProperties( Format::PIndent );
4519 }
4520 bool testCondition( Cell* cell ) {
4521 return ( !cell->isPartOfMerged() );
4522 }
4523 void doWork( Cell* cell, bool cellRegion, int x, int y ) {
4524 if ( cellRegion ) {
4525 cell->setDisplayDirtyFlag();
4526 cell->format()->setIndent( TQMAX( 0.0, cell->format()->getIndent( x, y ) - valIndent ) );
4527 cell->clearDisplayDirtyFlag();
4528 } else {
4529 cell->format()->setIndent( TQMAX( 0.0, tmpIndent - valIndent ) );
4530 }
4531 }
4532};
4533
4534
4535void Sheet::decreaseIndent( Selection* selectionInfo )
4536{
4537 double valIndent = doc()->getIndentValue();
4538 TQPoint marker(selectionInfo->marker());
4539 Cell* c = cellAt( marker );
4540 double tmpIndent = c->format()->getIndent( marker.x(), marker.y() );
4541
4542 DecreaseIndentWorker w( tmpIndent, valIndent );
4543 workOnCells( selectionInfo, w );
4544}
4545
4546
4547int Sheet::adjustColumnHelper( Cell * c, int _col, int _row )
4548{
4549 double long_max = 0.0;
4550 c->calculateTextParameters( painter(), _col, _row );
4551 if ( c->textWidth() > long_max )
4552 {
4553 double indent = 0.0;
4554 int a = c->format()->align( c->column(), c->row() );
4555 if ( a == Format::Undefined )
4556 {
4557 if ( c->value().isNumber() || c->isDate() || c->isTime())
4558 a = Format::Right;
4559 else
4560 a = Format::Left;
4561 }
4562
4563 if ( a == Format::Left )
4564 indent = c->format()->getIndent( c->column(), c->row() );
4565 long_max = indent + c->textWidth()
4566 + c->format()->leftBorderWidth( c->column(), c->row() )
4567 + c->format()->rightBorderWidth( c->column(), c->row() );
4568 }
4569 return (int)long_max;
4570}
4571
4572void Sheet::adjustArea(const Region& region)
4573{
4574 AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
4575 manipulator->setSheet(this);
4576 manipulator->setAdjustColumn(true);
4577 manipulator->setAdjustRow(true);
4578 manipulator->add(region);
4579 manipulator->execute();
4580}
4581
4582void Sheet::adjustColumn(const Region& region)
4583{
4584 AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
4585 manipulator->setSheet(this);
4586 manipulator->setAdjustColumn(true);
4587 manipulator->add(region);
4588 manipulator->execute();
4589}
4590
4591void Sheet::adjustRow(const Region& region)
4592{
4593 AdjustColumnRowManipulator* manipulator = new AdjustColumnRowManipulator();
4594 manipulator->setSheet(this);
4595 manipulator->setAdjustRow(true);
4596 manipulator->add(region);
4597 manipulator->execute();
4598}
4599
4600struct ClearTextSelectionWorker : public Sheet::CellWorker {
4601 Sheet * _s;
4602
4603 ClearTextSelectionWorker( Sheet * s )
4604 : Sheet::CellWorker( ), _s( s ) { }
4605
4606 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4607 return new UndoChangeAreaTextCell( doc, sheet, region );
4608 }
4609 bool testCondition( Cell* cell ) {
4610 return ( !cell->isObscured() );
4611 }
4612 void doWork( Cell* cell, bool, int, int )
4613 {
4614 cell->setCellText( "" );
4615 }
4616};
4617
4618void Sheet::clearTextSelection( Selection* selectionInfo )
4619{
4620 if (areaIsEmpty(*selectionInfo))
4621 return;
4622
4623 ClearTextSelectionWorker w( this );
4624 workOnCells( selectionInfo, w );
4625}
4626
4627
4628struct ClearValiditySelectionWorker : public Sheet::CellWorker {
4629 ClearValiditySelectionWorker( ) : Sheet::CellWorker( ) { }
4630
4631 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4632 return new UndoConditional( doc, sheet, region );
4633 }
4634 bool testCondition( Cell* cell ) {
4635 return ( !cell->isObscured() );
4636 }
4637 void doWork( Cell* cell, bool, int, int ) {
4638 cell->removeValidity();
4639 }
4640};
4641
4642void Sheet::clearValiditySelection( Selection* selectionInfo )
4643{
4644 if (areaIsEmpty(*selectionInfo, Validity))
4645 return;
4646
4647 ClearValiditySelectionWorker w;
4648 workOnCells( selectionInfo, w );
4649}
4650
4651
4652struct ClearConditionalSelectionWorker : public Sheet::CellWorker
4653{
4654 ClearConditionalSelectionWorker( ) : Sheet::CellWorker( ) { }
4655
4656 class UndoAction* createUndoAction( Doc* doc,
4657 Sheet* sheet,
4658 const KSpread::Region& region )
4659 {
4660 return new UndoConditional( doc, sheet, region );
4661 }
4662 bool testCondition( Cell* cell )
4663 {
4664 return ( !cell->isObscured() );
4665 }
4666 void doWork( Cell* cell, bool, int, int )
4667 {
4668 TQValueList<Conditional> emptyList;
4669 cell->setConditionList(emptyList);
4670 }
4671};
4672
4673void Sheet::clearConditionalSelection( Selection* selectionInfo )
4674{
4675 ClearConditionalSelectionWorker w;
4676 workOnCells( selectionInfo, w );
4677}
4678
4679void Sheet::fillSelection( Selection * selectionInfo, int direction )
4680{
4681 TQRect rct( selectionInfo->selection() );
4682 int right = rct.right();
4683 int bottom = rct.bottom();
4684 int left = rct.left();
4685 int top = rct.top();
4686 int width = rct.width();
4687 int height = rct.height();
4688
4689 TQDomDocument undoDoc = saveCellRegion( rct );
4690 loadSelectionUndo( undoDoc, rct, left - 1, top - 1, false, 0 );
4691
4692 TQDomDocument doc;
4693
4694 switch( direction )
4695 {
4696 case Right:
4697 doc = saveCellRegion( TQRect( left, top, 1, height ) );
4698 break;
4699
4700 case Up:
4701 doc = saveCellRegion( TQRect( left, bottom, width, 1 ) );
4702 break;
4703
4704 case Left:
4705 doc = saveCellRegion( TQRect( right, top, 1, height ) );
4706 break;
4707
4708 case Down:
4709 doc = saveCellRegion( TQRect( left, top, width, 1 ) );
4710 break;
4711 };
4712
4713 // Save to buffer
4714 TQBuffer buffer;
4715 buffer.open( IO_WriteOnly );
4716 TQTextStream str( &buffer );
4717 str.setEncoding( TQTextStream::UnicodeUTF8 );
4718 str << doc;
4719 buffer.close();
4720
4721 int i;
4722 switch( direction )
4723 {
4724 case Right:
4725 for ( i = left + 1; i <= right; ++i )
4726 {
4727 paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
4728 }
4729 break;
4730
4731 case Up:
4732 for ( i = bottom + 1; i >= top; --i )
4733 {
4734 paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
4735 }
4736 break;
4737
4738 case Left:
4739 for ( i = right - 1; i >= left; --i )
4740 {
4741 paste( buffer.buffer(), TQRect( i, top, 1, 1 ), false );
4742 }
4743 break;
4744
4745 case Down:
4746 for ( i = top + 1; i <= bottom; ++i )
4747 {
4748 paste( buffer.buffer(), TQRect( left, i, 1, 1 ), false );
4749 }
4750 break;
4751 }
4752
4753 this->doc()->setModified( true );
4754}
4755
4756
4757struct DefaultSelectionWorker : public Sheet::CellWorker {
4758 DefaultSelectionWorker( ) : Sheet::CellWorker( true, false, true ) { }
4759
4760 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4761 TQString title=i18n("Default Parameters");
4762 return new UndoCellFormat( doc, sheet, region, title );
4763 }
4764 bool testCondition( Cell* ) {
4765 return true;
4766 }
4767 void doWork( Cell* cell, bool, int, int ) {
4768 cell->defaultStyle();
4769 }
4770};
4771
4772void Sheet::defaultSelection( Selection* selectionInfo )
4773{
4774 TQRect selection(selectionInfo->selection());
4775 DefaultSelectionWorker w;
4776 SelectionType st = workOnCells( selectionInfo, w );
4777 switch ( st ) {
4778 case CompleteRows:
4779 RowFormat *rw;
4780 for ( int i = selection.top(); i <= selection.bottom(); i++ ) {
4781 rw = nonDefaultRowFormat( i );
4782 rw->defaultStyleFormat();
4783 }
4784 emit sig_updateView( this, *selectionInfo );
4785 return;
4786 case CompleteColumns:
4787 ColumnFormat *cl;
4788 for ( int i = selection.left(); i <= selection.right(); i++ ) {
4789 cl=nonDefaultColumnFormat( i );
4790 cl->defaultStyleFormat();
4791 }
4792 emit sig_updateView( this, *selectionInfo );
4793 return;
4794 case CellRegion:
4795 emit sig_updateView( this, *selectionInfo );
4796 return;
4797 }
4798}
4799
4800
4801struct SetConditionalWorker : public Sheet::CellWorker
4802{
4803 TQValueList<Conditional> conditionList;
4804 SetConditionalWorker( TQValueList<Conditional> _tmp ) :
4805 Sheet::CellWorker( ), conditionList( _tmp ) { }
4806
4807 class UndoAction* createUndoAction( Doc* doc,
4808 Sheet* sheet, const KSpread::Region& region )
4809 {
4810 return new UndoConditional( doc, sheet, region );
4811 }
4812
4813 bool testCondition( Cell* )
4814 {
4815 return true;
4816 }
4817
4818 void doWork( Cell* cell, bool, int, int )
4819 {
4820 if ( !cell->isObscured() ) // TODO: isPartOfMerged()???
4821 {
4822 cell->setConditionList(conditionList);
4823 cell->setDisplayDirtyFlag();
4824 }
4825 }
4826};
4827
4828void Sheet::setConditional( Selection* selectionInfo,
4829 TQValueList<Conditional> const & newConditions)
4830{
4831 if ( !doc()->undoLocked() )
4832 {
4833 UndoConditional * undo = new UndoConditional(doc(), this, *selectionInfo);
4834 doc()->addCommand( undo );
4835 }
4836
4837 Region::ConstIterator endOfList = selectionInfo->constEnd();
4838 for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
4839 {
4840 TQRect range = (*it)->rect().normalize();
4841
4842 int l = range.left();
4843 int r = range.right();
4844 int t = range.top();
4845 int b = range.bottom();
4846
4847 Cell * cell;
4848 Style * s = doc()->styleManager()->defaultStyle();
4849 for (int x = l; x <= r; ++x)
4850 {
4851 for (int y = t; y <= b; ++y)
4852 {
4853 cell = nonDefaultCell( x, y, false, s );
4854 cell->setConditionList( newConditions );
4855 cell->setDisplayDirtyFlag();
4856 }
4857 }
4858 }
4859
4860 emit sig_updateView( this, *selectionInfo );
4861}
4862
4863
4864struct SetValidityWorker : public Sheet::CellWorker {
4865 Validity tmp;
4866 SetValidityWorker( Validity _tmp ) : Sheet::CellWorker( ), tmp( _tmp ) { }
4867
4868 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4869 return new UndoConditional( doc, sheet, region );
4870 }
4871 bool testCondition( Cell* ) {
4872 return true;
4873 }
4874 void doWork( Cell* cell, bool, int, int ) {
4875 if ( !cell->isObscured() ) {
4876 cell->setDisplayDirtyFlag();
4877 if ( tmp.m_restriction==Restriction::None )
4878 cell->removeValidity();
4879 else
4880 {
4881 Validity *tmpValidity = cell->getValidity();
4882 tmpValidity->message=tmp.message;
4883 tmpValidity->title=tmp.title;
4884 tmpValidity->valMin=tmp.valMin;
4885 tmpValidity->valMax=tmp.valMax;
4886 tmpValidity->m_cond=tmp.m_cond;
4887 tmpValidity->m_action=tmp.m_action;
4888 tmpValidity->m_restriction=tmp.m_restriction;
4889 tmpValidity->timeMin=tmp.timeMin;
4890 tmpValidity->timeMax=tmp.timeMax;
4891 tmpValidity->dateMin=tmp.dateMin;
4892 tmpValidity->dateMax=tmp.dateMax;
4893 tmpValidity->displayMessage=tmp.displayMessage;
4894 tmpValidity->allowEmptyCell=tmp.allowEmptyCell;
4895 tmpValidity->displayValidationInformation=tmp.displayValidationInformation;
4896 tmpValidity->titleInfo=tmp.titleInfo;
4897 tmpValidity->messageInfo=tmp.messageInfo;
4898 tmpValidity->listValidity=tmp.listValidity;
4899 }
4900 cell->clearDisplayDirtyFlag();
4901 }
4902 }
4903};
4904
4905void Sheet::setValidity(Selection* selectionInfo,
4906 KSpread::Validity tmp )
4907{
4908 SetValidityWorker w( tmp );
4909 workOnCells( selectionInfo, w );
4910}
4911
4912
4913struct GetWordSpellingWorker : public Sheet::CellWorker {
4914 TQString& listWord;
4915 GetWordSpellingWorker( TQString& _listWord ) : Sheet::CellWorker( false, false, true ), listWord( _listWord ) { }
4916
4917 class UndoAction* createUndoAction( Doc*, Sheet*, const KSpread::Region& ) {
4918 return 0;
4919 }
4920 bool testCondition( Cell* ) {
4921 return true;
4922 }
4923 void doWork( Cell* c, bool cellRegion, int, int ) {
4924 if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
4925 if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
4926 && !c->isDate()
4927 && !c->text().isEmpty())
4928 {
4929 listWord+=c->text()+'\n';
4930 }
4931 }
4932 }
4933};
4934
4935TQString Sheet::getWordSpelling(Selection* selectionInfo )
4936{
4937 TQString listWord;
4938 GetWordSpellingWorker w( listWord );
4939 workOnCells( selectionInfo, w );
4940 return listWord;
4941}
4942
4943
4944struct SetWordSpellingWorker : public Sheet::CellWorker {
4945 TQStringList& list;
4946 int pos;
4947 Sheet * sheet;
4948 SetWordSpellingWorker( TQStringList & _list,Sheet * s )
4949 : Sheet::CellWorker( false, false, true ), list( _list ), pos( 0 ), sheet( s ) { }
4950
4951 class UndoAction* createUndoAction( Doc* doc, Sheet* sheet, const KSpread::Region& region ) {
4952 return new UndoChangeAreaTextCell( doc, sheet, region );
4953 }
4954 bool testCondition( Cell* ) {
4955 return true;
4956 }
4957 void doWork( Cell* c, bool cellRegion, int, int )
4958 {
4959 if ( !c->isObscured() || cellRegion /* ### ??? */ ) {
4960 if ( !c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty() && !c->isTime()
4961 && !c->isDate()
4962 && !c->text().isEmpty())
4963 {
4964
4965
4966 c->setCellText( list[pos] );
4967 pos++;
4968 }
4969 }
4970 }
4971};
4972
4973void Sheet::setWordSpelling(Selection* selectionInfo,
4974 const TQString _listWord )
4975{
4976 TQStringList list = TQStringList::split ( '\n', _listWord );
4977 SetWordSpellingWorker w( list, this );
4978 workOnCells( selectionInfo, w );
4979}
4980
4981static TQString cellAsText( Cell* cell, unsigned int max )
4982{
4983 TQString result;
4984 if( !cell->isDefault() )
4985 {
4986 int l = max - cell->strOutText().length();
4987 if (cell->defineAlignX() == Format::Right )
4988 {
4989 for ( int i = 0; i < l; ++i )
4990 result += " ";
4991 result += cell->strOutText();
4992 }
4993 else if (cell->defineAlignX() == Format::Left )
4994 {
4995 result += " ";
4996 result += cell->strOutText();
4997 // start with "1" because we already set one space
4998 for ( int i = 1; i < l; ++i )
4999 result += " ";
5000 }
5001 else // centered
5002 {
5003 int i;
5004 int s = (int) l / 2;
5005 for ( i = 0; i < s; ++i )
5006 result += " ";
5007 result += cell->strOutText();
5008 for ( i = s; i < l; ++i )
5009 result += " ";
5010 }
5011 }
5012 else
5013 {
5014 for ( unsigned int i = 0; i < max; ++i )
5015 result += " ";
5016 }
5017
5018 return result;
5019}
5020
5021TQString Sheet::copyAsText( Selection* selectionInfo )
5022{
5023 // Only one cell selected? => copy active cell
5024 if ( selectionInfo->isSingular() )
5025 {
5026 Cell * cell = cellAt( selectionInfo->marker() );
5027 if( !cell->isDefault() )
5028 return cell->strOutText();
5029 return "";
5030 }
5031
5032 TQRect selection(selectionInfo->selection());
5033
5034 // Find area
5035 unsigned top = selection.bottom();
5036 unsigned bottom = selection.top();
5037 unsigned left = selection.right();
5038 unsigned right = selection.left();
5039
5040 unsigned max = 1;
5041 for( Cell *c = d->cells.firstCell();c; c = c->nextCell() )
5042 {
5043 if ( !c->isDefault() )
5044 {
5045 TQPoint p( c->column(), c->row() );
5046 if ( selection.contains( p ) )
5047 {
5048 top = TQMIN( top, (unsigned) c->row() );
5049 left = TQMIN( left, (unsigned) c->column() );
5050 bottom = TQMAX( bottom, (unsigned) c->row() );
5051 right = TQMAX( right, (unsigned) c->column() );
5052
5053 if ( c->strOutText().length() > max )
5054 max = c->strOutText().length();
5055 }
5056 }
5057 }
5058
5059 ++max;
5060
5061 TQString result;
5062 for ( unsigned y = top; y <= bottom; ++y)
5063 {
5064 for ( unsigned x = left; x <= right; ++x)
5065 {
5066 Cell *cell = cellAt( x, y );
5067 result += cellAsText( cell, max );
5068 }
5069 result += "\n";
5070 }
5071
5072 return result;
5073}
5074
5075void Sheet::copySelection( Selection* selectionInfo )
5076{
5077 TQDomDocument doc = saveCellRegion( *selectionInfo, true );
5078
5079 // Save to buffer
5080 TQBuffer buffer;
5081 buffer.open( IO_WriteOnly );
5082 TQTextStream str( &buffer );
5083 str.setEncoding( TQTextStream::UnicodeUTF8 );
5084 str << doc;
5085 buffer.close();
5086
5087 TextDrag * kd = new TextDrag( 0L );
5088 kd->setPlain( copyAsText(selectionInfo) );
5089 kd->setKSpread( buffer.buffer() );
5090
5091 TQApplication::clipboard()->setData( kd );
5092}
5093
5094void Sheet::cutSelection( Selection* selectionInfo )
5095{
5096 TQDomDocument doc = saveCellRegion(*selectionInfo, true, true);
5097
5098 // Save to buffer
5099 TQBuffer buffer;
5100 buffer.open( IO_WriteOnly );
5101 TQTextStream str( &buffer );
5102 str.setEncoding( TQTextStream::UnicodeUTF8 );
5103 str << doc;
5104 buffer.close();
5105
5106 TextDrag * kd = new TextDrag( 0L );
5107 kd->setPlain( copyAsText(selectionInfo) );
5108 kd->setKSpread( buffer.buffer() );
5109
5110 TQApplication::clipboard()->setData( kd );
5111
5112 deleteSelection( selectionInfo, true );
5113}
5114
5115void Sheet::paste( const TQRect& pasteArea, bool makeUndo,
5116 Paste::Mode mode, Paste::Operation operation,
5117 bool insert, int insertTo, bool pasteFC,
5118 TQClipboard::Mode clipboardMode )
5119{
5120 TQMimeSource * mime = TQApplication::clipboard()->data( clipboardMode );
5121 if ( !mime )
5122 return;
5123
5124 TQByteArray b;
5125
5126 if ( mime->provides( TextDrag::selectionMimeType() ) )
5127 {
5128 b = mime->encodedData( TextDrag::selectionMimeType() );
5129 }
5130 else if( mime->provides( "text/plain" ) )
5131 {
5132 // Note: TQClipboard::text() seems to do a better job than encodedData( "text/plain" )
5133 // In particular it handles charsets (in the mimetype). Copied from KPresenter ;-)
5134 TQString _text = TQApplication::clipboard()->text( clipboardMode );
5135 doc()->emitBeginOperation();
5136 pasteTextPlain( _text, pasteArea );
5137 emit sig_updateView( this );
5138 // doc()->emitEndOperation();
5139 return;
5140 }
5141 else
5142 return;
5143
5144 // Do the actual pasting.
5145 doc()->emitBeginOperation();
5146 paste( b, pasteArea, makeUndo, mode, operation, insert, insertTo, pasteFC );
5147 emit sig_updateView( this );
5148 // doc()->emitEndOperation();
5149}
5150
5151
5152void Sheet::pasteTextPlain( TQString &_text, TQRect pasteArea)
5153{
5154// TQString tmp;
5155// tmp= TQString::fromLocal8Bit(_mime->encodedData( "text/plain" ));
5156 if( _text.isEmpty() )
5157 return;
5158
5159 TQString tmp = _text;
5160 int i;
5161 int mx = pasteArea.left();
5162 int my = pasteArea.top();
5163 int rows = 1;
5164 int len = tmp.length();
5165
5166 //count the numbers of lines in text
5167 for ( i = 0; i < len; ++i )
5168 {
5169 if ( tmp[i] == '\n' )
5170 ++rows;
5171 }
5172
5173 Cell * cell = nonDefaultCell( mx, my );
5174 if ( rows == 1 )
5175 {
5176 if ( !doc()->undoLocked() )
5177 {
5178 UndoSetText * undo = new UndoSetText( doc(), this , cell->text(), mx, my, cell->formatType() );
5179 doc()->addCommand( undo );
5180 }
5181 }
5182 else
5183 {
5184 TQRect rect(mx, my, mx, my + rows - 1);
5185 UndoChangeAreaTextCell * undo = new UndoChangeAreaTextCell( doc(), this , rect );
5186 doc()->addCommand( undo );
5187 }
5188
5189 i = 0;
5190 TQString rowtext;
5191
5192 while ( i < rows )
5193 {
5194 int p = 0;
5195
5196 p = tmp.find('\n');
5197
5198 if (p < 0)
5199 p = tmp.length();
5200
5201 rowtext = tmp.left(p);
5202
5203 if ( !isProtected() || cell->format()->notProtected( mx, my + i ) )
5204 {
5205 cell->setCellText( rowtext );
5206 cell->updateChart();
5207 }
5208
5209 // next cell
5210 ++i;
5211 cell = nonDefaultCell( mx, my + i );
5212
5213 if (!cell || p == (int) tmp.length())
5214 break;
5215
5216 // exclude the left part and '\n'
5217 tmp = tmp.right(tmp.length() - p - 1);
5218 }
5219
5220 if (!isLoading())
5221 refreshMergedCell();
5222
5223 emit sig_updateView( this );
5224 emit sig_updateHBorder( this );
5225 emit sig_updateVBorder( this );
5226}
5227
5228void Sheet::paste( const TQByteArray& b, const TQRect& pasteArea, bool makeUndo,
5229 Paste::Mode mode, Paste::Operation operation,
5230 bool insert, int insertTo, bool pasteFC )
5231{
5232 kdDebug(36001) << "Parsing " << b.size() << " bytes" << endl;
5233
5234 TQBuffer buffer( b );
5235 buffer.open( IO_ReadOnly );
5236 TQDomDocument doc;
5237 doc.setContent( &buffer );
5238 buffer.close();
5239
5240 // ##### TODO: Test for parsing errors
5241
5242 int mx = pasteArea.left();
5243 int my = pasteArea.top();
5244
5245 loadSelection( doc, pasteArea, mx - 1, my - 1, makeUndo,
5246 mode, operation, insert, insertTo, pasteFC );
5247}
5248
5249bool Sheet::loadSelection(const TQDomDocument& doc, const TQRect& pasteArea,
5250 int _xshift, int _yshift, bool makeUndo,
5251 Paste::Mode mode, Paste::Operation operation, bool insert,
5252 int insertTo, bool pasteFC)
5253{
5254 //kdDebug(36001) << "loadSelection called. pasteArea=" << pasteArea << endl;
5255
5256 if (!isLoading() && makeUndo)
5257 {
5258 loadSelectionUndo( doc, pasteArea, _xshift, _yshift, insert, insertTo );
5259 }
5260
5261 TQDomElement root = doc.documentElement(); // "spreadsheet-snippet"
5262
5263 int rowsInClpbrd = root.attribute( "rows" ).toInt();
5264 int columnsInClpbrd = root.attribute( "columns" ).toInt();
5265
5266 // find size of rectangle that we want to paste to (either clipboard size or current selection)
5267 const int pasteWidth = ( pasteArea.width() >= columnsInClpbrd
5268 && util_isRowSelected(pasteArea) == false
5269 && root.namedItem( "rows" ).toElement().isNull() )
5270 ? pasteArea.width() : columnsInClpbrd;
5271 const int pasteHeight = ( pasteArea.height() >= rowsInClpbrd
5272 && util_isColumnSelected(pasteArea) == false
5273 && root.namedItem( "columns" ).toElement().isNull())
5274 ? pasteArea.height() : rowsInClpbrd;
5275
5276// kdDebug() << "loadSelection: paste area has size "
5277// << pasteHeight << " rows * "
5278// << pasteWidth << " columns " << endl;
5279// kdDebug() << "loadSelection: " << rowsInClpbrd << " rows and "
5280// << columnsInClpbrd << " columns in clipboard." << endl;
5281// kdDebug() << "xshift: " << _xshift << " _yshift: " << _yshift << endl;
5282
5283 TQDomElement e = root.firstChild().toElement(); // "columns", "rows" or "cell"
5284 for (; !e.isNull(); e = e.nextSibling().toElement())
5285 {
5286 // entire columns given
5287 if (e.tagName() == "columns" && !isProtected())
5288 {
5289 _yshift = 0;
5290
5291 // Clear the existing columns
5292 int col = e.attribute("column").toInt();
5293 int width = e.attribute("count").toInt();
5294 if (!insert)
5295 {
5296 for ( int i = col; i < col + width; ++i )
5297 {
5298 d->cells.clearColumn( _xshift + i );
5299 d->columns.removeElement( _xshift + i );
5300 }
5301 }
5302
5303 // Insert column formats
5304 TQDomElement c = e.firstChild().toElement();
5305 for ( ; !c.isNull(); c = c.nextSibling().toElement() )
5306 {
5307 if ( c.tagName() == "column" )
5308 {
5309 ColumnFormat *cl = new ColumnFormat( this, 0 );
5310 if ( cl->load( c, _xshift, mode, pasteFC ) )
5311 insertColumnFormat( cl );
5312 else
5313 delete cl;
5314 }
5315 }
5316 }
5317
5318 // entire rows given
5319 if (e.tagName() == "rows" && !isProtected())
5320 {
5321 _xshift = 0;
5322
5323 // Clear the existing rows
5324 int row = e.attribute("row").toInt();
5325 int height = e.attribute("count").toInt();
5326 if ( !insert )
5327 {
5328 for( int i = row; i < row + height; ++i )
5329 {
5330 d->cells.clearRow( _yshift + i );
5331 d->rows.removeElement( _yshift + i );
5332 }
5333 }
5334
5335 // Insert row formats
5336 TQDomElement c = e.firstChild().toElement();
5337 for( ; !c.isNull(); c = c.nextSibling().toElement() )
5338 {
5339 if ( c.tagName() == "row" )
5340 {
5341 RowFormat *cl = new RowFormat( this, 0 );
5342 if ( cl->load( c, _yshift, mode, pasteFC ) )
5343 insertRowFormat( cl );
5344 else
5345 delete cl;
5346 }
5347 }
5348 }
5349
5350 Cell* refreshCell = 0;
5351 Cell *cell;
5352 Cell *cellBackup = NULL;
5353 if (e.tagName() == "cell")
5354 {
5355 int row = e.attribute( "row" ).toInt() + _yshift;
5356 int col = e.attribute( "column" ).toInt() + _xshift;
5357
5358 // tile the selection with the clipboard contents
5359 for (int roff = 0; row + roff - _yshift <= pasteHeight; roff += rowsInClpbrd)
5360 {
5361 for (int coff = 0; col + coff - _xshift <= pasteWidth; coff += columnsInClpbrd)
5362 {
5363// kdDebug() << "loadSelection: cell at " << (col+coff) << "," << (row+roff)
5364// << " with roff,coff= " << roff << "," << coff
5365// << ", _xshift: " << _xshift << ", _yshift: " << _yshift << endl;
5366
5367 cell = nonDefaultCell( col + coff, row + roff );
5368 if (isProtected() && !cell->format()->notProtected(col + coff, row + roff))
5369 {
5370 continue;
5371 }
5372
5373 cellBackup = new Cell(this, cell->column(), cell->row());
5374 cellBackup->copyAll(cell);
5375
5376 if (!cell->load(e, _xshift + coff, _yshift + roff, mode, operation, pasteFC))
5377 {
5378 cell->copyAll(cellBackup);
5379 }
5380 else
5381 {
5382 if (cell->isFormula())
5383 {
5384 cell->setCalcDirtyFlag();
5385 }
5386 }
5387
5388 delete cellBackup;
5389
5390
5391
5392 cell = cellAt( col + coff, row + roff );
5393 if( !refreshCell && cell->updateChart( false ) )
5394 {
5395 refreshCell = cell;
5396 }
5397 }
5398 }
5399 }
5400
5401 //refresh chart after that you paste all cells
5402
5403 /* I don't think this is gonna work....doesn't this only update
5404 one chart -- the one which had a dependant cell update first? - John
5405
5406 I don't have time to check on this now....
5407 */
5408 if ( refreshCell )
5409 refreshCell->updateChart();
5410 }
5411 this->doc()->setModified( true );
5412
5413 if (!isLoading())
5414 refreshMergedCell();
5415
5416 emit sig_updateView( this );
5417 emit sig_updateHBorder( this );
5418 emit sig_updateVBorder( this );
5419
5420 return true;
5421}
5422
5423void Sheet::loadSelectionUndo(const TQDomDocument& d, const TQRect& loadArea,
5424 int _xshift, int _yshift,
5425 bool insert, int insertTo)
5426{
5427 TQDomElement root = d.documentElement(); // "spreadsheet-snippet"
5428
5429 int rowsInClpbrd = root.attribute( "rows" ).toInt();
5430 int columnsInClpbrd = root.attribute( "columns" ).toInt();
5431
5432 // find rect that we paste to
5433 const int pasteWidth = (loadArea.width() >= columnsInClpbrd &&
5434 util_isRowSelected(loadArea) == false &&
5435 root.namedItem( "rows" ).toElement().isNull())
5436 ? loadArea.width() : columnsInClpbrd;
5437 const int pasteHeight = (loadArea.height() >= rowsInClpbrd &&
5438 util_isColumnSelected(loadArea) == false &&
5439 root.namedItem( "columns" ).toElement().isNull())
5440 ? loadArea.height() : rowsInClpbrd;
5441
5442 uint numCols = 0;
5443 uint numRows = 0;
5444
5445 Region region;
5446 for (TQDomNode n = root.firstChild(); !n.isNull(); n = n.nextSibling())
5447 {
5448 TQDomElement e = n.toElement(); // "columns", "rows" or "cell"
5449 if (e.tagName() == "columns")
5450 {
5451 _yshift = 0;
5452 int col = e.attribute("column").toInt();
5453 int width = e.attribute("count").toInt();
5454 for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
5455 {
5456 uint overlap = TQMAX(0, (col - 1 + coff + width) - pasteWidth);
5457 uint effWidth = width - overlap;
5458 region.add(TQRect(_xshift + col + coff, 1, effWidth, KS_rowMax));
5459 numCols += effWidth;
5460 }
5461 }
5462 else if (e.tagName() == "rows")
5463 {
5464 _xshift = 0;
5465 int row = e.attribute("row").toInt();
5466 int height = e.attribute("count").toInt();
5467 for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
5468 {
5469 uint overlap = TQMAX(0, (row - 1 + roff + height) - pasteHeight);
5470 uint effHeight = height - overlap;
5471 region.add(TQRect(1, _yshift + row + roff, KS_colMax, effHeight));
5472 numRows += effHeight;
5473 }
5474 }
5475 else if (!e.isNull())
5476 {
5477 // store the cols/rows for the insertion
5478 int col = e.attribute("column").toInt();
5479 int row = e.attribute("row").toInt();
5480 for (int coff = 0; col + coff <= pasteWidth; coff += columnsInClpbrd)
5481 {
5482 for (int roff = 0; row + roff <= pasteHeight; roff += rowsInClpbrd)
5483 {
5484 region.add(TQPoint(_xshift + col + coff, _yshift + row + roff));
5485 }
5486 }
5487 }
5488 }
5489
5490 if (!doc()->undoLocked())
5491 {
5492 UndoCellPaste *undo = new UndoCellPaste( doc(), this, _xshift, _yshift, region, insert, insertTo );
5493 doc()->addCommand( undo );
5494 }
5495
5496 if (insert)
5497 {
5498 TQRect rect = region.boundingRect();
5499 // shift cells to the right
5500 if (insertTo == -1 && numCols == 0 && numRows == 0)
5501 {
5502 rect.setWidth(rect.width());
5503 shiftRow(rect, false);
5504 }
5505 // shift cells to the bottom
5506 else if (insertTo == 1 && numCols == 0 && numRows == 0)
5507 {
5508 rect.setHeight(rect.height());
5509 shiftColumn( rect, false );
5510 }
5511 // insert columns
5512 else if (insertTo == 0 && numCols == 0 && numRows > 0)
5513 {
5514 insertRow(rect.top(), rect.height() - 1, false);
5515 }
5516 // insert rows
5517 else if (insertTo == 0 && numCols > 0 && numRows == 0)
5518 {
5519 insertColumn(rect.left(), rect.width() - 1, false);
5520 }
5521 }
5522}
5523
5524bool Sheet::testAreaPasteInsert()const
5525{
5526 TQMimeSource* mime = TQApplication::clipboard()->data( TQClipboard::Clipboard );
5527 if ( !mime )
5528 return false;
5529
5530 TQByteArray b;
5531
5532 if ( mime->provides( "application/x-kspread-snippet" ) )
5533 b = mime->encodedData( "application/x-kspread-snippet" );
5534 else
5535 return false;
5536
5537 TQBuffer buffer( b );
5538 buffer.open( IO_ReadOnly );
5539 TQDomDocument d;
5540 d.setContent( &buffer );
5541 buffer.close();
5542
5543 TQDomElement e = d.documentElement();
5544 if ( !e.namedItem( "columns" ).toElement().isNull() )
5545 return false;
5546
5547 if ( !e.namedItem( "rows" ).toElement().isNull() )
5548 return false;
5549
5550 TQDomElement c = e.firstChild().toElement();
5551 for( ; !c.isNull(); c = c.nextSibling().toElement() )
5552 {
5553 if ( c.tagName() == "cell" )
5554 return true;
5555 }
5556 return false;
5557}
5558
5559void Sheet::deleteCells(const Region& region)
5560{
5561 // A list of all cells we want to delete.
5562 TQPtrStack<Cell> cellStack;
5563
5564 Region::ConstIterator endOfList = region.constEnd();
5565 for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
5566 {
5567 TQRect range = (*it)->rect().normalize();
5568
5569 int right = range.right();
5570 int left = range.left();
5571 int bottom = range.bottom();
5572 int col;
5573 for ( int row = range.top(); row <= bottom; ++row )
5574 {
5575 Cell * c = getFirstCellRow( row );
5576 while ( c )
5577 {
5578 col = c->column();
5579 if ( col < left )
5580 {
5581 c = getNextCellRight( left - 1, row );
5582 continue;
5583 }
5584 if ( col > right )
5585 break;
5586
5587 if ( !c->isDefault() )
5588 cellStack.push( c );
5589
5590 c = getNextCellRight( col, row );
5591 }
5592 }
5593 }
5594
5595 d->cells.setAutoDelete( false );
5596
5597 // Remove the cells from the sheet
5598 while ( !cellStack.isEmpty() )
5599 {
5600 Cell * cell = cellStack.pop();
5601
5602 d->cells.remove( cell->column(), cell->row() );
5603 cell->setCalcDirtyFlag();
5604 setRegionPaintDirty(cell->cellRect());
5605
5606 delete cell;
5607 }
5608
5609 d->cells.setAutoDelete( true );
5610
5611 setLayoutDirtyFlag();
5612
5613 // TODO: don't go through all cells here!
5614 // Since obscured cells might have been deleted we
5615 // have to reenforce it.
5616 Cell * c = d->cells.firstCell();
5617 for( ;c; c = c->nextCell() )
5618 {
5619 if ( c->doesMergeCells() && !c->isDefault() )
5620 c->mergeCells( c->column(), c->row(),
5621 c->extraXCells(), c->extraYCells() );
5622 }
5623 doc()->setModified( true );
5624}
5625
5626void Sheet::deleteSelection( Selection* selectionInfo, bool undo )
5627{
5628 if ( undo && !doc()->undoLocked() )
5629 {
5630 UndoDelete *undo = new UndoDelete( doc(), this, *selectionInfo );
5631 doc()->addCommand( undo );
5632 }
5633
5634 Region::ConstIterator endOfList = selectionInfo->constEnd();
5635 for (Region::ConstIterator it = selectionInfo->constBegin(); it != endOfList; ++it)
5636 {
5637 TQRect range = (*it)->rect().normalize();
5638
5639 // Entire rows selected ?
5640 if ( util_isRowSelected(range) )
5641 {
5642 for( int i = range.top(); i <= range.bottom(); ++i )
5643 {
5644 d->cells.clearRow( i );
5645 d->rows.removeElement( i );
5646 }
5647
5648 emit sig_updateVBorder( this );
5649 }
5650 // Entire columns selected ?
5651 else if ( util_isColumnSelected(range) )
5652 {
5653 for( int i = range.left(); i <= range.right(); ++i )
5654 {
5655 d->cells.clearColumn( i );
5656 d->columns.removeElement( i );
5657 }
5658
5659 emit sig_updateHBorder( this );
5660 }
5661 else
5662 {
5663 setRegionPaintDirty( range );
5664 deleteCells( range );
5665 }
5666 }
5667 refreshMergedCell();
5668 emit sig_updateView( this );
5669}
5670
5671void Sheet::updateView()
5672{
5673 emit sig_updateView( this );
5674}
5675
5676void Sheet::updateView( TQRect const & rect )
5677{
5678 emit sig_updateView( this, rect );
5679}
5680
5681void Sheet::updateView(Region* region)
5682{
5683 emit sig_updateView( this, *region );
5684}
5685
5686void Sheet::refreshView( const Region& region )
5687{
5688 Region tmpRegion;
5689 Region::ConstIterator endOfList = region.constEnd();
5690 for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
5691 {
5692 TQRect range = (*it)->rect().normalize();
5693 // TODO: don't go through all cells when refreshing!
5694 TQRect tmp(range);
5695 Cell * c = d->cells.firstCell();
5696 for( ;c; c = c->nextCell() )
5697 {
5698 if ( !c->isDefault() &&
5699 c->row() >= range.top() && c->row() <= range.bottom() &&
5700 c->column() >= range.left() && c->column() <= range.right() )
5701 {
5702 if (c->doesMergeCells())
5703 {
5704 int right=TQMAX(tmp.right(),c->column()+c->extraXCells());
5705 int bottom=TQMAX(tmp.bottom(),c->row()+c->extraYCells());
5706
5707 tmp.setRight(right);
5708 tmp.setBottom(bottom);
5709 }
5710 }
5711 }
5712 deleteCells( range );
5713 tmpRegion.add(tmp);
5714 }
5715 emit sig_updateView( this, tmpRegion );
5716}
5717
5718
5719void Sheet::mergeCells(const Region& region, bool hor, bool ver)
5720{
5721 // sanity check
5722 if( isProtected() )
5723 return;
5724 if( workbook()->isProtected() )
5725 return;
5726
5727 MergeManipulator* manipulator = new MergeManipulator();
5728 manipulator->setSheet(this);
5729 manipulator->setHorizontalMerge(hor);
5730 manipulator->setVerticalMerge(ver);
5731 manipulator->add(region);
5732 manipulator->execute();
5733}
5734
5735void Sheet::dissociateCells(const Region& region)
5736{
5737 // sanity check
5738 if( isProtected() )
5739 return;
5740 if( workbook()->isProtected() )
5741 return;
5742
5743 Manipulator* manipulator = new MergeManipulator();
5744 manipulator->setSheet(this);
5745 manipulator->setReverse(true);
5746 manipulator->add(region);
5747 manipulator->execute();
5748}
5749
5750bool Sheet::testListChoose(Selection* selectionInfo)
5751{
5752 TQRect selection( selectionInfo->selection() );
5753 TQPoint marker( selectionInfo->marker() );
5754
5755 Cell *cell = cellAt( marker.x(), marker.y() );
5756 TQString tmp=cell->text();
5757
5758 Cell* c = firstCell();
5759 bool different=false;
5760 int col;
5761 for( ;c; c = c->nextCell() )
5762 {
5763 col = c->column();
5764 if ( selection.left() <= col && selection.right() >= col &&
5765 !c->isPartOfMerged() &&
5766 !(col==marker.x() && c->row()==marker.y()))
5767 {
5768 if(!c->isFormula() && !c->value().isNumber() && !c->value().asString().isEmpty()
5769 && !c->isTime() &&!c->isDate() )
5770 {
5771 if(c->text()!=tmp)
5772 different=true;
5773 }
5774
5775 }
5776 }
5777 return different;
5778}
5779
5780
5781
5782TQDomDocument Sheet::saveCellRegion(const Region& region, bool copy, bool era)
5783{
5784 TQDomDocument dd( "spreadsheet-snippet" );
5785 dd.appendChild( dd.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
5786 TQDomElement root = dd.createElement( "spreadsheet-snippet" );
5787 dd.appendChild(root);
5788
5789 // find the upper left corner of the selection
5790 TQRect boundingRect = region.boundingRect();
5791 int left = boundingRect.left();
5792 int top = boundingRect.top();
5793
5794 // for tiling the clipboard content in the selection
5795 root.setAttribute( "rows", boundingRect.height() );
5796 root.setAttribute( "columns", boundingRect.width() );
5797
5798 Region::ConstIterator endOfList = region.constEnd();
5799 for (Region::ConstIterator it = region.constBegin(); it != endOfList; ++it)
5800 {
5801 TQRect range = (*it)->rect().normalize();
5802
5803 //
5804 // Entire rows selected?
5805 //
5806 if ((*it)->isRow())
5807 {
5808 TQDomElement rows = dd.createElement("rows");
5809 rows.setAttribute( "count", range.height() );
5810 rows.setAttribute( "row", range.top() - top + 1 );
5811 root.appendChild( rows );
5812
5813 // Save all cells.
5814 for (Cell* cell = d->cells.firstCell(); cell; cell = cell->nextCell())
5815 {
5816 if (!cell->isDefault() && !cell->isPartOfMerged())
5817 {
5818 TQPoint point(cell->column(), cell->row());
5819 if (range.contains(point))
5820 {
5821 root.appendChild(cell->save( dd, 0, top - 1, copy, copy, era));
5822 }
5823 }
5824 }
5825
5826 // ##### Inefficient
5827 // Save the row formats if there are any
5828 RowFormat* format;
5829 for (int row = range.top(); row <= range.bottom(); ++row)
5830 {
5831 format = rowFormat( row );
5832 if (format && !format->isDefault())
5833 {
5834 TQDomElement e = format->save(dd, top - 1, copy);
5835 if (!e.isNull())
5836 {
5837 rows.appendChild( e );
5838 }
5839 }
5840 }
5841 continue;
5842 }
5843
5844 //
5845 // Entire columns selected?
5846 //
5847 if ((*it)->isColumn())
5848 {
5849 TQDomElement columns = dd.createElement("columns");
5850 columns.setAttribute( "count", range.width() );
5851 columns.setAttribute( "column", range.left() - left + 1 );
5852 root.appendChild( columns );
5853
5854 // Save all cells.
5855 for (Cell* cell = d->cells.firstCell();cell; cell = cell->nextCell())
5856 {
5857 if (!cell->isDefault() && !cell->isPartOfMerged())
5858 {
5859 TQPoint point(cell->column(), cell->row());
5860 if (range.contains(point))
5861 {
5862 root.appendChild(cell->save( dd, left - 1, 0, copy, copy, era));
5863 }
5864 }
5865 }
5866
5867 // ##### Inefficient
5868 // Save the column formats if there are any
5869 ColumnFormat* format;
5870 for (int col = range.left(); col <= range.right(); ++col)
5871 {
5872 format = columnFormat(col);
5873 if (format && !format->isDefault())
5874 {
5875 TQDomElement e = format->save(dd, left - 1, copy);
5876 if (!e.isNull())
5877 {
5878 columns.appendChild(e);
5879 }
5880 }
5881 }
5882 continue;
5883 }
5884
5885 // Save all cells.
5886 //store all cell
5887 //when they don't exist we created them
5888 //because it's necessary when there is a format on a column/row
5889 //but I remove cell which is inserted.
5890 Cell* cell;
5891 bool insert;
5892 enableScrollBarUpdates(false);
5893 for (int col = range.left(); col <= range.right(); ++col)
5894 {
5895 for (int row = range.top(); row <= range.bottom(); ++row)
5896 {
5897 insert = false;
5898 cell = cellAt(col, row);
5899 if (cell == d->defaultCell)
5900 {
5901 cell = new Cell(this, col, row);
5902 insertCell(cell);
5903 insert = true;
5904 }
5905 root.appendChild(cell->save(dd, left - 1, top - 1, true, copy, era));
5906 if (insert)
5907 {
5908 d->cells.remove(col, row);
5909 }
5910 }
5911 }
5912 enableScrollBarUpdates(true);
5913 }
5914 return dd;
5915}
5916
5917TQDomElement Sheet::saveXML( TQDomDocument& dd )
5918{
5919 TQDomElement sheet = dd.createElement( "table" );
5920 sheet.setAttribute( "name", d->name );
5921
5922
5923 //Laurent: for oasis format I think that we must use style:direction...
5924 sheet.setAttribute( "layoutDirection", (d->layoutDirection == RightToLeft) ? "rtl" : "ltr" );
5925 sheet.setAttribute( "columnnumber", (int)d->showColumnNumber);
5926 sheet.setAttribute( "borders", (int)d->showPageBorders);
5927 sheet.setAttribute( "hide", (int)d->hide);
5928 sheet.setAttribute( "hidezero", (int)d->hideZero);
5929 sheet.setAttribute( "firstletterupper", (int)d->firstLetterUpper);
5930 sheet.setAttribute( "grid", (int)d->showGrid );
5931 sheet.setAttribute( "printGrid", (int)d->print->printGrid() );
5932 sheet.setAttribute( "printCommentIndicator", (int)d->print->printCommentIndicator() );
5933 sheet.setAttribute( "printFormulaIndicator", (int)d->print->printFormulaIndicator() );
5934 sheet.setAttribute( "showFormula", (int)d->showFormula);
5935 sheet.setAttribute( "showFormulaIndicator", (int)d->showFormulaIndicator);
5936 sheet.setAttribute( "showCommentIndicator", (int)d->showCommentIndicator);
5937 sheet.setAttribute( "lcmode", (int)d->lcMode);
5938 sheet.setAttribute( "autoCalc", (int)d->autoCalc);
5939 sheet.setAttribute( "borders1.2", 1);
5940 if ( !d->password.isNull() )
5941 {
5942 if ( d->password.size() > 0 )
5943 {
5944 TQCString str = KCodecs::base64Encode( d->password );
5945 sheet.setAttribute( "protected", TQString( str.data() ) );
5946 }
5947 else
5948 sheet.setAttribute( "protected", "" );
5949 }
5950
5951 // paper parameters
5952 TQDomElement paper = dd.createElement( "paper" );
5953 paper.setAttribute( "format", d->print->paperFormatString() );
5954 paper.setAttribute( "orientation", d->print->orientationString() );
5955 sheet.appendChild( paper );
5956
5957 TQDomElement borders = dd.createElement( "borders" );
5958 borders.setAttribute( "left", d->print->leftBorder() );
5959 borders.setAttribute( "top", d->print->topBorder() );
5960 borders.setAttribute( "right", d->print->rightBorder() );
5961 borders.setAttribute( "bottom", d->print->bottomBorder() );
5962 paper.appendChild( borders );
5963
5964 TQDomElement head = dd.createElement( "head" );
5965 paper.appendChild( head );
5966 if ( !d->print->headLeft().isEmpty() )
5967 {
5968 TQDomElement left = dd.createElement( "left" );
5969 head.appendChild( left );
5970 left.appendChild( dd.createTextNode( d->print->headLeft() ) );
5971 }
5972 if ( !d->print->headMid().isEmpty() )
5973 {
5974 TQDomElement center = dd.createElement( "center" );
5975 head.appendChild( center );
5976 center.appendChild( dd.createTextNode( d->print->headMid() ) );
5977 }
5978 if ( !d->print->headRight().isEmpty() )
5979 {
5980 TQDomElement right = dd.createElement( "right" );
5981 head.appendChild( right );
5982 right.appendChild( dd.createTextNode( d->print->headRight() ) );
5983 }
5984 TQDomElement foot = dd.createElement( "foot" );
5985 paper.appendChild( foot );
5986 if ( !d->print->footLeft().isEmpty() )
5987 {
5988 TQDomElement left = dd.createElement( "left" );
5989 foot.appendChild( left );
5990 left.appendChild( dd.createTextNode( d->print->footLeft() ) );
5991 }
5992 if ( !d->print->footMid().isEmpty() )
5993 {
5994 TQDomElement center = dd.createElement( "center" );
5995 foot.appendChild( center );
5996 center.appendChild( dd.createTextNode( d->print->footMid() ) );
5997 }
5998 if ( !d->print->footRight().isEmpty() )
5999 {
6000 TQDomElement right = dd.createElement( "right" );
6001 foot.appendChild( right );
6002 right.appendChild( dd.createTextNode( d->print->footRight() ) );
6003 }
6004
6005 // print range
6006 TQDomElement printrange = dd.createElement( "printrange-rect" );
6007 TQRect _printRange = d->print->printRange();
6008 int left = _printRange.left();
6009 int right = _printRange.right();
6010 int top = _printRange.top();
6011 int bottom = _printRange.bottom();
6012 //If whole rows are selected, then we store zeros, as KS_colMax may change in future
6013 if ( left == 1 && right == KS_colMax )
6014 {
6015 left = 0;
6016 right = 0;
6017 }
6018 //If whole columns are selected, then we store zeros, as KS_rowMax may change in future
6019 if ( top == 1 && bottom == KS_rowMax )
6020 {
6021 top = 0;
6022 bottom = 0;
6023 }
6024 printrange.setAttribute( "left-rect", left );
6025 printrange.setAttribute( "right-rect", right );
6026 printrange.setAttribute( "bottom-rect", bottom );
6027 printrange.setAttribute( "top-rect", top );
6028 sheet.appendChild( printrange );
6029
6030 // Print repeat columns
6031 TQDomElement printRepeatColumns = dd.createElement( "printrepeatcolumns" );
6032 printRepeatColumns.setAttribute( "left", d->print->printRepeatColumns().first );
6033 printRepeatColumns.setAttribute( "right", d->print->printRepeatColumns().second );
6034 sheet.appendChild( printRepeatColumns );
6035
6036 // Print repeat rows
6037 TQDomElement printRepeatRows = dd.createElement( "printrepeatrows" );
6038 printRepeatRows.setAttribute( "top", d->print->printRepeatRows().first );
6039 printRepeatRows.setAttribute( "bottom", d->print->printRepeatRows().second );
6040 sheet.appendChild( printRepeatRows );
6041
6042 //Save print zoom
6043 sheet.setAttribute( "printZoom", d->print->zoom() );
6044
6045 //Save page limits
6046 sheet.setAttribute( "printPageLimitX", d->print->pageLimitX() );
6047 sheet.setAttribute( "printPageLimitY", d->print->pageLimitY() );
6048
6049 // Save all cells.
6050 Cell* c = d->cells.firstCell();
6051 for( ;c; c = c->nextCell() )
6052 {
6053 if ( !c->isDefault() )
6054 {
6055 TQDomElement e = c->save( dd );
6056 if ( !e.isNull() )
6057 sheet.appendChild( e );
6058 }
6059 }
6060
6061 // Save all RowFormat objects.
6062 RowFormat* rl = d->rows.first();
6063 for( ; rl; rl = rl->next() )
6064 {
6065 if ( !rl->isDefault() )
6066 {
6067 TQDomElement e = rl->save( dd );
6068 if ( e.isNull() )
6069 return TQDomElement();
6070 sheet.appendChild( e );
6071 }
6072 }
6073
6074 // Save all ColumnFormat objects.
6075 ColumnFormat* cl = d->columns.first();
6076 for( ; cl; cl = cl->next() )
6077 {
6078 if ( !cl->isDefault() )
6079 {
6080 TQDomElement e = cl->save( dd );
6081 if ( e.isNull() )
6082 return TQDomElement();
6083 sheet.appendChild( e );
6084 }
6085 }
6086
6087 TQPtrListIterator<EmbeddedObject> chl = doc()->embeddedObjects();
6088 for( ; chl.current(); ++chl )
6089 {
6090 if ( chl.current()->sheet() == this )
6091 {
6092 TQDomElement e = chl.current()->save( dd );
6093
6094 if ( e.isNull() )
6095 return TQDomElement();
6096 sheet.appendChild( e );
6097 }
6098 }
6099 return sheet;
6100}
6101
6102bool Sheet::isLoading()
6103{
6104 return doc()->isLoading();
6105}
6106
6107
6108TQPtrList<EmbeddedObject> Sheet::getSelectedObjects()
6109{
6110 TQPtrList<EmbeddedObject> objects;
6111 TQPtrListIterator<EmbeddedObject> it = doc()->embeddedObjects();
6112 for ( ; it.current() ; ++it )
6113 {
6114 if( it.current()->isSelected()
6115 && it.current()->sheet() == this )
6116 {
6117 objects.append( it.current() );
6118 }
6119 }
6120 return objects;
6121}
6122
6123KoRect Sheet::getRealRect( bool all )
6124{
6125 KoRect rect;
6126
6127 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
6128 for ( ; it.current() ; ++it )
6129 {
6130
6131 if ( all || ( it.current()->isSelected() && ! it.current()->isProtect() ) )
6132 rect |= it.current()->geometry();
6133 }
6134
6135 return rect;
6136}
6137
6138// move object for releasemouseevent
6139KCommand *Sheet::moveObject(View *_view, double diffx, double diffy)
6140{
6141 bool createCommand=false;
6142 MoveObjectByCmd *moveByCmd=0L;
6143 Canvas * canvas = _view->canvasWidget();
6144 TQPtrList<EmbeddedObject> _objects;
6145 _objects.setAutoDelete( false );
6146 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
6147 for ( ; it.current() ; ++it )
6148 {
6149 if ( it.current()->isSelected() && !it.current()->isProtect())
6150 {
6151 _objects.append( it.current() );
6152 KoRect geometry = it.current()->geometry();
6153 geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
6154 TQRect br = doc()->zoomRect( geometry/*it.current()->geometry()*/ );
6155 br.moveBy( doc()->zoomItX( diffx ), doc()->zoomItY( diffy ) );
6156 br.moveBy( doc()->zoomItX( -canvas->xOffset() ), doc()->zoomItY( -canvas->yOffset() ) );
6157 canvas->repaint( br ); // Previous position
6158 canvas->repaintObject( it.current() ); // New position
6159 createCommand=true;
6160 }
6161 }
6162 if(createCommand) {
6163 moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ), KoPoint( diffx, diffy ),
6164 _objects, doc(), this );
6165
6166// m_doc->updateSideBarItem( this );
6167 }
6168 return moveByCmd;
6169}
6170
6171KCommand *Sheet::moveObject(View *_view,const KoPoint &_move,bool key)
6172{
6173 TQPtrList<EmbeddedObject> _objects;
6174 _objects.setAutoDelete( false );
6175 MoveObjectByCmd *moveByCmd=0L;
6176 Canvas * canvas = _view->canvasWidget();
6177 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects()/*m_objectList*/ );
6178 for ( ; it.current() ; ++it )
6179 {
6180 if ( it.current()->isSelected() && !it.current()->isProtect()) {
6181
6182 KoRect geometry = it.current()->geometry();
6183 geometry.moveBy( -canvas->xOffset(), -canvas->yOffset() );
6184 TQRect oldBoundingRect = doc()->zoomRect( geometry );
6185
6186
6187 KoRect r = it.current()->geometry();
6188 r.moveBy( _move.x(), _move.y() );
6189
6190 it.current()->setGeometry( r );
6191 _objects.append( it.current() );
6192
6193 canvas->repaint( oldBoundingRect );
6194 canvas->repaintObject( it.current() );
6195 }
6196 }
6197
6198 if ( key && !_objects.isEmpty())
6199 moveByCmd = new MoveObjectByCmd( i18n( "Move Objects" ),
6200 KoPoint( _move ),
6201 _objects, doc() ,this );
6202
6203 return moveByCmd;
6204}
6205
6206/*
6207 * Check if object name already exists.
6208 */
6209bool Sheet::objectNameExists( EmbeddedObject *object, TQPtrList<EmbeddedObject> &list ) {
6210 TQPtrListIterator<EmbeddedObject> it( list );
6211
6212 for ( it.toFirst(); it.current(); ++it ) {
6213 // object name can exist in current object.
6214 if ( it.current()->getObjectName() == object->getObjectName() &&
6215 it.current() != object ) {
6216 return true;
6217 }
6218 }
6219 return false;
6220}
6221
6222void Sheet::unifyObjectName( EmbeddedObject *object ) {
6223 if ( object->getObjectName().isEmpty() ) {
6224 object->setObjectName( object->getTypeString() );
6225 }
6226 TQString objectName( object->getObjectName() );
6227
6228 TQPtrList<EmbeddedObject> list( doc()->embeddedObjects() );
6229
6230 int count = 1;
6231
6232 while ( objectNameExists( object, list ) ) {
6233 count++;
6234 TQRegExp rx( " \\(\\d{1,3}\\)$" );
6235 if ( rx.search( objectName ) != -1 ) {
6236 objectName.remove( rx );
6237 }
6238 objectName += TQString(" (%1)").arg( count );
6239 object->setObjectName( objectName );
6240 }
6241}
6242
6243
6244void Sheet::checkContentDirection( TQString const & name )
6245{
6246 /* set sheet's direction to RTL if sheet name is an RTL string */
6247 if ( (name.isRightToLeft()) )
6248 setLayoutDirection( RightToLeft );
6249 else
6250 setLayoutDirection( LeftToRight );
6251
6252 emit sig_refreshView();
6253}
6254
6255bool Sheet::loadSheetStyleFormat( TQDomElement *style )
6256{
6257 TQString hleft, hmiddle, hright;
6258 TQString fleft, fmiddle, fright;
6259 TQDomNode header = KoDom::namedItemNS( *style, KoXmlNS::style, "header" );
6260
6261 if ( !header.isNull() )
6262 {
6263 kdDebug() << "Header exists" << endl;
6264 TQDomNode part = KoDom::namedItemNS( header, KoXmlNS::style, "region-left" );
6265 if ( !part.isNull() )
6266 {
6267 hleft = getPart( part );
6268 kdDebug() << "Header left: " << hleft << endl;
6269 }
6270 else
6271 kdDebug() << "Style:region:left doesn't exist!" << endl;
6272 part = KoDom::namedItemNS( header, KoXmlNS::style, "region-center" );
6273 if ( !part.isNull() )
6274 {
6275 hmiddle = getPart( part );
6276 kdDebug() << "Header middle: " << hmiddle << endl;
6277 }
6278 part = KoDom::namedItemNS( header, KoXmlNS::style, "region-right" );
6279 if ( !part.isNull() )
6280 {
6281 hright = getPart( part );
6282 kdDebug() << "Header right: " << hright << endl;
6283 }
6284 }
6285 //TODO implement it under kspread
6286 TQDomNode headerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "header-left" );
6287 if ( !headerleft.isNull() )
6288 {
6289 TQDomElement e = headerleft.toElement();
6290 if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
6291 kdDebug()<<"header.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
6292 else
6293 kdDebug()<<"header left doesn't has attribute style:display \n";
6294 }
6295 //TODO implement it under kspread
6296 TQDomNode footerleft = KoDom::namedItemNS( *style, KoXmlNS::style, "footer-left" );
6297 if ( !footerleft.isNull() )
6298 {
6299 TQDomElement e = footerleft.toElement();
6300 if ( e.hasAttributeNS( KoXmlNS::style, "display" ) )
6301 kdDebug()<<"footer.hasAttribute( style:display ) :"<<e.hasAttributeNS( KoXmlNS::style, "display" )<<endl;
6302 else
6303 kdDebug()<<"footer left doesn't has attribute style:display \n";
6304 }
6305
6306 TQDomNode footer = KoDom::namedItemNS( *style, KoXmlNS::style, "footer" );
6307
6308 if ( !footer.isNull() )
6309 {
6310 TQDomNode part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-left" );
6311 if ( !part.isNull() )
6312 {
6313 fleft = getPart( part );
6314 kdDebug() << "Footer left: " << fleft << endl;
6315 }
6316 part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-center" );
6317 if ( !part.isNull() )
6318 {
6319 fmiddle = getPart( part );
6320 kdDebug() << "Footer middle: " << fmiddle << endl;
6321 }
6322 part = KoDom::namedItemNS( footer, KoXmlNS::style, "region-right" );
6323 if ( !part.isNull() )
6324 {
6325 fright = getPart( part );
6326 kdDebug() << "Footer right: " << fright << endl;
6327 }
6328 }
6329
6330 print()->setHeadFootLine( hleft, hmiddle, hright,
6331 fleft, fmiddle, fright );
6332 return true;
6333}
6334
6335void Sheet::replaceMacro( TQString & text, const TQString & old, const TQString & newS )
6336{
6337 int n = text.find( old );
6338 if ( n != -1 )
6339 text = text.replace( n, old.length(), newS );
6340}
6341
6342
6343TQString Sheet::getPart( const TQDomNode & part )
6344{
6345 TQString result;
6346 TQDomElement e = KoDom::namedItemNS( part, KoXmlNS::text, "p" );
6347 while ( !e.isNull() )
6348 {
6349 TQString text = e.text();
6350 kdDebug() << "PART: " << text << endl;
6351
6352 TQDomElement macro = KoDom::namedItemNS( e, KoXmlNS::text, "time" );
6353 if ( !macro.isNull() )
6354 replaceMacro( text, macro.text(), "<time>" );
6355
6356 macro = KoDom::namedItemNS( e, KoXmlNS::text, "date" );
6357 if ( !macro.isNull() )
6358 replaceMacro( text, macro.text(), "<date>" );
6359
6360 macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-number" );
6361 if ( !macro.isNull() )
6362 replaceMacro( text, macro.text(), "<page>" );
6363
6364 macro = KoDom::namedItemNS( e, KoXmlNS::text, "page-count" );
6365 if ( !macro.isNull() )
6366 replaceMacro( text, macro.text(), "<pages>" );
6367
6368 macro = KoDom::namedItemNS( e, KoXmlNS::text, "sheet-name" );
6369 if ( !macro.isNull() )
6370 replaceMacro( text, macro.text(), "<sheet>" );
6371
6372 macro = KoDom::namedItemNS( e, KoXmlNS::text, "title" );
6373 if ( !macro.isNull() )
6374 replaceMacro( text, macro.text(), "<name>" );
6375
6376 macro = KoDom::namedItemNS( e, KoXmlNS::text, "file-name" );
6377 if ( !macro.isNull() )
6378 replaceMacro( text, macro.text(), "<file>" );
6379
6380 //add support for multi line into kspread
6381 if ( !result.isEmpty() )
6382 result += '\n';
6383 result += text;
6384 e = e.nextSibling().toElement();
6385 }
6386
6387 return result;
6388}
6389
6390
6391bool Sheet::loadOasis( const TQDomElement& sheetElement, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
6392{
6393 d->layoutDirection = LeftToRight;
6394 if ( sheetElement.hasAttributeNS( KoXmlNS::table, "style-name" ) )
6395 {
6396 TQString stylename = sheetElement.attributeNS( KoXmlNS::table, "style-name", TQString() );
6397 //kdDebug()<<" style of table :"<<stylename<<endl;
6398 const TQDomElement *style = oasisContext.oasisStyles().findStyle( stylename, "table" );
6399 Q_ASSERT( style );
6400 //kdDebug()<<" style :"<<style<<endl;
6401 if ( style )
6402 {
6403 TQDomElement properties( KoDom::namedItemNS( *style, KoXmlNS::style, "table-properties" ) );
6404 if ( !properties.isNull() )
6405 {
6406 if ( properties.hasAttributeNS( KoXmlNS::table, "display" ) )
6407 {
6408 bool visible = (properties.attributeNS( KoXmlNS::table, "display", TQString() ) == "true" ? true : false );
6409 d->hide = !visible;
6410 }
6411 }
6412 if ( style->hasAttributeNS( KoXmlNS::style, "master-page-name" ) )
6413 {
6414 TQString masterPageStyleName = style->attributeNS( KoXmlNS::style, "master-page-name", TQString() );
6415 //kdDebug()<<"style->attribute( style:master-page-name ) :"<<masterPageStyleName <<endl;
6416 TQDomElement *masterStyle = oasisContext.oasisStyles().masterPages()[masterPageStyleName];
6417 //kdDebug()<<"oasisStyles.styles()[masterPageStyleName] :"<<masterStyle<<endl;
6418 if ( masterStyle )
6419 {
6420 loadSheetStyleFormat( masterStyle );
6421 if ( masterStyle->hasAttributeNS( KoXmlNS::style, "page-layout-name" ) )
6422 {
6423 TQString masterPageLayoutStyleName = masterStyle->attributeNS( KoXmlNS::style, "page-layout-name", TQString() );
6424 //kdDebug()<<"masterPageLayoutStyleName :"<<masterPageLayoutStyleName<<endl;
6425 const TQDomElement *masterLayoutStyle = oasisContext.oasisStyles().findStyle( masterPageLayoutStyleName );
6426 if ( masterLayoutStyle )
6427 {
6428 //kdDebug()<<"masterLayoutStyle :"<<masterLayoutStyle<<endl;
6429 KoStyleStack styleStack;
6430 styleStack.setTypeProperties( "page-layout" );
6431 styleStack.push( *masterLayoutStyle );
6432 loadOasisMasterLayoutPage( styleStack );
6433 }
6434 }
6435 }
6436 }
6437 }
6438 }
6439
6440 //Maps from a column index to the name of the default cell style for that column
6441 TQMap<int,TQString> defaultColumnCellStyles;
6442
6443 int rowIndex = 1;
6444 int indexCol = 1;
6445 TQDomNode rowNode = sheetElement.firstChild();
6446 // Some spreadsheet programs may support more rows than
6447 // KSpread so limit the number of repeated rows.
6448 // FIXME POSSIBLE DATA LOSS!
6449 while( !rowNode.isNull() && rowIndex <= KS_rowMax )
6450 {
6451 kdDebug()<<" rowIndex :"<<rowIndex<<" indexCol :"<<indexCol<<endl;
6452 TQDomElement rowElement = rowNode.toElement();
6453 if( !rowElement.isNull() )
6454 {
6455 kdDebug()<<" Sheet::loadOasis rowElement.tagName() :"<<rowElement.localName()<<endl;
6456 if ( rowElement.namespaceURI() == KoXmlNS::table )
6457 {
6458 if ( rowElement.localName()=="table-column" && indexCol <= KS_colMax )
6459 {
6460 kdDebug ()<<" table-column found : index column before "<< indexCol<<endl;
6461 loadColumnFormat( rowElement, oasisContext.oasisStyles(), indexCol , styleMap);
6462 kdDebug ()<<" table-column found : index column after "<< indexCol<<endl;
6463 }
6464 else if ( rowElement.localName() == "table-header-rows" )
6465 {
6466 TQDomNode headerRowNode = rowElement.firstChild();
6467 while ( !headerRowNode.isNull() )
6468 {
6469 // NOTE Handle header rows as ordinary ones
6470 // as long as they're not supported.
6471 loadRowFormat( headerRowNode.toElement(), rowIndex,
6472 oasisContext, /*rowNode.isNull() ,*/ styleMap );
6473 headerRowNode = headerRowNode.nextSibling();
6474 }
6475 }
6476 else if( rowElement.localName() == "table-row" )
6477 {
6478 kdDebug()<<" table-row found :index row before "<<rowIndex<<endl;
6479 loadRowFormat( rowElement, rowIndex, oasisContext, /*rowNode.isNull() ,*/ styleMap );
6480 kdDebug()<<" table-row found :index row after "<<rowIndex<<endl;
6481 }
6482 else if ( rowElement.localName() == "shapes" )
6483 loadOasisObjects( rowElement, oasisContext );
6484 }
6485 }
6486 rowNode = rowNode.nextSibling();
6487 }
6488
6489 if ( sheetElement.hasAttributeNS( KoXmlNS::table, "print-ranges" ) )
6490 {
6491 // e.g.: Sheet4.A1:Sheet4.E28
6492 TQString range = sheetElement.attributeNS( KoXmlNS::table, "print-ranges", TQString() );
6493 range = Oasis::decodeFormula( range );
6494 Range p( range );
6495 if ( sheetName() == p.sheetName() )
6496 d->print->setPrintRange( p.range() );
6497 }
6498
6499
6500 if ( sheetElement.attributeNS( KoXmlNS::table, "protected", TQString() ) == "true" )
6501 {
6502 TQCString passwd( "" );
6503 if ( sheetElement.hasAttributeNS( KoXmlNS::table, "protection-key" ) )
6504 {
6505 TQString p = sheetElement.attributeNS( KoXmlNS::table, "protection-key", TQString() );
6506 TQCString str( p.latin1() );
6507 kdDebug(30518) << "Decoding password: " << str << endl;
6508 passwd = KCodecs::base64Decode( str );
6509 }
6510 kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
6511 d->password = passwd;
6512 }
6513 return true;
6514}
6515
6516
6517void Sheet::loadOasisObjects( const TQDomElement &parent, KoOasisLoadingContext& oasisContext )
6518{
6519 TQDomElement e;
6520 TQDomNode n = parent.firstChild();
6521 while( !n.isNull() )
6522 {
6523 e = n.toElement();
6524 if ( e.localName() == "frame" && e.namespaceURI() == KoXmlNS::draw )
6525 {
6526 EmbeddedObject *obj = 0;
6527 TQDomNode object = KoDom::namedItemNS( e, KoXmlNS::draw, "object" );
6528 if ( !object.isNull() )
6529 {
6530 if ( !object.toElement().attributeNS( KoXmlNS::draw, "notify-on-update-of-ranges", TQString()).isNull() )
6531 obj = new EmbeddedChart( doc(), this );
6532 else
6533 obj = new EmbeddedKOfficeObject( doc(), this );
6534 }
6535 else
6536 {
6537 TQDomNode image = KoDom::namedItemNS( e, KoXmlNS::draw, "image" );
6538 if ( !image.isNull() )
6539 obj = new EmbeddedPictureObject( this, doc()->pictureCollection() );
6540 else
6541 kdDebug() << "Object type wasn't loaded!" << endl;
6542 }
6543
6544 if ( obj )
6545 {
6546 obj->loadOasis( e, oasisContext );
6547 insertObject( obj );
6548 }
6549 }
6550 n = n.nextSibling();
6551 }
6552}
6553
6554
6555void Sheet::loadOasisMasterLayoutPage( KoStyleStack &styleStack )
6556{
6557 // use A4 as default page size
6558 float left = 20.0;
6559 float right = 20.0;
6560 float top = 20.0;
6561 float bottom = 20.0;
6562 float width = 210.0;
6563 float height = 297.0;
6564 TQString orientation = "Portrait";
6565 TQString format;
6566
6567 // Laurent : Why we stored layout information as Millimeter ?!!!!!
6568 // kspread used point for all other attribute
6569 // I don't understand :(
6570 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-width" ) )
6571 {
6572 width = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-width" ) ) );
6573 }
6574 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "page-height" ) )
6575 {
6576 height = KoUnit::toMM( KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "page-height" ) ) );
6577 }
6578 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-top" ) )
6579 {
6580 top = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) ) );
6581 }
6582 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-bottom" ) )
6583 {
6584 bottom = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) ) );
6585 }
6586 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-left" ) )
6587 {
6588 left = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) ) );
6589 }
6590 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "margin-right" ) )
6591 {
6592 right = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) ) );
6593 }
6594 if ( styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" ) )
6595 {
6596 kdDebug()<<"styleStack.hasAttribute( style:writing-mode ) :"<<styleStack.hasAttributeNS( KoXmlNS::style, "writing-mode" )<<endl;
6597 d->layoutDirection = ( styleStack.attributeNS( KoXmlNS::style, "writing-mode" )=="lr-tb" ) ? LeftToRight : RightToLeft;
6598 //TODO
6599 //<value>lr-tb</value>
6600 //<value>rl-tb</value>
6601 //<value>tb-rl</value>
6602 //<value>tb-lr</value>
6603 //<value>lr</value>
6604 //<value>rl</value>
6605 //<value>tb</value>
6606 //<value>page</value>
6607
6608 }
6609 if ( styleStack.hasAttributeNS( KoXmlNS::style, "print-orientation" ) )
6610 {
6611 orientation = ( styleStack.attributeNS( KoXmlNS::style, "print-orientation" )=="landscape" ) ? "Landscape" : "Portrait" ;
6612 }
6613 if ( styleStack.hasAttributeNS( KoXmlNS::style, "num-format" ) )
6614 {
6615 //not implemented into kspread
6616 //These attributes specify the numbering style to use.
6617 //If a numbering style is not specified, the numbering style is inherited from
6618 //the page style. See section 6.7.8 for information on these attributes
6619 kdDebug()<<" num-format :"<<styleStack.attributeNS( KoXmlNS::style, "num-format" )<<endl;
6620
6621 }
6622 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) )
6623 {
6624 //TODO
6625 kdDebug()<<" fo:background-color :"<<styleStack.attributeNS( KoXmlNS::fo, "background-color" )<<endl;
6626 }
6627 if ( styleStack.hasAttributeNS( KoXmlNS::style, "print" ) )
6628 {
6629 //todo parsing
6630 TQString str = styleStack.attributeNS( KoXmlNS::style, "print" );
6631 kdDebug()<<" style:print :"<<str<<endl;
6632
6633 if (str.contains( "headers" ) )
6634 {
6635 //TODO implement it into kspread
6636 }
6637 if ( str.contains( "grid" ) )
6638 {
6639 d->print->setPrintGrid( true );
6640 }
6641 if ( str.contains( "annotations" ) )
6642 {
6643 //TODO it's not implemented
6644 }
6645 if ( str.contains( "objects" ) )
6646 {
6647 //TODO it's not implemented
6648 }
6649 if ( str.contains( "charts" ) )
6650 {
6651 //TODO it's not implemented
6652 }
6653 if ( str.contains( "drawings" ) )
6654 {
6655 //TODO it's not implemented
6656 }
6657 if ( str.contains( "formulas" ) )
6658 {
6659 d->showFormula = true;
6660 }
6661 if ( str.contains( "zero-values" ) )
6662 {
6663 //TODO it's not implemented
6664 }
6665 }
6666 if ( styleStack.hasAttributeNS( KoXmlNS::style, "table-centering" ) )
6667 {
6668 TQString str = styleStack.attributeNS( KoXmlNS::style, "table-centering" );
6669 //TODO not implemented into kspread
6670 kdDebug()<<" styleStack.attribute( style:table-centering ) :"<<str<<endl;
6671#if 0
6672 if ( str == "horizontal" )
6673 {
6674 }
6675 else if ( str == "vertical" )
6676 {
6677 }
6678 else if ( str == "both" )
6679 {
6680 }
6681 else if ( str == "none" )
6682 {
6683 }
6684 else
6685 kdDebug()<<" table-centering unknown :"<<str<<endl;
6686#endif
6687 }
6688 format = TQString( "%1x%2" ).arg( width ).arg( height );
6689 kdDebug()<<" format : "<<format<<endl;
6690 d->print->setPaperLayout( left, top, right, bottom, format, orientation );
6691
6692 kdDebug()<<" left margin :"<<left<<" right :"<<right<<" top :"<<top<<" bottom :"<<bottom<<endl;
6693//<style:properties fo:page-width="21.8cm" fo:page-height="28.801cm" fo:margin-top="2cm" fo:margin-bottom="2.799cm" fo:margin-left="1.3cm" fo:margin-right="1.3cm" style:writing-mode="lr-tb"/>
6694// TQString format = paper.attribute( "format" );
6695// TQString orientation = paper.attribute( "orientation" );
6696// d->print->setPaperLayout( left, top, right, bottom, format, orientation );
6697// }
6698}
6699
6700
6701bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, int & indexCol, const TQDict<Style>& styleMap)
6702{
6703 kdDebug()<<"bool Sheet::loadColumnFormat(const TQDomElement& column, const KoOasisStyles& oasisStyles, unsigned int & indexCol ) index Col :"<<indexCol<<endl;
6704
6705 bool isNonDefaultColumn = false;
6706
6707 int number = 1;
6708 if ( column.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
6709 {
6710 bool ok = true;
6711 int n = column.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
6712 if ( ok )
6713 // Some spreadsheet programs may support more rows than KSpread so
6714 // limit the number of repeated rows.
6715 // FIXME POSSIBLE DATA LOSS!
6716 number = TQMIN( n, KS_colMax - indexCol + 1 );
6717 kdDebug() << "Repeated: " << number << endl;
6718 }
6719
6720 Format layout( this , doc()->styleManager()->defaultStyle() );
6721 if ( column.hasAttributeNS( KoXmlNS::table, "default-cell-style-name" ) )
6722 {
6723 const TQString styleName = column.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
6724 if ( !styleName.isEmpty() )
6725 {
6726 Style* const style = styleMap[ styleName ];
6727 if ( style )
6728 {
6729 layout.setStyle( style );
6730 isNonDefaultColumn = true;
6731 }
6732 }
6733 }
6734
6735 bool collapsed = false;
6736 if ( column.hasAttributeNS( KoXmlNS::table, "visibility" ) )
6737 {
6738 const TQString visibility = column.attributeNS( KoXmlNS::table, "visibility", TQString() );
6739 if ( visibility == "visible" )
6740 collapsed = false;
6741 else if ( visibility == "collapse" )
6742 collapsed = true;
6743 else if ( visibility == "filter" )
6744 collapsed = false; // FIXME Stefan: Set to true, if filters are supported.
6745 isNonDefaultColumn = true;
6746 }
6747
6748 KoStyleStack styleStack;
6749 if ( column.hasAttributeNS( KoXmlNS::table, "style-name" ) )
6750 {
6751 TQString str = column.attributeNS( KoXmlNS::table, "style-name", TQString() );
6752 const TQDomElement *style = oasisStyles.findStyle( str, "table-column" );
6753 if ( style )
6754 {
6755 styleStack.push( *style );
6756 isNonDefaultColumn = true;
6757 }
6758 }
6759 styleStack.setTypeProperties("table-column"); //style for column
6760
6761 double width = -1.0;
6762 if ( styleStack.hasAttributeNS( KoXmlNS::style, "column-width" ) )
6763 {
6764 width = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "column-width" ) , -1.0 );
6765 kdDebug()<<" style:column-width : width :"<<width<<endl;
6766 isNonDefaultColumn = true;
6767 }
6768
6769 bool insertPageBreak = false;
6770 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
6771 {
6772 TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
6773 if ( str == "page" )
6774 {
6775 insertPageBreak = true;
6776 }
6777 else
6778 kdDebug()<<" str :"<<str<<endl;
6779 isNonDefaultColumn = true;
6780 }
6781
6782 for ( int i = 0; i < number; ++i )
6783 {
6784// kdDebug()<<" insert new column: pos :"<<indexCol<<" width :"<<width<<" hidden ? "<<collapsed<<endl;
6785
6786 ColumnFormat* columnFormat;
6787 if ( isNonDefaultColumn )
6788 {
6789 columnFormat = nonDefaultColumnFormat( indexCol );
6790
6791 if ( width != -1.0 ) //safe
6792 columnFormat->setWidth( (int) width );
6793 // if ( insertPageBreak )
6794 // columnFormat->setPageBreak( true )
6795 if ( collapsed )
6796 columnFormat->setHide( true );
6797 }
6798 else
6799 {
6800 columnFormat = this->columnFormat( indexCol );
6801 }
6802 columnFormat->copy( layout );
6803
6804 ++indexCol;
6805 }
6806// kdDebug()<<" after index column !!!!!!!!!!!!!!!!!! :"<<indexCol<<endl;
6807 return true;
6808}
6809
6810
6811bool Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex, KoOasisLoadingContext& oasisContext, TQDict<Style>& styleMap )
6812{
6813// kdDebug()<<"Sheet::loadRowFormat( const TQDomElement& row, int &rowIndex,const KoOasisStyles& oasisStyles, bool isLast )***********\n";
6814
6815 int backupRow = rowIndex;
6816 bool isNonDefaultRow = false;
6817
6818 KoStyleStack styleStack;
6819 if ( row.hasAttributeNS( KoXmlNS::table, "style-name" ) )
6820 {
6821 TQString str = row.attributeNS( KoXmlNS::table, "style-name", TQString() );
6822 const TQDomElement *style = oasisContext.oasisStyles().findStyle( str, "table-row" );
6823 if ( style )
6824 {
6825 styleStack.push( *style );
6826 isNonDefaultRow = true;
6827 }
6828 }
6829 styleStack.setTypeProperties( "table-row" );
6830
6831 Format layout( this , doc()->styleManager()->defaultStyle() );
6832 if ( row.hasAttributeNS( KoXmlNS::table,"default-cell-style-name" ) )
6833 {
6834 const TQString styleName = row.attributeNS( KoXmlNS::table, "default-cell-style-name", TQString() );
6835 if ( !styleName.isEmpty() )
6836 {
6837 Style* const style = styleMap[ styleName ];
6838 if ( style )
6839 {
6840 layout.setStyle( style );
6841 isNonDefaultRow = true;
6842 }
6843 }
6844 }
6845
6846 double height = -1.0;
6847 if ( styleStack.hasAttributeNS( KoXmlNS::style, "row-height" ) )
6848 {
6849 height = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::style, "row-height" ) , -1.0 );
6850 // kdDebug()<<" properties style:row-height : height :"<<height<<endl;
6851 isNonDefaultRow = true;
6852 }
6853
6854 int number = 1;
6855 if ( row.hasAttributeNS( KoXmlNS::table, "number-rows-repeated" ) )
6856 {
6857 bool ok = true;
6858 int n = row.attributeNS( KoXmlNS::table, "number-rows-repeated", TQString() ).toInt( &ok );
6859 if ( ok )
6860 // Some spreadsheet programs may support more rows than KSpread so
6861 // limit the number of repeated rows.
6862 // FIXME POSSIBLE DATA LOSS!
6863 number = TQMIN( n, KS_rowMax - rowIndex + 1 );
6864 }
6865
6866 bool collapse = false;
6867 if ( row.hasAttributeNS( KoXmlNS::table, "visibility" ) )
6868 {
6869 const TQString visibility = row.attributeNS( KoXmlNS::table, "visibility", TQString() );
6870 if ( visibility == "visible" )
6871 collapse = false;
6872 else if ( visibility == "collapse" )
6873 collapse = true;
6874 else if ( visibility == "filter" )
6875 collapse = false; // FIXME Stefan: Set to true, if filters are supported.
6876 isNonDefaultRow = true;
6877 }
6878
6879 bool insertPageBreak = false;
6880 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "break-before" ) )
6881 {
6882 TQString str = styleStack.attributeNS( KoXmlNS::fo, "break-before" );
6883 if ( str == "page" )
6884 {
6885 insertPageBreak = true;
6886 }
6887 // else
6888 // kdDebug()<<" str :"<<str<<endl;
6889 isNonDefaultRow = true;
6890 }
6891
6892 //number == number of row to be copy. But we must copy cell too.
6893 for ( int i = 0; i < number; ++i )
6894 {
6895 // kdDebug()<<" create non defaultrow format :"<<rowIndex<<" repeate : "<<number<<" height :"<<height<<endl;
6896
6897 RowFormat* rowFormat;
6898 if ( isNonDefaultRow )
6899 {
6900 rowFormat = nonDefaultRowFormat( rowIndex );
6901
6902 if ( height != -1.0 )
6903 rowFormat->setHeight( (int) height );
6904 if ( collapse )
6905 rowFormat->setHide( true );
6906 }
6907 else
6908 {
6909 rowFormat = this->rowFormat( rowIndex );
6910 }
6911 rowFormat->copy( layout );
6912
6913 ++rowIndex;
6914 }
6915
6916 int columnIndex = 0;
6917 TQDomNode cellNode = row.firstChild();
6918 int endRow = min(backupRow+number,KS_rowMax);
6919
6920
6921 while ( !cellNode.isNull() )
6922 {
6923 TQDomElement cellElement = cellNode.toElement();
6924 if ( !cellElement.isNull() )
6925 {
6926 columnIndex++;
6927 TQString localName = cellElement.localName();
6928
6929 if ( ((localName == "table-cell") || (localName == "covered-table-cell")) && cellElement.namespaceURI() == KoXmlNS::table)
6930 {
6931 //kdDebug() << "Loading cell #" << cellCount << endl;
6932
6933 Style* style = 0;
6934 const bool cellHasStyle = cellElement.hasAttributeNS( KoXmlNS::table, "style-name" );
6935 if ( cellHasStyle )
6936 {
6937 style = styleMap[ cellElement.attributeNS( KoXmlNS::table , "style-name" , TQString() ) ];
6938 }
6939
6940 Cell* const cell = nonDefaultCell( columnIndex, backupRow ); // FIXME Stefan: if empty, delete afterwards
6941 cell->loadOasis( cellElement, oasisContext, style );
6942
6943 int cols = 1;
6944
6945 // Copy this cell across & down, if it has repeated rows or columns, but only
6946 // if the cell has some content or a style associated with it.
6947 if ( (number > 1) || cellElement.hasAttributeNS( KoXmlNS::table, "number-columns-repeated" ) )
6948 {
6949 bool ok = false;
6950 int n = cellElement.attributeNS( KoXmlNS::table, "number-columns-repeated", TQString() ).toInt( &ok );
6951
6952 if (ok)
6953 // Some spreadsheet programs may support more columns than
6954 // KSpread so limit the number of repeated columns.
6955 // FIXME POSSIBLE DATA LOSS!
6956 cols = TQMIN( n, KS_colMax - columnIndex + 1 );
6957
6958 if ( !cellHasStyle && ( cell->isEmpty() && cell->format()->comment( columnIndex, backupRow ).isEmpty() ) )
6959 {
6960 // just increment it
6961 columnIndex += cols - 1;
6962 }
6963 else
6964 {
6965 for ( int k = cols ; k ; --k )
6966 {
6967 if ( k != cols )
6968 columnIndex++;
6969
6970 for ( int newRow = backupRow; newRow < endRow; ++newRow )
6971 {
6972 Cell* target = nonDefaultCell( columnIndex, newRow );
6973
6974 if (cell != target)
6975 target->copyAll( cell );
6976 }
6977 }
6978 }
6979 }
6980 }
6981 }
6982 cellNode = cellNode.nextSibling();
6983 }
6984
6985 return true;
6986}
6987
6988void Sheet::maxRowCols( int & maxCols, int & maxRows )
6989{
6990 const Cell * cell = firstCell();
6991 while ( cell )
6992 {
6993 if ( cell->column() > maxCols )
6994 maxCols = cell->column();
6995
6996 if ( cell->row() > maxRows )
6997 maxRows = cell->row();
6998
6999 cell = cell->nextCell();
7000 }
7001
7002 const RowFormat * row = firstRow();
7003 while ( row )
7004 {
7005 if ( row->row() > maxRows )
7006 maxRows = row->row();
7007
7008 row = row->next();
7009 }
7010 const ColumnFormat* col = firstCol();
7011 while ( col )
7012 {
7013 if ( col->column() > maxCols )
7014 maxCols = col->column();
7015
7016 col = col->next();
7017 }
7018}
7019
7020
7021bool Sheet::compareRows( int row1, int row2, int& maxCols ) const
7022{
7023 if ( *rowFormat( row1 ) != *rowFormat( row2 ) )
7024 {
7025// kdDebug() << "\t Formats of " << row1 << " and " << row2 << " are different" << endl;
7026 return false;
7027 }
7028 // FIXME Stefan: Make use of the cluster functionality.
7029 for ( int col = 1; col <= maxCols; ++col )
7030 {
7031 if ( *cellAt( col, row1 ) != *cellAt( col, row2 ) )
7032 {
7033// kdDebug() << "\t Cell at column " << col << " in row " << row2 << " differs from the one in row " << row1 << endl;
7034 return false;
7035 }
7036 }
7037 return true;
7038}
7039
7040
7041void Sheet::saveOasisHeaderFooter( KoXmlWriter &xmlWriter ) const
7042{
7043 TQString headerLeft = print()->headLeft();
7044 TQString headerCenter= print()->headMid();
7045 TQString headerRight = print()->headRight();
7046
7047 TQString footerLeft = print()->footLeft();
7048 TQString footerCenter= print()->footMid();
7049 TQString footerRight = print()->footRight();
7050
7051 xmlWriter.startElement( "style:header");
7052 if ( ( !headerLeft.isEmpty() )
7053 || ( !headerCenter.isEmpty() )
7054 || ( !headerRight.isEmpty() ) )
7055 {
7056 xmlWriter.startElement( "style:region-left" );
7057 xmlWriter.startElement( "text:p" );
7058 convertPart( headerLeft, xmlWriter );
7059 xmlWriter.endElement();
7060 xmlWriter.endElement();
7061
7062 xmlWriter.startElement( "style:region-center" );
7063 xmlWriter.startElement( "text:p" );
7064 convertPart( headerCenter, xmlWriter );
7065 xmlWriter.endElement();
7066 xmlWriter.endElement();
7067
7068 xmlWriter.startElement( "style:region-right" );
7069 xmlWriter.startElement( "text:p" );
7070 convertPart( headerRight, xmlWriter );
7071 xmlWriter.endElement();
7072 xmlWriter.endElement();
7073 }
7074 else
7075 {
7076 xmlWriter.startElement( "text:p" );
7077
7078 xmlWriter.startElement( "text:sheet-name" );
7079 xmlWriter.addTextNode( "???" );
7080 xmlWriter.endElement();
7081
7082 xmlWriter.endElement();
7083 }
7084 xmlWriter.endElement();
7085
7086
7087 xmlWriter.startElement( "style:footer");
7088 if ( ( !footerLeft.isEmpty() )
7089 || ( !footerCenter.isEmpty() )
7090 || ( !footerRight.isEmpty() ) )
7091 {
7092 xmlWriter.startElement( "style:region-left" );
7093 xmlWriter.startElement( "text:p" );
7094 convertPart( footerLeft, xmlWriter );
7095 xmlWriter.endElement();
7096 xmlWriter.endElement(); //style:region-left
7097
7098 xmlWriter.startElement( "style:region-center" );
7099 xmlWriter.startElement( "text:p" );
7100 convertPart( footerCenter, xmlWriter );
7101 xmlWriter.endElement();
7102 xmlWriter.endElement();
7103
7104 xmlWriter.startElement( "style:region-right" );
7105 xmlWriter.startElement( "text:p" );
7106 convertPart( footerRight, xmlWriter );
7107 xmlWriter.endElement();
7108 xmlWriter.endElement();
7109 }
7110 else
7111 {
7112 xmlWriter.startElement( "text:p" );
7113
7114 xmlWriter.startElement( "text:sheet-name" );
7115 xmlWriter.addTextNode( "Page " ); // ???
7116 xmlWriter.endElement();
7117
7118 xmlWriter.startElement( "text:page-number" );
7119 xmlWriter.addTextNode( "1" ); // ???
7120 xmlWriter.endElement();
7121
7122 xmlWriter.endElement();
7123 }
7124 xmlWriter.endElement();
7125
7126
7127}
7128
7129void Sheet::addText( const TQString & text, KoXmlWriter & writer ) const
7130{
7131 if ( !text.isEmpty() )
7132 writer.addTextNode( text );
7133}
7134
7135void Sheet::convertPart( const TQString & part, KoXmlWriter & xmlWriter ) const
7136{
7137 TQString text;
7138 TQString var;
7139
7140 bool inVar = false;
7141 uint i = 0;
7142 uint l = part.length();
7143 while ( i < l )
7144 {
7145 if ( inVar || part[i] == '<' )
7146 {
7147 inVar = true;
7148 var += part[i];
7149 if ( part[i] == '>' )
7150 {
7151 inVar = false;
7152 if ( var == "<page>" )
7153 {
7154 addText( text, xmlWriter );
7155 xmlWriter.startElement( "text:page-number" );
7156 xmlWriter.addTextNode( "1" );
7157 xmlWriter.endElement();
7158 }
7159 else if ( var == "<pages>" )
7160 {
7161 addText( text, xmlWriter );
7162 xmlWriter.startElement( "text:page-count" );
7163 xmlWriter.addTextNode( "99" ); //TODO I think that it can be different from 99
7164 xmlWriter.endElement();
7165 }
7166 else if ( var == "<date>" )
7167 {
7168 addText( text, xmlWriter );
7169 //text:p><text:date style:data-style-name="N2" text:date-value="2005-10-02">02/10/2005</text:date>, <text:time>10:20:12</text:time></text:p> "add style" => create new style
7170#if 0 //FIXME
7171 TQDomElement t = dd.createElement( "text:date" );
7172 t.setAttribute( "text:date-value", "0-00-00" );
7173 // todo: "style:data-style-name", "N2"
7174 t.appendChild( dd.createTextNode( TQDate::currentDate().toString() ) );
7175 parent.appendChild( t );
7176#endif
7177 }
7178 else if ( var == "<time>" )
7179 {
7180 addText( text, xmlWriter );
7181
7182 xmlWriter.startElement( "text:time" );
7183 xmlWriter.addTextNode( TQTime::currentTime().toString() );
7184 xmlWriter.endElement();
7185 }
7186 else if ( var == "<file>" ) // filepath + name
7187 {
7188 addText( text, xmlWriter );
7189 xmlWriter.startElement( "text:file-name" );
7190 xmlWriter.addAttribute( "text:display", "full" );
7191 xmlWriter.addTextNode( "???" );
7192 xmlWriter.endElement();
7193 }
7194 else if ( var == "<name>" ) // filename
7195 {
7196 addText( text, xmlWriter );
7197
7198 xmlWriter.startElement( "text:title" );
7199 xmlWriter.addTextNode( "???" );
7200 xmlWriter.endElement();
7201 }
7202 else if ( var == "<author>" )
7203 {
7204 Doc* sdoc = d->workbook->doc();
7205 KoDocumentInfo * docInfo = sdoc->documentInfo();
7206 KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
7207
7208 text += authorPage->fullName();
7209
7210 addText( text, xmlWriter );
7211 }
7212 else if ( var == "<email>" )
7213 {
7214 Doc* sdoc = d->workbook->doc();
7215 KoDocumentInfo * docInfo = sdoc->documentInfo();
7216 KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
7217
7218 text += authorPage->email();
7219 addText( text, xmlWriter );
7220
7221 }
7222 else if ( var == "<org>" )
7223 {
7224 Doc* sdoc = d->workbook->doc();
7225 KoDocumentInfo * docInfo = sdoc->documentInfo();
7226 KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
7227
7228 text += authorPage->company();
7229 addText( text, xmlWriter );
7230
7231 }
7232 else if ( var == "<sheet>" )
7233 {
7234 addText( text, xmlWriter );
7235
7236 xmlWriter.startElement( "text:sheet-name" );
7237 xmlWriter.addTextNode( "???" );
7238 xmlWriter.endElement();
7239 }
7240 else
7241 {
7242 // no known variable:
7243 text += var;
7244 addText( text, xmlWriter );
7245 }
7246
7247 text = "";
7248 var = "";
7249 }
7250 }
7251 else
7252 {
7253 text += part[i];
7254 }
7255 ++i;
7256 }
7257 if ( !text.isEmpty() || !var.isEmpty() )
7258 {
7259 //we don't have var at the end =>store it
7260 addText( text+var, xmlWriter );
7261 }
7262 kdDebug()<<" text end :"<<text<<" var :"<<var<<endl;
7263}
7264
7265
7266void Sheet::loadOasisSettings( const KoOasisSettings::NamedMap &settings )
7267{
7268 // Find the entry in the map that applies to this sheet (by name)
7269 KoOasisSettings::Items items = settings.entry( d->name );
7270 if ( items.isNull() )
7271 return;
7272 d->hideZero = items.parseConfigItemBool( "ShowZeroValues" );
7273 d->showGrid = items.parseConfigItemBool( "ShowGrid" );
7274 d->firstLetterUpper = items.parseConfigItemBool( "FirstLetterUpper" );
7275
7276 int cursorX = items.parseConfigItemInt( "CursorPositionX" );
7277 int cursorY = items.parseConfigItemInt( "CursorPositionY" );
7278 doc()->loadingInfo()->setCursorPosition( this, TQPoint( cursorX, cursorY ) );
7279
7280 double offsetX = items.parseConfigItemDouble( "xOffset" );
7281 double offsetY = items.parseConfigItemDouble( "yOffset" );
7282 doc()->loadingInfo()->setScrollingOffset( this, KoPoint( offsetX, offsetY ) );
7283
7284 d->showFormulaIndicator = items.parseConfigItemBool( "ShowFormulaIndicator" );
7285 d->showCommentIndicator = items.parseConfigItemBool( "ShowCommentIndicator" );
7286 d->showPageBorders = items.parseConfigItemBool( "ShowPageBorders" );
7287 d->lcMode = items.parseConfigItemBool( "lcmode" );
7288 d->autoCalc = items.parseConfigItemBool( "autoCalc" );
7289 d->showColumnNumber = items.parseConfigItemBool( "ShowColumnNumber" );
7290}
7291
7292void Sheet::saveOasisSettings( KoXmlWriter &settingsWriter ) const
7293{
7294 //not into each page into oo spec
7295 settingsWriter.addConfigItem( "ShowZeroValues", d->hideZero );
7296 settingsWriter.addConfigItem( "ShowGrid", d->showGrid );
7297 //not define into oo spec
7298 settingsWriter.addConfigItem( "FirstLetterUpper", d->firstLetterUpper);
7299 settingsWriter.addConfigItem( "ShowFormulaIndicator", d->showFormulaIndicator );
7300 settingsWriter.addConfigItem( "ShowCommentIndicator", d->showCommentIndicator );
7301 settingsWriter.addConfigItem( "ShowPageBorders",d->showPageBorders );
7302 settingsWriter.addConfigItem( "lcmode", d->lcMode );
7303 settingsWriter.addConfigItem( "autoCalc", d->autoCalc );
7304 settingsWriter.addConfigItem( "ShowColumnNumber", d->showColumnNumber );
7305}
7306
7307bool Sheet::saveOasis( KoXmlWriter & xmlWriter, KoGenStyles &mainStyles, GenValidationStyles &valStyle, KoStore *store, KoXmlWriter* /*manifestWriter*/, int &indexObj, int &partIndexObj )
7308{
7309 int maxCols= 1;
7310 int maxRows= 1;
7311 xmlWriter.startElement( "table:table" );
7312 xmlWriter.addAttribute( "table:name", d->name );
7313 xmlWriter.addAttribute( "table:style-name", saveOasisSheetStyleName(mainStyles ) );
7314 if ( !d->password.isEmpty() )
7315 {
7316 xmlWriter.addAttribute("table:protected", "true" );
7317 TQCString str = KCodecs::base64Encode( d->password );
7318 xmlWriter.addAttribute("table:protection-key", TQString( str.data() ) );/* FIXME !!!!*/
7319 }
7320 TQRect _printRange = d->print->printRange();
7321 if ( _printRange != ( TQRect( TQPoint( 1, 1 ), TQPoint( KS_colMax, KS_rowMax ) ) ) )
7322 {
7323 TQString range= convertRangeToRef( d->name, _printRange );
7324 kdDebug()<<" range : "<<range<<endl;
7325 xmlWriter.addAttribute( "table:print-ranges", range );
7326 }
7327
7328 saveOasisObjects( store, xmlWriter, mainStyles, indexObj, partIndexObj );
7329 maxRowCols( maxCols, maxRows );
7330 saveOasisColRowCell( xmlWriter, mainStyles, maxCols, maxRows, valStyle );
7331 xmlWriter.endElement();
7332 return true;
7333}
7334
7335void Sheet::saveOasisPrintStyleLayout( KoGenStyle &style ) const
7336{
7337 TQString printParameter;
7338 if ( d->print->printGrid() )
7339 printParameter="grid ";
7340 if ( d->print->printObjects() )
7341 printParameter+="objects ";
7342 if ( d->print->printCharts() )
7343 printParameter+="charts ";
7344 if ( d->showFormula )
7345 printParameter+="formulas ";
7346 if ( !printParameter.isEmpty() )
7347 {
7348 printParameter+="drawings zero-values"; //default print style attributes in OO
7349 style.addProperty( "style:print", printParameter );
7350 }
7351}
7352
7353TQString Sheet::saveOasisSheetStyleName( KoGenStyles &mainStyles )
7354{
7355 KoGenStyle pageStyle( Doc::STYLE_PAGE, "table"/*FIXME I don't know if name is sheet*/ );
7356
7357 KoGenStyle pageMaster( Doc::STYLE_PAGEMASTER );
7358 pageMaster.addAttribute( "style:page-layout-name", d->print->saveOasisSheetStyleLayout( mainStyles ) );
7359
7360 TQBuffer buffer;
7361 buffer.open( IO_WriteOnly );
7362 KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level
7363 saveOasisHeaderFooter(elementWriter);
7364
7365 TQString elementContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
7366 pageMaster.addChildElement( "headerfooter", elementContents );
7367 pageStyle.addAttribute( "style:master-page-name", mainStyles.lookup( pageMaster, "Standard" ) );
7368
7369 pageStyle.addProperty( "table:display", !d->hide );
7370 return mainStyles.lookup( pageStyle, "ta" );
7371}
7372
7373
7374void Sheet::saveOasisColRowCell( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles,
7375 int maxCols, int maxRows, GenValidationStyles &valStyle )
7376{
7377 kdDebug() << "Sheet::saveOasisColRowCell: " << d->name << endl;
7378 kdDebug() << "\t Sheet dimension: " << maxCols << " x " << maxRows << endl;
7379
7380 // saving the columns
7381 //
7382 int i = 1;
7383 while ( i <= maxCols )
7384 {
7385// kdDebug() << "Sheet::saveOasisColRowCell: first col loop:"
7386// << " i: " << i
7387// << " column: " << column->column() << endl;
7388 ColumnFormat* column = columnFormat( i );
7389
7390 KoGenStyle currentColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
7391 currentColumnStyle.addPropertyPt( "style:column-width", column->dblWidth() );
7392 currentColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
7393
7394 //style default layout for column
7395 KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
7396 TQString currentDefaultCellStyleName = column->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
7397
7398
7399 bool hide = column->isHide();
7400 bool refColumnIsDefault = column->isDefault();
7401 int j = i;
7402 int repeated = 1;
7403
7404 while ( j <= maxCols )
7405 {
7406// kdDebug() << "Sheet::saveOasisColRowCell: second col loop:"
7407// << " j: " << j
7408// << " column: " << nextColumn->column() << endl;
7409 ColumnFormat* nextColumn = d->columns.next( j++ );
7410
7411 // no next or not the adjacent column?
7412 if ( !nextColumn || nextColumn->column() != j )
7413 {
7414 if ( refColumnIsDefault )
7415 {
7416 // if the origin column was a default column,
7417 // we count the default columns
7418 if ( !nextColumn )
7419 {
7420 repeated = maxCols - i + 1;
7421 }
7422 else
7423 {
7424 repeated = nextColumn->column() - j + 1;
7425 }
7426 }
7427 // otherwise we just stop here to process the adjacent
7428 // column in the next iteration of the outer loop
7429 break;
7430 }
7431#if 0
7432 KoGenStyle nextColumnStyle( Doc::STYLE_COLUMN_AUTO, "table-column" );
7433 nextColumnStyle.addPropertyPt( "style:column-width", nextColumn->dblWidth() );/*FIXME pt and not mm */
7434 nextColumnStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
7435
7436 KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
7437 TQString nextDefaultCellStyleName = nextColumn->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
7438
7439 if ( hide != nextColumn->isHide() ||
7440 nextDefaultCellStyleName != currentDefaultCellStyleName ||
7441 !( nextColumnStyle == currentColumnStyle ) )
7442 {
7443 break;
7444 }
7445#endif
7446 if ( *column != *nextColumn )
7447 {
7448 break;
7449 }
7450 ++repeated;
7451 }
7452 xmlWriter.startElement( "table:table-column" );
7453 if ( !column->isDefault() )
7454 {
7455 xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentColumnStyle, "co" ) );
7456
7457 if ( !currentDefaultCellStyle.isDefaultStyle() )
7458 xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
7459
7460 if ( hide )
7461 xmlWriter.addAttribute( "table:visibility", "collapse" );
7462 }
7463
7464 if ( repeated > 1 )
7465 xmlWriter.addAttribute( "table:number-columns-repeated", repeated );
7466
7467 xmlWriter.endElement();
7468
7469 kdDebug() << "Sheet::saveOasisColRowCell: column " << i << " "
7470 << "repeated " << repeated << " time(s)" << endl;
7471 i += repeated;
7472 }
7473
7474
7475 // saving the rows and the cells
7476 // we have to loop through all rows of the used area
7477 for ( i = 1; i <= maxRows; ++i )
7478 {
7479 RowFormat* const row = rowFormat( i );
7480
7481 KoGenStyle currentRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
7482 currentRowStyle.addPropertyPt( "style:row-height", row->dblHeight() );
7483 currentRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
7484
7485 // default cell style for row
7486 KoGenStyle currentDefaultCellStyle; // the type is determined in saveOasisCellStyle
7487 TQString currentDefaultCellStyleName = row->saveOasisCellStyle( currentDefaultCellStyle, mainStyles );
7488
7489 xmlWriter.startElement( "table:table-row" );
7490
7491 if ( !row->isDefault() )
7492 {
7493 xmlWriter.addAttribute( "table:style-name", mainStyles.lookup( currentRowStyle, "ro" ) );
7494 }
7495 int repeated = 1;
7496 // empty row?
7497 if ( !getFirstCellRow( i ) )
7498 {
7499// kDebug() << "Sheet::saveOasisColRowCell: first row loop:"
7500// << " i: " << i
7501// << " row: " << row->row() << endl;
7502 //bool isHidden = row->isHide();
7503 bool isDefault = row->isDefault();
7504 int j = i + 1;
7505
7506 // search for
7507 // next non-empty row
7508 // or
7509 // next row with different Format
7510 while ( j <= maxRows && !getFirstCellRow( j ) )
7511 {
7512 RowFormat* const nextRow = rowFormat( j );
7513// kDebug() << "Sheet::saveOasisColRowCell: second row loop:"
7514// << " j: " << j
7515// << " row: " << nextRow->row() << endl;
7516
7517 // if the reference row has the default row format
7518 if ( isDefault )
7519 {
7520 // if the next is not default, stop here
7521 if ( !nextRow->isDefault() )
7522 break;
7523 // otherwise, jump to the next
7524 ++j;
7525 continue;
7526 }
7527#if 0
7528 // create the Oasis representation of the format for the comparison
7529 KoGenStyle nextRowStyle( Doc::STYLE_ROW_AUTO, "table-row" );
7530 nextRowStyle.addPropertyPt( "style:row-height", nextRow->dblHeight() );
7531 nextRowStyle.addProperty( "fo:break-before", "auto" );/*FIXME auto or not ?*/
7532
7533 // default cell style name for next row
7534 KoGenStyle nextDefaultCellStyle; // the type is determined in saveOasisCellStyle
7535 TQString nextDefaultCellStyleName = nextRow->saveOasisCellStyle( nextDefaultCellStyle, mainStyles );
7536
7537 // if the formats differ, stop here
7538 if ( isHidden != nextRow->isHide() ||
7539 nextDefaultCellStyleName != currentDefaultCellStyleName ||
7540 !(nextRowStyle == currentRowStyle) )
7541 {
7542 break;
7543 }
7544#endif
7545 if ( *row != *nextRow )
7546 {
7547 break;
7548 }
7549 // otherwise, process the next
7550 ++j;
7551 }
7552 repeated = j - i;
7553
7554 if ( repeated > 1 )
7555 xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
7556 if ( !currentDefaultCellStyle.isDefaultStyle() )
7557 xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
7558 if ( row->isHide() ) // never true for the default row
7559 xmlWriter.addAttribute( "table:visibility", "collapse" );
7560
7561 // NOTE Stefan: Even if paragraph 8.1 states, that rows may be empty, the
7562 // RelaxNG schema does not allow that.
7563 xmlWriter.startElement( "table:table-cell" );
7564 xmlWriter.endElement();
7565
7566 kdDebug() << "Sheet::saveOasisColRowCell: empty row " << i << ' '
7567 << "repeated " << repeated << " time(s)" << endl;
7568
7569 // copy the index for the next row to process
7570 i = j - 1; /*it's already incremented in the for loop*/
7571 }
7572 else // row is not empty
7573 {
7574 if ( !currentDefaultCellStyle.isDefaultStyle() )
7575 xmlWriter.addAttribute( "table:default-cell-style-name", currentDefaultCellStyleName );
7576 if ( row->isHide() ) // never true for the default row
7577 xmlWriter.addAttribute( "table:visibility", "collapse" );
7578
7579 int j = i + 1;
7580 while ( compareRows( i, j, maxCols ) && j <= maxRows )
7581 {
7582 j++;
7583 repeated++;
7584 }
7585 if ( repeated > 1 )
7586 {
7587 kdDebug() << "Sheet::saveOasisColRowCell: NON-empty row " << i << ' '
7588 << "repeated " << repeated << " times" << endl;
7589
7590 xmlWriter.addAttribute( "table:number-rows-repeated", repeated );
7591 }
7592
7593 saveOasisCells( xmlWriter, mainStyles, i, maxCols, valStyle );
7594
7595 // copy the index for the next row to process
7596 i = j - 1; /*it's already incremented in the for loop*/
7597 }
7598 xmlWriter.endElement();
7599 }
7600}
7601
7602void Sheet::saveOasisCells( KoXmlWriter& xmlWriter, KoGenStyles &mainStyles, int row, int maxCols, GenValidationStyles &valStyle )
7603{
7604 int i = 1;
7605 Cell* cell = cellAt( i, row );
7606 Cell* nextCell = getNextCellRight( i, row );
7607 // while
7608 // the current cell is not a default one
7609 // or
7610 // we have a further cell in this row
7611 while ( !cell->isDefault() || nextCell )
7612 {
7613 kdDebug() << "Sheet::saveOasisCells:"
7614 << " i: " << i
7615 << " column: " << (cell->isDefault() ? 0 : cell->column()) << endl;
7616 int repeated = 1;
7617 cell->saveOasis( xmlWriter, mainStyles, row, i, repeated, valStyle );
7618 i += repeated;
7619 // stop if we reached the end column
7620 if ( i > maxCols )
7621 break;
7622 cell = cellAt( i, row );
7623 nextCell = getNextCellRight( i, row );
7624 }
7625}
7626
7627bool Sheet::loadXML( const TQDomElement& sheet )
7628{
7629 bool ok = false;
7630 if ( !doc()->loadingInfo() || !doc()->loadingInfo()->loadTemplate() )
7631 {
7632 d->name = sheet.attribute( "name" );
7633 if ( d->name.isEmpty() )
7634 {
7635 doc()->setErrorMessage( i18n("Invalid document. Sheet name is empty.") );
7636 return false;
7637 }
7638 }
7639
7640 bool detectDirection = true;
7641 d->layoutDirection = LeftToRight;
7642 TQString layoutDir = sheet.attribute( "layoutDirection" );
7643 if( !layoutDir.isEmpty() )
7644 {
7645 if( layoutDir == "rtl" )
7646 {
7647 detectDirection = false;
7648 d->layoutDirection = RightToLeft;
7649 }
7650 else if( layoutDir == "ltr" )
7651 {
7652 detectDirection = false;
7653 d->layoutDirection = LeftToRight;
7654 }
7655 else
7656 kdDebug()<<" Direction not implemented : "<<layoutDir<<endl;
7657 }
7658 if( detectDirection )
7659 checkContentDirection( d->name );
7660
7661 /* older versions of KSpread allowed all sorts of characters that
7662 the parser won't actually understand. Replace these with '_'
7663 Also, the initial character cannot be a space.
7664 */
7665 if (d->name[0] == ' ')
7666 {
7667 d->name.remove(0,1);
7668 }
7669 for (unsigned int i=0; i < d->name.length(); i++)
7670 {
7671 if ( !(d->name[i].isLetterOrNumber() ||
7672 d->name[i] == ' ' || d->name[i] == '.' ||
7673 d->name[i] == '_'))
7674 {
7675 d->name[i] = '_';
7676 }
7677 }
7678
7679 /* make sure there are no name collisions with the altered name */
7680 TQString testName;
7681 TQString baseName;
7682 int nameSuffix = 0;
7683
7684 testName = d->name;
7685 baseName = d->name;
7686
7687 /* so we don't panic over finding ourself in the follwing test*/
7688 d->name = "";
7689 while (workbook()->findSheet(testName) != NULL)
7690 {
7691 nameSuffix++;
7692 testName = baseName + '_' + TQString::number(nameSuffix);
7693 }
7694 d->name = testName;
7695
7696 kdDebug(36001)<<"Sheet::loadXML: table name="<<d->name<<endl;
7697 setName(d->name.utf8());
7698 (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
7699
7700 if( sheet.hasAttribute( "grid" ) )
7701 {
7702 d->showGrid = (int)sheet.attribute("grid").toInt( &ok );
7703 // we just ignore 'ok' - if it didn't work, go on
7704 }
7705 if( sheet.hasAttribute( "printGrid" ) )
7706 {
7707 d->print->setPrintGrid( (bool)sheet.attribute("printGrid").toInt( &ok ) );
7708 // we just ignore 'ok' - if it didn't work, go on
7709 }
7710 if( sheet.hasAttribute( "printCommentIndicator" ) )
7711 {
7712 d->print->setPrintCommentIndicator( (bool)sheet.attribute("printCommentIndicator").toInt( &ok ) );
7713 // we just ignore 'ok' - if it didn't work, go on
7714 }
7715 if( sheet.hasAttribute( "printFormulaIndicator" ) )
7716 {
7717 d->print->setPrintFormulaIndicator( (bool)sheet.attribute("printFormulaIndicator").toInt( &ok ) );
7718 // we just ignore 'ok' - if it didn't work, go on
7719 }
7720 if( sheet.hasAttribute( "hide" ) )
7721 {
7722 d->hide = (bool)sheet.attribute("hide").toInt( &ok );
7723 // we just ignore 'ok' - if it didn't work, go on
7724 }
7725 if( sheet.hasAttribute( "showFormula" ) )
7726 {
7727 d->showFormula = (bool)sheet.attribute("showFormula").toInt( &ok );
7728 // we just ignore 'ok' - if it didn't work, go on
7729 }
7730 //Compatibility with KSpread 1.1.x
7731 if( sheet.hasAttribute( "formular" ) )
7732 {
7733 d->showFormula = (bool)sheet.attribute("formular").toInt( &ok );
7734 // we just ignore 'ok' - if it didn't work, go on
7735 }
7736 if( sheet.hasAttribute( "showFormulaIndicator" ) )
7737 {
7738 d->showFormulaIndicator = (bool)sheet.attribute("showFormulaIndicator").toInt( &ok );
7739 // we just ignore 'ok' - if it didn't work, go on
7740 }
7741 if( sheet.hasAttribute( "showCommentIndicator" ) )
7742 {
7743 d->showCommentIndicator = (bool)sheet.attribute("showCommentIndicator").toInt( &ok );
7744 // we just ignore 'ok' - if it didn't work, go on
7745 }
7746 if( sheet.hasAttribute( "borders" ) )
7747 {
7748 d->showPageBorders = (bool)sheet.attribute("borders").toInt( &ok );
7749 // we just ignore 'ok' - if it didn't work, go on
7750 }
7751 if( sheet.hasAttribute( "lcmode" ) )
7752 {
7753 d->lcMode = (bool)sheet.attribute("lcmode").toInt( &ok );
7754 // we just ignore 'ok' - if it didn't work, go on
7755 }
7756 if ( sheet.hasAttribute( "autoCalc" ) )
7757 {
7758 d->autoCalc = ( bool )sheet.attribute( "autoCalc" ).toInt( &ok );
7759 // we just ignore 'ok' - if it didn't work, go on
7760 }
7761 if( sheet.hasAttribute( "columnnumber" ) )
7762 {
7763 d->showColumnNumber = (bool)sheet.attribute("columnnumber").toInt( &ok );
7764 // we just ignore 'ok' - if it didn't work, go on
7765 }
7766 if( sheet.hasAttribute( "hidezero" ) )
7767 {
7768 d->hideZero = (bool)sheet.attribute("hidezero").toInt( &ok );
7769 // we just ignore 'ok' - if it didn't work, go on
7770 }
7771 if( sheet.hasAttribute( "firstletterupper" ) )
7772 {
7773 d->firstLetterUpper = (bool)sheet.attribute("firstletterupper").toInt( &ok );
7774 // we just ignore 'ok' - if it didn't work, go on
7775 }
7776
7777 // Load the paper layout
7778 TQDomElement paper = sheet.namedItem( "paper" ).toElement();
7779 if ( !paper.isNull() )
7780 {
7781 TQString format = paper.attribute( "format" );
7782 TQString orientation = paper.attribute( "orientation" );
7783
7784 // <borders>
7785 TQDomElement borders = paper.namedItem( "borders" ).toElement();
7786 if ( !borders.isNull() )
7787 {
7788 float left = borders.attribute( "left" ).toFloat();
7789 float right = borders.attribute( "right" ).toFloat();
7790 float top = borders.attribute( "top" ).toFloat();
7791 float bottom = borders.attribute( "bottom" ).toFloat();
7792 d->print->setPaperLayout( left, top, right, bottom, format, orientation );
7793 }
7794 TQString hleft, hright, hcenter;
7795 TQString fleft, fright, fcenter;
7796 // <head>
7797 TQDomElement head = paper.namedItem( "head" ).toElement();
7798 if ( !head.isNull() )
7799 {
7800 TQDomElement left = head.namedItem( "left" ).toElement();
7801 if ( !left.isNull() )
7802 hleft = left.text();
7803 TQDomElement center = head.namedItem( "center" ).toElement();
7804 if ( !center.isNull() )
7805 hcenter = center.text();
7806 TQDomElement right = head.namedItem( "right" ).toElement();
7807 if ( !right.isNull() )
7808 hright = right.text();
7809 }
7810 // <foot>
7811 TQDomElement foot = paper.namedItem( "foot" ).toElement();
7812 if ( !foot.isNull() )
7813 {
7814 TQDomElement left = foot.namedItem( "left" ).toElement();
7815 if ( !left.isNull() )
7816 fleft = left.text();
7817 TQDomElement center = foot.namedItem( "center" ).toElement();
7818 if ( !center.isNull() )
7819 fcenter = center.text();
7820 TQDomElement right = foot.namedItem( "right" ).toElement();
7821 if ( !right.isNull() )
7822 fright = right.text();
7823 }
7824 d->print->setHeadFootLine( hleft, hcenter, hright, fleft, fcenter, fright);
7825 }
7826
7827 // load print range
7828 TQDomElement printrange = sheet.namedItem( "printrange-rect" ).toElement();
7829 if ( !printrange.isNull() )
7830 {
7831 int left = printrange.attribute( "left-rect" ).toInt();
7832 int right = printrange.attribute( "right-rect" ).toInt();
7833 int bottom = printrange.attribute( "bottom-rect" ).toInt();
7834 int top = printrange.attribute( "top-rect" ).toInt();
7835 if ( left == 0 ) //whole row(s) selected
7836 {
7837 left = 1;
7838 right = KS_colMax;
7839 }
7840 if ( top == 0 ) //whole column(s) selected
7841 {
7842 top = 1;
7843 bottom = KS_rowMax;
7844 }
7845 d->print->setPrintRange( TQRect( TQPoint( left, top ), TQPoint( right, bottom ) ) );
7846 }
7847
7848 // load print zoom
7849 if( sheet.hasAttribute( "printZoom" ) )
7850 {
7851 double zoom = sheet.attribute( "printZoom" ).toDouble( &ok );
7852 if ( ok )
7853 {
7854 d->print->setZoom( zoom );
7855 }
7856 }
7857
7858 // load page limits
7859 if( sheet.hasAttribute( "printPageLimitX" ) )
7860 {
7861 int pageLimit = sheet.attribute( "printPageLimitX" ).toInt( &ok );
7862 if ( ok )
7863 {
7864 d->print->setPageLimitX( pageLimit );
7865 }
7866 }
7867
7868 // load page limits
7869 if( sheet.hasAttribute( "printPageLimitY" ) )
7870 {
7871 int pageLimit = sheet.attribute( "printPageLimitY" ).toInt( &ok );
7872 if ( ok )
7873 {
7874 d->print->setPageLimitY( pageLimit );
7875 }
7876 }
7877
7878 // Load the cells
7879 TQDomNode n = sheet.firstChild();
7880 while( !n.isNull() )
7881 {
7882 TQDomElement e = n.toElement();
7883 if ( !e.isNull() )
7884 {
7885 TQString tagName=e.tagName();
7886 if ( tagName == "cell" )
7887 {
7888 Cell *cell = new Cell( this, 0, 0 );
7889 if ( cell->load( e, 0, 0 ) )
7890 insertCell( cell );
7891 else
7892 delete cell; // Allow error handling: just skip invalid cells
7893 }
7894 else if ( tagName == "row" )
7895 {
7896 RowFormat *rl = new RowFormat( this, 0 );
7897 if ( rl->load( e ) )
7898 insertRowFormat( rl );
7899 else
7900 delete rl;
7901 }
7902 else if ( tagName == "column" )
7903 {
7904 ColumnFormat *cl = new ColumnFormat( this, 0 );
7905 if ( cl->load( e ) )
7906 insertColumnFormat( cl );
7907 else
7908 delete cl;
7909 }
7910 else if ( tagName == "object" )
7911 {
7912 EmbeddedKOfficeObject *ch = new EmbeddedKOfficeObject( doc(), this );
7913 if ( ch->load( e ) )
7914 insertObject( ch );
7915 else
7916 {
7917 ch->embeddedObject()->setDeleted(true);
7918 delete ch;
7919 }
7920 }
7921 else if ( tagName == "chart" )
7922 {
7923 EmbeddedChart *ch = new EmbeddedChart( doc(), this );
7924 if ( ch->load( e ) )
7925 insertObject( ch );
7926 else
7927 {
7928 ch->embeddedObject()->setDeleted(true);
7929 delete ch;
7930 }
7931 }
7932 }
7933
7934 n = n.nextSibling();
7935 }
7936
7937
7938 // load print repeat columns
7939 TQDomElement printrepeatcolumns = sheet.namedItem( "printrepeatcolumns" ).toElement();
7940 if ( !printrepeatcolumns.isNull() )
7941 {
7942 int left = printrepeatcolumns.attribute( "left" ).toInt();
7943 int right = printrepeatcolumns.attribute( "right" ).toInt();
7944 d->print->setPrintRepeatColumns( qMakePair( left, right ) );
7945 }
7946
7947 // load print repeat rows
7948 TQDomElement printrepeatrows = sheet.namedItem( "printrepeatrows" ).toElement();
7949 if ( !printrepeatrows.isNull() )
7950 {
7951 int top = printrepeatrows.attribute( "top" ).toInt();
7952 int bottom = printrepeatrows.attribute( "bottom" ).toInt();
7953 d->print->setPrintRepeatRows( qMakePair( top, bottom ) );
7954 }
7955
7956 if( !sheet.hasAttribute( "borders1.2" ) )
7957 {
7958 convertObscuringBorders();
7959 }
7960
7961 if ( sheet.hasAttribute( "protected" ) )
7962 {
7963 TQString passwd = sheet.attribute( "protected" );
7964
7965 if ( passwd.length() > 0 )
7966 {
7967 TQCString str( passwd.latin1() );
7968 d->password = KCodecs::base64Decode( str );
7969 }
7970 else
7971 d->password = TQCString( "" );
7972 }
7973
7974 return true;
7975}
7976
7977
7978bool Sheet::loadChildren( KoStore* _store )
7979{
7980 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
7981 for( ; it.current(); ++it )
7982 {
7983 if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
7984 {
7985 kdDebug() << "KSpreadSheet::loadChildren" << endl;
7986 if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->loadDocument( _store ) )
7987 return false;
7988 }
7989 }
7990
7991 return true;
7992}
7993
7994
7995void Sheet::setShowPageBorders( bool b )
7996{
7997 if ( b == d->showPageBorders )
7998 return;
7999
8000 d->showPageBorders = b;
8001 emit sig_updateView( this );
8002}
8003
8004void Sheet::addCellBinding( CellBinding *_bind )
8005{
8006 d->cellBindings.append( _bind );
8007
8008 doc()->setModified( true );
8009}
8010
8011void Sheet::removeCellBinding( CellBinding *_bind )
8012{
8013 d->cellBindings.removeRef( _bind );
8014
8015 doc()->setModified( true );
8016}
8017
8018Sheet* Sheet::findSheet( const TQString & _name )
8019{
8020 if ( !workbook() )
8021 return 0L;
8022
8023 return workbook()->findSheet( _name );
8024}
8025
8026// ###### Torben: Use this one instead of d->cells.insert()
8027void Sheet::insertCell( Cell *_cell )
8028{
8029
8030 d->cells.insert( _cell, _cell->column(), _cell->row() );
8031
8032 // Adjust the scrollbar range, if the max. dimension has changed.
8033 if ( d->scrollBarUpdates )
8034 {
8035 checkRangeHBorder ( _cell->column() );
8036 checkRangeVBorder ( _cell->row() );
8037 }
8038}
8039
8040void Sheet::insertColumnFormat( ColumnFormat *l )
8041{
8042 d->columns.insertElement( l, l->column() );
8043}
8044
8045void Sheet::insertRowFormat( RowFormat *l )
8046{
8047 d->rows.insertElement( l, l->row() );
8048}
8049
8050void Sheet::update()
8051{
8052 Cell* c = d->cells.firstCell();
8053 for( ;c; c = c->nextCell() )
8054 {
8055 updateCell(c, c->column(), c->row());
8056 }
8057}
8058
8059void Sheet::updateCellArea(const Region& cellArea)
8060{
8061 if ( doc()->isLoading() || doc()->delayCalculation() || (!getAutoCalc()))
8062 return;
8063
8064 setRegionPaintDirty( cellArea );
8065}
8066
8067void Sheet::updateCell( Cell */*cell*/, int _column, int _row )
8068{
8069 TQRect cellArea(TQPoint(_column, _row), TQPoint(_column, _row));
8070
8071 updateCellArea(cellArea);
8072}
8073
8074void Sheet::emit_updateRow( RowFormat *_format, int _row, bool repaint )
8075{
8076 if ( doc()->isLoading() )
8077 return;
8078
8079 Cell* c = d->cells.firstCell();
8080 for( ;c; c = c->nextCell() )
8081 if ( c->row() == _row )
8082 c->setLayoutDirtyFlag( true );
8083
8084 if ( repaint )
8085 {
8086 //All the cells in this row, or below this row will need to be repainted
8087 //So add that region of the sheet to the paint dirty list.
8088 setRegionPaintDirty( TQRect( 0 , _row , KS_colMax , KS_rowMax) );
8089
8090 emit sig_updateVBorder( this );
8091 emit sig_updateView( this );
8092 }
8093 emit sig_maxRow(maxRow());
8094 _format->clearDisplayDirtyFlag();
8095}
8096
8097void Sheet::emit_updateColumn( ColumnFormat *_format, int _column )
8098{
8099 if ( doc()->isLoading() )
8100 return;
8101
8102 Cell* c = d->cells.firstCell();
8103 for( ;c; c = c->nextCell() )
8104 if ( c->column() == _column )
8105 c->setLayoutDirtyFlag( true );
8106
8107 //All the cells in this column or to the right of it will need to be repainted if the column
8108 //has been resized or hidden, so add that region of the sheet to the paint dirty list.
8109 setRegionPaintDirty( TQRect( _column , 0 , KS_colMax , KS_rowMax) );
8110
8111 emit sig_updateHBorder( this );
8112 emit sig_updateView( this );
8113 emit sig_maxColumn( maxColumn() );
8114
8115
8116
8117 _format->clearDisplayDirtyFlag();
8118}
8119
8120bool Sheet::insertChart( const KoRect& _rect, KoDocumentEntry& _e, const TQRect& _data )
8121{
8122 kdDebug(36001) << "Creating document" << endl;
8123 KoDocument* dd = _e.createDoc();
8124 kdDebug(36001) << "Created" << endl;
8125 if ( !dd )
8126 // Error message is already displayed, so just return
8127 return false;
8128
8129 kdDebug(36001) << "NOW FETCHING INTERFACE" << endl;
8130
8131 if ( !dd->initDoc(KoDocument::InitDocEmbedded) )
8132 return false;
8133
8134 EmbeddedChart * ch = new EmbeddedChart( doc(), this, dd, _rect );
8135 ch->setDataArea( _data );
8136 ch->update();
8137 ch->chart()->setCanChangeValue( false );
8138
8139 KoChart::WizardExtension * wiz = ch->chart()->wizardExtension();
8140
8141 Range dataRange;
8142 dataRange.setRange( _data );
8143 dataRange.setSheet( this );
8144
8145 TQString rangeString=dataRange.toString();
8146
8147 if ( wiz )
8148 wiz->show( rangeString );
8149
8150 insertObject( ch );
8151
8152 return true;
8153}
8154
8155bool Sheet::insertChild( const KoRect& _rect, KoDocumentEntry& _e )
8156{
8157 KoDocument* d = _e.createDoc( doc() );
8158 if ( !d )
8159 {
8160 kdDebug() << "Error inserting child!" << endl;
8161 return false;
8162 }
8163 if ( !d->initDoc(KoDocument::InitDocEmbedded) )
8164 return false;
8165
8166 EmbeddedKOfficeObject* ch = new EmbeddedKOfficeObject( doc(), this, d, _rect );
8167 insertObject( ch );
8168 return true;
8169}
8170
8171bool Sheet::insertPicture( const KoPoint& point , const KURL& url )
8172{
8173 KoPicture picture = doc()->pictureCollection()->downloadPicture( url , 0 );
8174
8175 return insertPicture(point,picture);
8176}
8177
8178bool Sheet::insertPicture( const KoPoint& point , KoPicture& picture )
8179{
8180
8181 if (picture.isNull())
8182 return false;
8183
8184 KoPictureKey key = picture.getKey();
8185
8186 KoRect destinationRect;
8187 destinationRect.setLeft( point.x() );
8188 destinationRect.setTop( point.y() );
8189
8190 //Generate correct pixel size - this is a bit tricky.
8191 //This ensures that when we load the image it appears
8192 //the same size on screen on a 100%-zoom KSpread spreadsheet as it would in an
8193 //image viewer or another spreadsheet program such as OpenOffice.
8194 //
8195 //KoUnit assumes 72DPI, whereas the user's display resolution will probably be
8196 //different (eg. 96*96). So, we convert the actual size in pixels into inches
8197 //using the screen display resolution and then use KoUnit to convert back into
8198 //the appropriate pixel size KSpread.
8199
8200 KoSize destinationSize;
8201
8202 double inchWidth = (double)picture.getOriginalSize().width() / KoGlobal::dpiX();
8203 double inchHeight = (double)picture.getOriginalSize().height() / KoGlobal::dpiY();
8204
8205 destinationSize.setWidth( KoUnit::fromUserValue(inchWidth,KoUnit::U_INCH) );
8206 destinationSize.setHeight( KoUnit::fromUserValue(inchHeight,KoUnit::U_INCH) );
8207
8208 destinationRect.setSize( destinationSize);
8209
8210 EmbeddedPictureObject* object = new EmbeddedPictureObject( this, destinationRect, doc()->pictureCollection(),key);
8211 // ch->setPicture(key);
8212
8213 insertObject( object );
8214 return true;
8215}
8216
8217bool Sheet::insertPicture( const KoPoint& point, const TQPixmap& pixmap )
8218{
8219 TQByteArray data;
8220 TQBuffer buffer(data);
8221
8222 buffer.open( IO_ReadWrite );
8223 pixmap.save( &buffer , "PNG" );
8224
8225 //Reset the buffer so that KoPicture reads the whole file from the beginning
8226 //(at the moment the read/write position is at the end)
8227 buffer.reset();
8228
8229 KoPicture picture;
8230 picture.load( &buffer , "PNG" );
8231
8232 doc()->pictureCollection()->insertPicture(picture);
8233
8234 return insertPicture( point , picture );
8235}
8236
8237void Sheet::insertObject( EmbeddedObject *_obj )
8238{
8239 doc()->insertObject( _obj );
8240 emit sig_updateView( _obj );
8241}
8242
8243void Sheet::changeChildGeometry( EmbeddedKOfficeObject *_child, const KoRect& _rect )
8244{
8245 _child->setGeometry( _rect );
8246
8247 emit sig_updateChildGeometry( _child );
8248}
8249
8250bool Sheet::saveChildren( KoStore* _store, const TQString &_path )
8251{
8252 int i = 0;
8253
8254 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
8255 for( ; it.current(); ++it )
8256 {
8257 if ( it.current()->sheet() == this && ( it.current()->getType() == OBJECT_KOFFICE_PART || it.current()->getType() == OBJECT_CHART ) )
8258 {
8259 TQString path = TQString( "%1/%2" ).arg( _path ).arg( i++ );
8260 if ( !dynamic_cast<EmbeddedKOfficeObject*>( it.current() )->embeddedObject()->document()->saveToStore( _store, path ) )
8261 return false;
8262 }
8263 }
8264 return true;
8265}
8266
8267bool Sheet::saveOasisObjects( KoStore */*store*/, KoXmlWriter &xmlWriter, KoGenStyles& mainStyles, int & indexObj, int &partIndexObj )
8268{
8269 //int i = 0;
8270 if ( doc()->embeddedObjects().isEmpty() )
8271 return true;
8272
8273 bool objectFound = false; // object on this sheet?
8274 EmbeddedObject::KSpreadOasisSaveContext sc( xmlWriter, mainStyles, indexObj, partIndexObj );
8275 TQPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
8276 for( ; it.current(); ++it )
8277 {
8278 if ( it.current()->sheet() == this && ( doc()->savingWholeDocument() || it.current()->isSelected() ) )
8279 {
8280 if ( !objectFound )
8281 {
8282 xmlWriter.startElement( "table:shapes" );
8283 objectFound = true;
8284 }
8285 if ( !it.current()->saveOasisObject(sc) )
8286 {
8287 xmlWriter.endElement();
8288 return false;
8289 }
8290 ++indexObj;
8291 }
8292 }
8293 if ( objectFound )
8294 {
8295 xmlWriter.endElement();
8296 }
8297 return true;
8298}
8299
8300Sheet::~Sheet()
8301{
8302 //Disable automatic recalculation of dependancies on this sheet to prevent crashes
8303 //in certain situations:
8304 //
8305 //For example, suppose a cell in SheetB depends upon a cell in SheetA. If the cell in SheetB is emptied
8306 //after SheetA has already been deleted, the program would try to remove dependancies from the cell in SheetA
8307 //causing a crash.
8308 setAutoCalc(false);
8309
8310 s_mapSheets->remove( d->id );
8311
8312 //when you remove all sheet (close file)
8313 //you must reinit s_id otherwise there is not
8314 //the good name between map and sheet
8315 if( s_mapSheets->count()==0)
8316 s_id=0L;
8317
8318 Cell* c = d->cells.firstCell();
8319 for( ; c; c = c->nextCell() )
8320 c->sheetDies();
8321
8322 d->cells.clear(); // cells destructor needs sheet to still exist
8323
8324 d->painter->end();
8325 delete d->painter;
8326 delete d->widget;
8327
8328 delete d->defaultFormat;
8329 delete d->defaultCell;
8330 delete d->defaultRowFormat;
8331 delete d->defaultColumnFormat;
8332 delete d->print;
8333 delete d->dcop;
8334
8335 delete d->dependencies;
8336
8337 delete d;
8338
8339 //this is for debugging a crash
8340 d=0;
8341}
8342
8343void Sheet::checkRangeHBorder ( int _column )
8344{
8345 if ( d->scrollBarUpdates && _column > d->maxColumn )
8346 {
8347 d->maxColumn = _column;
8348 emit sig_maxColumn( _column );
8349 }
8350}
8351
8352void Sheet::checkRangeVBorder ( int _row )
8353{
8354 if ( d->scrollBarUpdates && _row > d->maxRow )
8355 {
8356 d->maxRow = _row;
8357 emit sig_maxRow( _row );
8358 }
8359}
8360
8361
8362void Sheet::enableScrollBarUpdates( bool _enable )
8363{
8364 d->scrollBarUpdates = _enable;
8365}
8366
8367DCOPObject* Sheet::dcopObject()
8368{
8369 if ( !d->dcop )
8370 d->dcop = new SheetIface( this );
8371
8372 return d->dcop;
8373}
8374
8375void Sheet::hideSheet(bool _hide)
8376{
8377 setHidden(_hide);
8378 if(_hide)
8379 emit sig_SheetHidden(this);
8380 else
8381 emit sig_SheetShown(this);
8382}
8383
8384void Sheet::removeSheet()
8385{
8386 emit sig_SheetRemoved(this);
8387}
8388
8389bool Sheet::setSheetName( const TQString& name, bool init, bool /*makeUndo*/ )
8390{
8391 if ( workbook()->findSheet( name ) )
8392 return false;
8393
8394 if ( isProtected() )
8395 return false;
8396
8397 if ( d->name == name )
8398 return true;
8399
8400 TQString old_name = d->name;
8401 d->name = name;
8402
8403 if ( init )
8404 return true;
8405
8406 TQPtrListIterator<Sheet> it( workbook()->sheetList() );
8407 for ( ; it.current(); ++it )
8408 it.current()->changeCellTabName( old_name, name );
8409
8410 doc()->changeAreaSheetName( old_name, name );
8411 emit sig_nameChanged( this, old_name );
8412
8413 setName(name.utf8());
8414 (dynamic_cast<SheetIface*>(dcopObject()))->sheetNameHasChanged();
8415
8416 return true;
8417}
8418
8419
8420void Sheet::updateLocale()
8421{
8422 doc()->emitBeginOperation(true);
8423 setRegionPaintDirty(TQRect(TQPoint(1,1), TQPoint(KS_colMax, KS_rowMax)));
8424
8425 Cell* c = d->cells.firstCell();
8426 for( ;c; c = c->nextCell() )
8427 {
8428 TQString _text = c->text();
8429 c->setCellText( _text );
8430 }
8431 emit sig_updateView( this );
8432 // doc()->emitEndOperation();
8433}
8434
8435Cell* Sheet::getFirstCellColumn(int col) const
8436{ return d->cells.getFirstCellColumn(col); }
8437
8438Cell* Sheet::getLastCellColumn(int col) const
8439{ return d->cells.getLastCellColumn(col); }
8440
8441Cell* Sheet::getFirstCellRow(int row) const
8442{ return d->cells.getFirstCellRow(row); }
8443
8444Cell* Sheet::getLastCellRow(int row) const
8445{ return d->cells.getLastCellRow(row); }
8446
8447Cell* Sheet::getNextCellUp(int col, int row) const
8448{ return d->cells.getNextCellUp(col, row); }
8449
8450Cell* Sheet::getNextCellDown(int col, int row) const
8451{ return d->cells.getNextCellDown(col, row); }
8452
8453Cell* Sheet::getNextCellLeft(int col, int row) const
8454{ return d->cells.getNextCellLeft(col, row); }
8455
8456Cell* Sheet::getNextCellRight(int col, int row) const
8457{ return d->cells.getNextCellRight(col, row); }
8458
8459void Sheet::convertObscuringBorders()
8460{
8461 /* a word of explanation here:
8462 beginning with KSpread 1.2 (actually, cvs of Mar 28, 2002), border information
8463 is stored differently. Previously, for a cell obscuring a region, the entire
8464 region's border's data would be stored in the obscuring cell. This caused
8465 some data loss in certain situations. After that date, each cell stores
8466 its own border data, and prints it even if it is an obscured cell (as long
8467 as that border isn't across an obscuring border).
8468 Anyway, this function is used when loading a file that was stored with the
8469 old way of borders. All new files have the sheet attribute "borders1.2" so
8470 if that isn't in the file, all the border data will be converted here.
8471 It's a bit of a hack but I can't think of a better way and it's not *that*
8472 bad of a hack.:-)
8473 */
8474 Cell* c = d->cells.firstCell();
8475 TQPen topPen, bottomPen, leftPen, rightPen;
8476 for( ;c; c = c->nextCell() )
8477 {
8478 if (c->extraXCells() > 0 || c->extraYCells() > 0)
8479 {
8480 topPen = c->topBorderPen(c->column(), c->row());
8481 leftPen = c->leftBorderPen(c->column(), c->row());
8482 rightPen = c->rightBorderPen(c->column(), c->row());
8483 bottomPen = c->bottomBorderPen(c->column(), c->row());
8484
8485 c->format()->setTopBorderStyle(TQt::NoPen);
8486 c->format()->setLeftBorderStyle(TQt::NoPen);
8487 c->format()->setRightBorderStyle(TQt::NoPen);
8488 c->format()->setBottomBorderStyle(TQt::NoPen);
8489
8490 for (int x = c->column(); x < c->column() + c->extraXCells(); x++)
8491 {
8492 nonDefaultCell( x, c->row() )->setTopBorderPen(topPen);
8493 nonDefaultCell( x, c->row() + c->extraYCells() )->
8494 setBottomBorderPen(bottomPen);
8495 }
8496 for (int y = c->row(); y < c->row() + c->extraYCells(); y++)
8497 {
8498 nonDefaultCell( c->column(), y )->setLeftBorderPen(leftPen);
8499 nonDefaultCell( c->column() + c->extraXCells(), y )->
8500 setRightBorderPen(rightPen);
8501 }
8502 }
8503 }
8504}
8505
8506/**********************
8507 * Printout Functions *
8508 **********************/
8509
8510// TODO Stefan: these belong to View, even better Canvas
8511void Sheet::setRegionPaintDirty( Region const & region )
8512{
8513 DilationManipulator manipulator;
8514 manipulator.setSheet(this);
8515 manipulator.add(region);
8516 manipulator.execute();
8517 // don't put it in the undo list! ;-)
8518 d->paintDirtyList.add(manipulator);
8519 //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
8520}
8521
8522void Sheet::setRegionPaintDirty( TQRect const & range )
8523{
8524 DilationManipulator manipulator;
8525 manipulator.setSheet(this);
8526 manipulator.add(range);
8527 manipulator.execute();
8528 // don't put it in the undo list! ;-)
8529 d->paintDirtyList.add(manipulator);
8530 //kdDebug() << "setRegionPaintDirty "<< static_cast<Region*>(&manipulator)->name(this) << endl;
8531}
8532
8533void Sheet::clearPaintDirtyData()
8534{
8535 d->paintDirtyList.clear();
8536}
8537
8538bool Sheet::cellIsPaintDirty( TQPoint const & cell ) const
8539{
8540 return d->paintDirtyList.contains(cell);
8541}
8542
8543#ifndef NDEBUG
8544void Sheet::printDebug()
8545{
8546 int iMaxColumn = maxColumn();
8547 int iMaxRow = maxRow();
8548
8549 kdDebug(36001) << "Cell | Content | DataT | Text" << endl;
8550 Cell *cell;
8551 for ( int currentrow = 1 ; currentrow < iMaxRow ; ++currentrow )
8552 {
8553 for ( int currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
8554 {
8555 cell = cellAt( currentcolumn, currentrow );
8556 if ( !cell->isDefault() && !cell->isEmpty() )
8557 {
8558 TQString cellDescr = Cell::name( currentcolumn, currentrow );
8559 cellDescr = cellDescr.rightJustify( 4,' ' );
8560 //TQString cellDescr = "Cell ";
8561 //cellDescr += TQString::number(currentrow).rightJustify(3,'0') + ',';
8562 //cellDescr += TQString::number(currentcolumn).rightJustify(3,'0') + ' ';
8563 cellDescr += " | ";
8564 cellDescr += cell->value().type();
8565 cellDescr += " | ";
8566 cellDescr += cell->text();
8567 if ( cell->isFormula() )
8568 cellDescr += TQString(" [result: %1]").arg( cell->value().asString() );
8569 kdDebug(36001) << cellDescr << endl;
8570 }
8571 }
8572 }
8573}
8574#endif
8575
8576} // namespace KSpread
8577
The canvas builds a part of the GUI of KSpread.
This is an abstract base class only.
virtual void cellChanged(Cell *_obj)
Call this function if one of the cells covered by this binding (.
For every cell in the spread sheet there is a Cell object.
TQString name() const
Returns the name of the cell.
TQString columnName() const
Returns the column name of the cell.
This class holds the data that makes up a spreadsheet.
Definition kspread_doc.h:98
@ STYLE_COLUMN_AUTO
auto column styles
@ STYLE_ROW_AUTO
auto row styles
A map is a simple container for all sheets.
Definition kspread_map.h:59
The Style class represents a cell style.
Abstract base class.
Provides a wrapper for cell value.
Operation
The current cell value treatment.
Mode
The pasted content.
@ Format
Format only.
The KSpread namespace.
Definition commands.h:39