/* This file is part of the KDE project Copyright 2006 Stefan Nikolaus Copyright 1999-2002,2004 Laurent Montel Copyright 2002-2005 Ariya Hidayat Copyright 1999-2001,2003 David Faure Copyright 2001-2003 Philipp Mueller Copyright 2002-2003 Norbert Andres Copyright 2000-2001 Werner Trobin Copyright 2002 Harri Porten Copyright 2002 John Dailey Copyright 1999-2000 Torben Weis Copyright 2000 Wilco Greven Copyright 1999 Boris Wedl Copyright 1999 Reginald Stadlbauer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KSPREAD_CANVAS #define KSPREAD_CANVAS #include #include #include #include #include #include #include "kspread_util.h" #define YBORDER_WIDTH 50 #define XBORDER_HEIGHT 20 class TQWidget; class TQTimer; class TQButton; class TQPainter; class TQLabel; class TQScrollBar; class KoRect; class KoPoint; namespace KSpread { class Cell; class EditWidget; class Canvas; class HBorder; class VBorder; class Sheet; class Doc; class Point; class Range; class Region; class View; class Selection; class CellEditor; class LocationEditWidget; class ComboboxLocationEditWidget; class EmbeddedObject; /** * The canvas builds a part of the GUI of KSpread. * It contains the borders, scrollbars, * editwidget and of course it displays the sheet. * Especially most of the user interface logic is implemented here. * That means that this class knows what to do when a key is pressed * or if the mouse button was clicked. */ class KSPREAD_EXPORT Canvas : public TQWidget { friend class HBorder; friend class VBorder; friend class View; Q_OBJECT TQ_OBJECT public: /** * The current action associated with the mouse. * Default is 'NoAction'. */ enum MouseActions { /** No mouse action (default) */ NoAction, /** Marking action */ Mark, /** Merging cell */ ResizeCell, /** Autofilling */ AutoFill, /** Resizing the selection */ ResizeSelection }; enum EditorType { CellEditor, EditWidget }; Canvas (View *_view); ~Canvas( ); View* view() const; Doc* doc() const; KSpread::EditWidget* editWidget() const; KSpread::CellEditor* editor() const; /** * @return the usual selection of cells */ Selection* selectionInfo() const; /** * @return a selection of cells used in formulas */ Selection* choice() const; /** * @deprecated use selectionInfo() * Selections are no longer contiguous in general. * @see Selection::lastRange() * @see Selection::activeElement() */ TQRect selection() const; /** * convenience function. * @return selection's marker * @see Selection::marker() */ TQPoint marker() const; /** * convenience function. * @return selection's marker's column * @see Selection::marker() */ int markerColumn() const; /** * convenience function. * @return selection's marker's row * @see Selection::marker() */ int markerRow() const; /** * @return the pen, the default grid is painted with (light gray) */ const TQPen& defaultGridPen() const; /** * convenience function * @see View::zoom() */ double zoom() const; /** * @return the width of the columns before the current screen */ double xOffset() const; /** * @return the height of the rows before the current screen */ double yOffset() const; /** * Sets the width of the columns before the current screen */ void setXOffset( double _xOffset ); /** * Sets the height of the rows before the current screen */ void setYOffset( double _yOffset ); /** * @return a rect indicating which cell range is currently visible onscreen */ TQRect visibleCells() const; /** * @return a pointer to the active sheet */ Sheet* activeSheet() const; /** * convenience function * @see Map::findSheet() */ Sheet* findSheet( const TQString& _name ) const; /** * Validates the selected cell. */ void validateSelection(); /** * Paint all visible cells that have a paint dirty flag set */ void paintUpdates(); /** * Makes sure a cell is visible onscreen by scrolling up/down and left/right * * @param location the cell coordinates to scroll to */ void scrollToCell(TQPoint location) const; /** * Chooses the correct EditorType by looking at * the current cells value. By default CellEditor is chosen. */ void createEditor( bool captureArrowKeys=false ); bool createEditor( EditorType type, bool addFocus = true, bool captureArrowKeys=false ); /** * Deletes the current cell editor. * * @see #createEditor * @see #editor * @param saveChanges if true, the edited text is stored in the cell. * if false, the changes are discarded. * @param array if true, array formula was entered */ void deleteEditor(bool saveChanges, bool array = false); /** * Called from @ref EditWidget and CellEditor * if they loose the focus because the user started a "choose selection". * This is done because the editor wants to get its focus back afterwards. * But somehow Canvas must know whether the EditWidget or the CellEditor * lost the focus when the user clicked on the canvas. */ void setLastEditorWithFocus( EditorType type ); /** * Switches to choose mode and sets the initial selection to the * position returned by marker(). * Clears the choice. */ void startChoose(); /** * Switches to choose mode and sets the initial @p selection. */ void startChoose( const TQRect& selection ); /** * Switches to selection mode. * Clear the choice. */ void endChoose(); /** * Switches the choose mode on and off. * Does not clear the choice. */ void setChooseMode(bool state); /** * @return @c true if choose mode is enabled, @c false otherwise */ bool chooseMode() const; void equalizeRow(); void equalizeColumn(); /** * Updates the position widget. */ void updatePosWidget(); /** * Close the cell editor and saves changes. * @see deleteEditor() */ void closeEditor(); // Created by the view since it's tqlayout is managed there, // but is in fact a sibling of the canvas, which needs to know about it. void setEditWidget( KSpread::EditWidget * ew ); virtual bool focusNextPrevChild( bool ); /** * Depending on the offset in "zoomed" screen pixels * for the horizontal direction, * the function returns the steps in unzoomed points * for the autoscroll acceleration */ double autoScrollAccelerationX( int offset ); /** * Depending on the offset in "zoomed" screen pixels * for the vertical direction, * the function returns the steps in unzoomed points * for the autoscroll acceleration */ double autoScrollAccelerationY( int offset ); //TODO: These embedded-object related methods need API documentation! EmbeddedObject* getObject( const TQPoint &pos, Sheet *_sheet ); void selectAllObjects(); void deselectAllObjects(); void selectObject( EmbeddedObject* ); void deselectObject( EmbeddedObject* ); void setMouseSelectedObject(bool b); bool isObjectSelected(); /** * @brief Move object by mouse * * @param pos The position of the mouse * @param keepXorYunchanged if true keep x or y position unchanged */ void moveObjectsByMouse( KoPoint &pos, bool keepXorYunchanged ); //---- stuff needed for resizing ---- /// resize the m_resizeObject void resizeObject( ModifyType _modType, const KoPoint & point, bool keepRatio ); /// create KPrResizeCmd void finishResizeObject( const TQString &name, bool tqlayout = true ); /** * @brief Display object above the other objects in editiong mode * * This is used to bring a single slected object to front, so it is easier * to modify. * * @param object which should be displayed above the other objects */ void raiseObject( EmbeddedObject *object ); /** * @brief Don't display an object above the others */ void lowerObject(); /** * @brief Get the list of objects in the order they should be displayed. * * This takes into acount the object set in raiseObject so that it is * the last one in the list returned (the one that is displayed above all * the others). * * @return List of objects */ void displayObjectList( TQPtrList &list ); KoRect objectRect( bool all ) const; void repaintObject( EmbeddedObject *obj ); /** * This is intended to copy the selected objects to the clipboard so that they can be pasted into other * applications. However, until at least KWord, KSpread, KPresenter, KChart and KFormula have consistant * support for copying and pasting of OASIS objects the selected objects will just be copied in the form * of raster graphics */ void copyOasisObjects(); //void insertOasisData(); public slots: void slotScrollVert( int _value ); void slotScrollHorz( int _value ); void slotMaxColumn( int _max_column ); void slotMaxRow( int _max_row ); signals: void objectSelectedChanged(); void objectSizeChanged(); protected: virtual void keyPressEvent ( TQKeyEvent* _ev ); virtual void paintEvent ( TQPaintEvent* _ev ); virtual void mousePressEvent( TQMouseEvent* _ev ); virtual void mouseReleaseEvent( TQMouseEvent* _ev ); virtual void mouseMoveEvent( TQMouseEvent* _ev ); virtual void mouseDoubleClickEvent( TQMouseEvent* ); virtual void wheelEvent( TQWheelEvent* ); virtual void focusInEvent( TQFocusEvent* ); virtual void focusOutEvent( TQFocusEvent* ); virtual void resizeEvent( TQResizeEvent * _ev ); virtual void dragMoveEvent(TQDragMoveEvent * _ev); virtual void dropEvent(TQDropEvent * _ev); virtual void dragLeaveEvent(TQDragLeaveEvent * _ev); /** * Checks to see if there is a size grip for a highlight range at a given position. * Note that both X and Y coordinates are UNZOOMED. To translate from a zoomed coordinate (eg. position of a mouse event) to * an unzoomed coordinate, use Doc::unzoomItX and Doc::unzoomItY. The document object * can be accessed via view()->doc() * @param x Unzoomed x coordinate to check * @param y Unzoomed y coordinate to check * @return @c true if there is a size grip at the specified position, @c false otherwise. */ bool highlightRangeSizeGripAt(double x, double y); private slots: /** * Scroll canvas when receiving this signal */ void slotAutoScroll(const TQPoint &scrollDist); void doAutoScroll(); void speakCell(TQWidget* w, const TQPoint& p, uint flags); private: virtual bool eventFilter( TQObject *o, TQEvent *e ); HBorder* hBorderWidget() const; VBorder* vBorderWidget() const; TQScrollBar* horzScrollBar() const; TQScrollBar* vertScrollBar() const; /** * Returns the area of the document currently visible in a painter's * window, calculated by taking the painter's window() property and * translating it by the current x and y offset of the Canvas (taking * the zoom level into account) */ TQRect painterWindowGeometry( const TQPainter& painter ) const; /** * Enables clipping and removes the areas on the canvas widget occupied by embedded objects from * the clip region. This ensures that subsequent drawing operations using the given painter * don't paint over the area occupied by embedded objects */ void clipoutChildren( TQPainter& painter ) const; /** * Returns the range of cells which appear in the specified area of the Canvas widget * For example, cellsInArea( TQRect(0,0,width(),height()) ) returns a range containing all visible cells * * @param area The area (in pixels) on the Canvas widget */ TQRect cellsInArea( const TQRect area ) const; /** * Paints the tqchildren */ void paintChildren( TQPainter& painter, TQWMatrix& matrix ); /** * @see #setLastEditorWithFocus */ EditorType lastEditorWithFocus() const; private: void moveObject( int x, int y, bool key ); void startTheDrag(); /* helpers for the paintUpdates function */ void paintNormalMarker(TQPainter& painter, const KoRect &viewRect); /** * Paint the highlighted ranges of cells. When the user is editing a formula in a text box, cells and ranges referenced * in the formula are highlighted on the canvas. * @param painter The painter on which to draw the highlighted ranges * @param viewRect The area currently visible on the canvas */ void paintHighlightedRanges(TQPainter& painter, const KoRect& viewRect); /** * Calculates the visible region on the canvas occupied by a range of cells on the currently active sheet. * This is used for drawing the thick border around the current selection or highlights around cell range * references. * The results do not take into account the current zoom factor of the sheet, * use Doc::zoomRect on @p visibleRect after calling this function to get a new rectangle taking * the zoom level into account. * @param sheetArea The range of cells on the current sheet * @param visibleRect This is set to the visible region occupied by the given range of cells * */ void sheetAreaToVisibleRect( const TQRect& sheetArea, KoRect& visibleRect ); /** * Calculates the physical region on the canvas widget occupied by a range of cells on * the currently active sheet. * Unlike @see sheetAreaToVisibleRect , scrolling the view does not affect sheetAreaToRect. * * @param sheetArea The range of cells on the current sheet * @param visibleRect This is set to the physical region occupied by the given range of cells */ void sheetAreaToRect( const TQRect& sheetArea, KoRect& rect ); /** * helper function in drawing the marker and choose marker. * @param marker the rectangle that represents the marker being drawn * (cell coordinates) * @param viewRect the visible area on the canvas * @param positions output parameter where the viewable left, top, right, and * bottom of the marker will be. They are stored in the array * in that order, and take into account cropping due to part * of the marker being off screen. This array should have * at least a size of 4 pre-allocated. * @param paintSides booleans indicating whether a particular side is visible. * Again, these are in the order left, top, right, bottom. * This should be preallocated with a size of at least 4. */ void retrieveMarkerInfo( const TQRect &marker, const KoRect &viewRect, double positions[], bool paintSides[] ); bool formatKeyPress( TQKeyEvent * _ev ); /** helper method for formatKeyPress */ bool formatCellByKey(Cell *cell, int key, const TQRect &rect); void processClickSelectionHandle(TQMouseEvent *event); void processLeftClickAnchor(); /** current cursor position, be it marker or choose marker */ TQPoint cursorPos(); /** * returns the rect that needs to be redrawn */ TQRect moveDirection(KSpread::MoveTo direction, bool extendSelection); void processEnterKey(TQKeyEvent *event); void processArrowKey(TQKeyEvent *event); void processEscapeKey(TQKeyEvent *event); bool processHomeKey(TQKeyEvent *event); bool processEndKey(TQKeyEvent *event); bool processPriorKey(TQKeyEvent *event); bool processNextKey(TQKeyEvent *event); void processDeleteKey(TQKeyEvent *event); void processF2Key(TQKeyEvent *event); void processF4Key(TQKeyEvent *event); void processOtherKey(TQKeyEvent *event); bool processControlArrowKey(TQKeyEvent *event); void processIMEvent( TQIMEvent * event ); /** * Used in choose mode. Shows/hides the editor depending on the selected * sheet. Triggers an update of the regions shown in the CellEditor. * @see CellEditor::updateChoice() */ void updateEditor(); /** * This function sets the paint dirty flag for a @p changedRegion in a * @p sheet . * The calculation which cells really should look different with the new * selection rather than repainting the entire area has to be done before. * @param sheet the sheet, which contains the cells * @param changedRegion the cell region to be set as dirty */ void setSelectionChangePaintDirty(Sheet* sheet, const Region& changedRegion); private: class Private; Private* d; }; /** * HBorder */ class HBorder : public TQWidget { Q_OBJECT TQ_OBJECT public: HBorder( TQWidget *_parent, Canvas *_canvas, View *_view ); ~HBorder(); int markerColumn() const { return m_iSelectionAnchor; } void equalizeColumn( double resize ); void updateColumns( int from, int to ); TQSize sizeHint() const; private slots: void doAutoScroll(); protected: virtual void paintEvent ( TQPaintEvent* _ev ); virtual void mousePressEvent( TQMouseEvent* _ev ); virtual void mouseReleaseEvent( TQMouseEvent* _ev ); virtual void mouseDoubleClickEvent( TQMouseEvent* _ev ); virtual void mouseMoveEvent( TQMouseEvent* _ev ); virtual void wheelEvent( TQWheelEvent* ); virtual void focusOutEvent( TQFocusEvent* ev ); virtual void resizeEvent( TQResizeEvent * _ev ); void paintSizeIndicator( int mouseX, bool firstTime ); private: Canvas *m_pCanvas; View *m_pView; TQTimer * m_scrollTimer; /** * Flag that inidicates whether the user wants to mark columns. * The user may mark columns by dragging the mouse around in th XBorder widget. * If he is doing that right now, this flag is true. Mention that the user may * also resize columns by dragging the mouse. This case is not covered by this flag. */ bool m_bSelection; /** * The column over which the user pressed the mouse button. * If the user marks columns in the XBorder widget, then this is the initial * column on which he pressed the mouse button. */ int m_iSelectionAnchor; /** * Flag that indicates whether the user resizes a column * The user may resize columns by dragging the mouse around in the HBorder widget. * If he is doing that right now, this flag is true. */ bool m_bResize; /** * The column over which the user pressed the mouse button. * The user may resize columns by dragging the mouse around the XBorder widget. * This is the column over which he pressed the mouse button. This column is going * to be resized. */ int m_iResizedColumn; /** * Last position of the mouse, when resizing. */ int m_iResizePos; /** * The label used for showing the current size, when resizing */ TQLabel *m_lSize; /** * True when the mouse button is pressed */ bool m_bMousePressed; private: }; /** * VBorder */ class VBorder : public TQWidget { Q_OBJECT TQ_OBJECT public: VBorder( TQWidget *_parent, Canvas *_canvas, View *_view ); ~VBorder(); int markerRow() const { return m_iSelectionAnchor; } void equalizeRow( double resize ); void updateRows( int from, int to ); TQSize sizeHint() const; private slots: void doAutoScroll(); protected: virtual void paintEvent ( TQPaintEvent* _ev ); virtual void mousePressEvent( TQMouseEvent* _ev ); virtual void mouseReleaseEvent( TQMouseEvent* _ev ); virtual void mouseMoveEvent( TQMouseEvent* _ev ); virtual void mouseDoubleClickEvent( TQMouseEvent* _ev ); virtual void wheelEvent( TQWheelEvent* ); virtual void focusOutEvent( TQFocusEvent* ev ); void paintSizeIndicator( int mouseY, bool firstTime ); private: Canvas *m_pCanvas; View *m_pView; TQTimer * m_scrollTimer; bool m_bSelection; int m_iSelectionAnchor; bool m_bResize; int m_iResizedRow; int m_iResizePos; /** * The label used for showing the current size, when resizing */ TQLabel *m_lSize; /** * True when the mouse button is pressed */ bool m_bMousePressed; }; /** * Tooltip, which displays the comment and cell content, when it's too short */ class ToolTip : public TQToolTip { public: ToolTip( Canvas* canvas ); protected: /** * @reimp */ void maybeTip( const TQPoint& p ); private: Canvas* m_canvas; }; } // namespace KSpread #endif // KSPREAD_CANVAS