diff options
Diffstat (limited to 'kexi/widget/tableview/kexidataawareobjectiface.h')
-rw-r--r-- | kexi/widget/tableview/kexidataawareobjectiface.h | 918 |
1 files changed, 918 insertions, 0 deletions
diff --git a/kexi/widget/tableview/kexidataawareobjectiface.h b/kexi/widget/tableview/kexidataawareobjectiface.h new file mode 100644 index 00000000..4cf2aa6a --- /dev/null +++ b/kexi/widget/tableview/kexidataawareobjectiface.h @@ -0,0 +1,918 @@ +/* This file is part of the KDE project + Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl> + + Based on KexiTableView code. + Copyright (C) 2002 Till Busch <till@bux.at> + Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at> + Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org> + Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org> + + This program 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXIDATAAWAREOBJECTINTERFACE_H +#define KEXIDATAAWAREOBJECTINTERFACE_H + +#include <qguardedptr.h> + +#include <qtimer.h> +#include <kdebug.h> +#include <widget/utils/kexiarrowtip.h> +#include <kexisearchandreplaceiface.h> +#include "kexitableviewdata.h" + +class QObject; +class QScrollBar; +class KPopupMenu; +class KexiTableItem; +class KexiTableViewData; +class KexiRecordMarker; +class KexiTableViewHeader; +class KexiRecordNavigator; +#include <kexidataiteminterface.h> + +namespace KexiDB { + class RowEditBuffer; +} + +//! default column width in pixels +#define KEXI_DEFAULT_DATA_COLUMN_WIDTH 120 + +//! \brief The KexiDataAwareObjectInterface is an interface for record-based data object. +/** This interface is implemented by KexiTableView and KexiFormView + and used by KexiDataAwareView. If yu're implementing this interface, + add KEXI_DATAAWAREOBJECTINTERFACE convenience macro just after Q_OBJECT. + + You should add following code to your destructor so data is deleted: + \code + if (m_owner) + delete m_data; + m_data = 0; + \endcode + This is not performed in KexiDataAwareObjectInterface because you may need + to access m_data in your desctructor. +*/ +class KEXIDATATABLE_EXPORT KexiDataAwareObjectInterface +{ + public: + KexiDataAwareObjectInterface(); + virtual ~KexiDataAwareObjectInterface(); + + /*! Sets data for this object. if \a owner is true, the object will own + \a data and therefore will be destroyed when needed, else: \a data is (possibly) shared and + not owned by the widget. + If widget already has _different_ data object assigned (and owns this data), + old data is destroyed before new assignment. + */ + void setData( KexiTableViewData *data, bool owner = true ); + + /*! \return data structure displayed for this object */ + inline KexiTableViewData *data() const { return m_data; } + + /*! \return currently selected column number or -1. */ + inline int currentColumn() const { return m_curCol; } + + /*! \return currently selected row number or -1. */ + inline int currentRow() const { return m_curRow; } + + /*! \return last row visible on the screen (counting from 0). + The returned value is guaranteed to be smaller or equal to currentRow() or -1 + if there are no rows. */ + virtual int lastVisibleRow() const = 0; + + /*! \return currently selected item (row data) or null. */ + KexiTableItem *selectedItem() const { return m_currentItem; } + + /*! \return number of rows in this view. */ + int rows() const; + + /*! \return number of visible columns in this view. + By default returns dataColumns(), what is proper table view. + In case of form view, there can be a number of duplicated columns defined + (data-aware widgets, see KexiFormScrollView::columns()), + so columns() can return greater number than dataColumns(). */ + virtual int columns() const { return dataColumns(); } + + /*! Helper function. + \return number of columns of data. */ + int dataColumns() const; + + /*! \return true if data represented by this object + is not editable (it can be editable with other ways although, + outside of this object). */ + virtual bool isReadOnly() const; + + /*! Sets readOnly flag for this object. + Unless the flag is set, the widget inherits readOnly flag from it's data + structure assigned with setData(). The default value if false. + + This method is useful when you need to switch on the flag indepentently + from the data structure. + Note: it is not allowed to force readOnly off + when internal data is readOnly - in that case the method does nothing. + You can check internal data flag calling data()->isReadOnly(). + + If \a set is true, insertingEnabled flag will be cleared automatically. + \sa isInsertingEnabled() + */ + void setReadOnly(bool set); + + /*! \return true if sorting is enabled. */ + inline bool isSortingEnabled() const { return m_isSortingEnabled; } + + /*! Sets sorting on column \a col, or (when \a col == -1) sets rows unsorted + this will do not work if sorting is disabled with setSortingEnabled() */ + virtual void setSorting(int col, bool ascending=true); + + /*! Enables or disables sorting for this object + This method is different that setSorting() because it prevents both user + and programmer from sorting by clicking a column's header or calling setSorting(). + By default sorting is enabled. + */ + virtual void setSortingEnabled(bool set); + + /*! \return sorted column number or -1 if no column is sorted within data. + This does not mean that any sorting has been performed within GUI of this object, + because the data could be changed in the meantime outside of this GUI object. */ + int dataSortedColumn() const; + + /*! \return 1 if ascending order for data sorting data is set, -1 for descending, + 0 for no sorting. + This does not mean that any sorting has been performed within GUI of this objetct, + because the data could be changed in the meantime outside of this GUI object. + */ + int dataSortingOrder() const; + + /*! Sorts all rows by column selected with setSorting(). + If there is currently row edited, it is accepted. + If acception failed, sort() will return false. + \return true on success. */ + virtual bool sort(); + + /*! Sorts currently selected column in ascending order. + This slot is used typically for "data_sort_az" action. */ + void sortAscending(); + + /*! Sorts currently selected column in descending order. + This slot is used typically for "data_sort_za" action. */ + void sortDescending(); + + /*! \return true if data inserting is enabled (the default). */ + virtual bool isInsertingEnabled() const; + + /*! Sets insertingEnabled flag. If true, empty row is available + at the end of this widget for new entering new data. + Unless the flag is set, the widget inherits insertingEnabled flag from it's data + structure assigned with setData(). The default value if false. + + Note: it is not allowed to force insertingEnabled on when internal data + has insertingEnabled set off - in that case the method does nothing. + You can check internal data flag calling data()->insertingEnabled(). + + Setting this flag to true will have no effect if read-only flag is true. + \sa setReadOnly() + */ + void setInsertingEnabled(bool set); + + /*! \return true if row deleting is enabled. + Equal to deletionPolicy() != NoDelete && !isReadOnly()). */ + bool isDeleteEnabled() const; + + /*! \return true if inserting empty rows are enabled (false by default). + Mostly usable for not db-aware objects (e.g. used in Kexi Alter Table). + Note, that if inserting is disabled, or the data set is read-only, + this flag will be ignored. */ + bool isEmptyRowInsertingEnabled() const { return m_emptyRowInsertingEnabled; } + + /*! Sets emptyRowInserting flag. + Note, that if inserting is disabled, this flag is ignored. */ + void setEmptyRowInsertingEnabled(bool set); + + /*! Enables or disables filtering. Filtering is enabled by default. */ + virtual void setFilteringEnabled(bool set); + + /*! \return true if filtering is enabled. */ + inline bool isFilteringEnabled() const { return m_isFilteringEnabled; } + + /*! Added for convenience: configure this object + to behave more like spreadsheet (it's used for things like alter-table view). + - hides navigator + - disables sorting, inserting and filtering + - enables accepting row after cell accepting; see setAcceptsRowEditAfterCellAccepting() + - enables inserting empty row; see setEmptyRowInsertingEnabled() */ + virtual void setSpreadSheetMode(); + + /*! \return true id "spreadSheetMode" is enabled. It's false by default. */ + bool spreadSheetMode() const { return m_spreadSheetMode; } + + /*! \return true if currently selected row is edited. */ + inline bool rowEditing() const { return m_rowEditing; } + + enum DeletionPolicy + { + NoDelete = 0, + AskDelete = 1, + ImmediateDelete = 2, + SignalDelete = 3 + }; + + /*! \return deletion policy for this object. + The default (after allocating) is AskDelete. */ + DeletionPolicy deletionPolicy() const { return m_deletionPolicy; } + + virtual void setDeletionPolicy(DeletionPolicy policy); + + /*! Deletes currently selected record; does nothing if no record + is currently selected. If record is in edit mode, editing + is cancelled before deleting. */ + virtual void deleteCurrentRow(); + + /*! Inserts one empty row above row \a row. If \a row is -1 (the default), + new row is inserted above the current row (or above 1st row if there is no current). + A new item becomes current if row is -1 or if row is equal currentRow(). + This method does nothing if: + -inserting flag is disabled (see isInsertingEnabled()) + -read-only flag is set (see isReadOnly()) + \ return inserted row's data + */ + virtual KexiTableItem *insertEmptyRow(int row = -1); + + /*! For reimplementation: called by deleteItem(). If returns false, deleting is aborted. + Default implementation just returns true. */ + virtual bool beforeDeleteItem(KexiTableItem *item); + + /*! Deletes \a item. Used by deleteCurrentRow(). Calls beforeDeleteItem() before deleting, + to double-check if deleting is allowed. + \return true on success. */ + bool deleteItem(KexiTableItem *item);//, bool moveCursor=true); + + /*! Inserts newItem at \a row. -1 means current row. Used by insertEmptyRow(). */ + void insertItem(KexiTableItem *newItem, int row = -1); + + /*! Clears entire table data, its visible representation + and deletes data at database backend (if this is db-aware object). + Does not clear columns information. + Does not destroy KexiTableViewData object (if present) but only clears its contents. + Displays confirmation dialog if \a ask is true (the default is false). + Repaints widget if \a repaint is true (the default). + For empty tables, true is returned immediately. + If isDeleteEnabled() is false, false is returned. + For spreadsheet mode all current rows are just replaced by empty rows. + \return true on success, false on failure, and cancelled if user cancelled deletion + (only possible if \a ask is true). + */ + tristate deleteAllRows(bool ask = false, bool repaint = true); + + /*! \return maximum number of rows that can be displayed per one "page" + for current view's size. */ + virtual int rowsPerPage() const = 0; + + virtual void selectRow(int row); + virtual void selectNextRow(); + virtual void selectPrevRow(); + virtual void selectNextPage(); //!< page down action + virtual void selectPrevPage(); //!< page up action + virtual void selectFirstRow(); + virtual void selectLastRow(); + virtual void addNewRecordRequested(); + + /*! Clears current selection. Current row and column will be now unspecified: + currentRow(), currentColumn() will return -1, and selectedItem() will return null. */ + virtual void clearSelection(); + + /*! Moves cursor to \a row and \a col. If \a col is -1, current column number is used. + If forceSet is true, cursor position is updated even if \a row and \a col doesn't + differ from actual position. */ + virtual void setCursorPosition(int row, int col = -1, bool forceSet = false); + + /*! Ensures that cell at \a row and \a col is visible. + If \a col is -1, current column number is used. \a row and \a col (if not -1) must + be between 0 and rows() (or cols() accordingly). */ + virtual void ensureCellVisible(int row, int col/*=-1*/) = 0; + + /*! Specifies, if this object automatically accepts + row editing (using acceptRowEdit()) on accepting any cell's edit + (i.e. after acceptEditor()). \sa acceptsRowEditAfterCellAccepting() */ + virtual void setAcceptsRowEditAfterCellAccepting(bool set); + + /*! \return true, if this object automatically accepts + row editing (using acceptRowEdit()) on accepting any cell's edit + (i.e. after acceptEditor()). + By default this flag is set to false. + Not that if the query for this table has given constraints defined, + like NOT NULL / NOT EMPTY for more than one field - editing a record would + be impossible for the flag set to true, because of constraints violation. + However, setting this flag to true can be useful especially for not-db-aware + data set (it's used e.g. in Kexi Alter Table's field editor). */ + bool acceptsRowEditAfterCellAccepting() const { return m_acceptsRowEditAfterCellAccepting; } + + /*! \return true, if this table accepts dropping data on the rows. */ + bool dropsAtRowEnabled() const { return m_dropsAtRowEnabled; } + + /*! Specifies, if this table accepts dropping data on the rows. + If enabled: + - dragging over row is indicated by drawing a line at bottom side of this row + - dragOverRow() signal will be emitted on dragging, + -droppedAtRow() will be emitted on dropping + By default this flag is set to false. */ + virtual void setDropsAtRowEnabled(bool set); + + /*! \return currently used data (field/cell) editor or 0 if there is no data editing. */ + inline KexiDataItemInterface *editor() const { return m_editor; } + + /*! Cancels row editing All changes made to the editing + row during this current session will be undone. + \return true on success or false on failure (e.g. when editor does not exist) */ + virtual bool cancelRowEdit(); + + /*! Accepts row editing. All changes made to the editing + row during this current session will be accepted (saved). + \return true if accepting was successful, false otherwise + (e.g. when current row contain data that does not meet given constraints). */ + virtual bool acceptRowEdit(); + + virtual void removeEditor(); + + /*! Cancels changes made to the currently active editor. + Reverts the editor's value to old one. + \return true on success or false on failure (e.g. when editor does not exist) */ + virtual bool cancelEditor(); + + //! Accepst changes made to the currently active editor. + //! \return true on success or false on failure (e.g. when editor does not exist or there is data validation error) + virtual bool acceptEditor(); + + //! Creates editors and shows it, what usually means the beginning of a cell editing + virtual void createEditor(int row, int col, const QString& addText = QString::null, + bool removeOld = false) = 0; + + /*! Used when Return key is pressed on cell, the cell has been double clicked + or "+" navigator's button is clicked. + Also used when we want to continue editing a cell after "invalid value" message + was displayed (in this case, \a setText is usually not empty, what means + that text will be set in the cell replacing previous value). + */ + virtual void startEditCurrentCell(const QString& setText = QString::null); + + /*! Deletes currently selected cell's contents, if allowed. + In most cases delete is not accepted immediately but "row editing" mode is just started. */ + virtual void deleteAndStartEditCurrentCell(); + + inline KexiTableItem *itemAt(int row) const; + + /*! \return column information for column number \a col. + Default implementation just returns column # col, + but for Kexi Forms column data + corresponding to widget number is used here + (see KexiFormScrollView::fieldNumberForColumn()). */ + virtual KexiTableViewColumn* column(int col); + + /*! \return field number within data model connected to a data-aware + widget at column \a col. Can return -1 if there's no such column. */ + virtual int fieldNumberForColumn(int col) { return col; } + + bool hasDefaultValueAt(const KexiTableViewColumn& tvcol); + + const QVariant* bufferedValueAt(int col, bool useDefaultValueIfPossible = true); + + //! \return a type of column \a col - one of KexiDB::Field::Type + int columnType(int col); + + //! \return default value for column \a col + QVariant columnDefaultValue(int col) const; + + /*! \return true is column \a col is editable. + Default implementation takes information about 'readOnly' flag from data member. + Within forms, this is reimplemented for checking 'readOnly' flag from a widget + ('readOnly' flag from data member is still checked though). + */ + virtual bool columnEditable(int col); + + /*! Redraws the current cell. To be implemented. */ + virtual void updateCurrentCell() = 0; + + inline KexiRecordMarker* verticalHeader() const { return m_verticalHeader; } + + //! signals + virtual void itemChanged(KexiTableItem *, int row, int col) = 0; + virtual void itemChanged(KexiTableItem *, int row, int col, QVariant oldValue) = 0; + virtual void itemDeleteRequest(KexiTableItem *, int row, int col) = 0; + virtual void currentItemDeleteRequest() = 0; + //! Emitted for spreadsheet mode when an item was deleted and a new item has been appended + virtual void newItemAppendedForAfterDeletingInSpreadSheetMode() = 0; + + /*! Data has been refreshed on-screen - emitted from initDataContents(). */ + virtual void dataRefreshed() = 0; + virtual void dataSet( KexiTableViewData *data ) = 0; + + /*! \return a pointer to context menu. This can be used to plug some actions there. */ + KPopupMenu* contextMenu() const { return m_popupMenu; } + + /*! \return true if the context menu is enabled (visible) for the view. + True by default. */ + bool contextMenuEnabled() const { return m_contextMenuEnabled; } + + /*! Enables or disables the context menu for the view. */ + void setContextMenuEnabled(bool set) { m_contextMenuEnabled = set; } + + /*! \return true if vertical scrollbar's tooltips are enabled (true by default). */ + bool scrollbarToolTipsEnabled() const; + + /*! Enables or disables vertical scrollbar's tooltip. */ + void setScrollbarToolTipsEnabled(bool set); + + /*! Typically handles pressing Enter or F2 key: + if current cell has boolean type, toggles it's value, + otherwise starts editing (startEditCurrentCell()). */ + void startEditOrToggleValue(); + + /*! \return true if new row is edited; implies: rowEditing==true. */ + inline bool newRowEditing() const { return m_newRowEditing; } + + /*! Reaction on toggling a boolean value of a cell: + we're starting to edit the cell and inverting it's state. */ + virtual void boolToggled(); + + virtual void connectCellSelectedSignal(const QObject* receiver, + const char* intIntMember) = 0; + + virtual void connectRowEditStartedSignal(const QObject* receiver, + const char* intMember) = 0; + + virtual void connectRowEditTerminatedSignal(const QObject* receiver, + const char* voidMember) = 0; + + virtual void connectReloadActionsSignal(const QObject* receiver, + const char* voidMember) = 0; + + virtual void connectDataSetSignal(const QObject* receiver, + const char* kexiTableViewDataMember) = 0; + + virtual void connectToReloadDataSlot(const QObject* sender, + const char* voidSignal) = 0; + + virtual void slotDataDestroying(); + + //! Copy current selection to a clipboard (e.g. cell) + virtual void copySelection() = 0; + + //! Cut current selection to a clipboard (e.g. cell) + virtual void cutSelection() = 0; + + //! Paste current clipboard contents (e.g. to a cell) + virtual void paste() = 0; + + /*! Finds \a valueToFind within the data items + \a options are used to control the process. Selection is moved to found value. + If \a next is true, "find next" is performed, else "find previous" is performed. + + Searching behaviour also depends on status of the previous search: for every search, + position of the cells containing the found value is stored internally + by the data-aware interface (not in options). + Moreover, position (start, end) of the found value is also stored. + Thus, the subsequent search will reuse this information to be able to start + searching exactly after the previously found value (or before for "find previous" option). + The flags can be zeroed, what will lead to seaching from the first character + of the current item (cell). + + \return true if value has been found, false if value has not been found, + and cancelled if there is nothing to find or there is no data to search in. */ + virtual tristate find(const QVariant& valueToFind, + const KexiSearchAndReplaceViewInterface::Options& options, bool next); + + /*! Finds \a valueToFind within the data items and replaces with \a replacement + \a options are used to control the process. + \return true if value has been found and replaced, false if value + has not been found and replaced, and cancelled if there is nothing + to find or there is no data to search in or the data is read only. + If \a replaceAll is true, all found values are replaced. */ + virtual tristate findNextAndReplace(const QVariant& valueToFind, + const QVariant& replacement, + const KexiSearchAndReplaceViewInterface::Options& options, bool replaceAll); + + /*! \return vertical scrollbar */ + virtual QScrollBar* verticalScrollBar() const = 0; + + /*! Used in KexiTableView::keyPressEvent() (and in continuous forms). + \return true when the key press event \e was consumed. + You should also check e->isAccepted(), if it's true, nothing should be done; + if it is false, you should call setCursorPosition() for the altered \a curCol + and \c curRow variables. + + If \a moveToFirstField is not 0, *moveToFirstField will be set to true + when the cursor should be moved to the first field (in tab order) and to false otherwise. + If \a moveToLastField is not 0, *moveToLastField will be set to true + when the cursor should be moved to the last field (in tab order) and to false otherwise. + Note for forms: if moveToFirstField and moveToLastField are not 0, + \a curCol is altered after calling this method, so setCursorPosition() will set to + the index of an appropriate column (field). This is needed because field widgets can be + inserted and ordered in custom tab order, so the very first field in the data source + can be other than the very first field in the form. + + Used by KexiTableView::keyPressEvent() and KexiTableView::keyPressEvent(). */ + virtual bool handleKeyPress(QKeyEvent *e, int &curRow, int &curCol, bool fullRowSelection, + bool *moveToFirstField = 0, bool *moveToLastField = 0); + + protected: + /*! Reimplementation for KexiDataAwareObjectInterface. + Initializes data contents (resizes it, sets cursor at 1st row). + Sets record count for record navigator. + Sets cursor positin (using setCursorPosition()) to first row or sets + (-1, -1) position if no rows are available. + Called on setData(). Also called once on show event after + refreshRequested() signal was received from KexiTableViewData object. */ + virtual void initDataContents(); + + /*! Clears columns information and thus all internal table data + and its visible representation. Repaints widget if \a repaint is true. */ + virtual void clearColumns(bool repaint = true); + + /*! Called by clearColumns() to clear internals of the object. + For example, KexiTableView removes contents of it's horizontal header. */ + virtual void clearColumnsInternal(bool repaint) = 0; + + /*! @internal for implementation + This should append another section within horizontal header or any sort of caption + for a field using provided names. \a width is a hint for new field's width. */ + virtual void addHeaderColumn(const QString& caption, const QString& description, + const QIconSet& icon, int size) = 0; + + /*! @internal for implementation + \return sorting order (within GUI): -1: descending, 1: ascending, 0: no sorting. + This does not mean that any sorting has been performed within GUI of this object, + because the data could be changed in the meantime outside of this GUI object. + @see dataSortingOrder()*/ + virtual int currentLocalSortingOrder() const = 0; + + /*! @internal for implementation + \return sorted column number for this widget or -1 if no column + is sorted witin GUI. + This does not mean that the same sorting is performed within data member + which is used by this widget, because the data could be changed in the meantime + outside of this GUI widget. + @see dataSortedColumn() */ + virtual int currentLocalSortColumn() const = 0; + + /*! @internal for implementation + Shows sorting indicator order within GUI: -1: descending, 1: ascending, + 0: no sorting. This should not perform any sorting within data member + which is used by this object. + col = -1 should mean "no sorting" as well. */ + virtual void setLocalSortingOrder(int col, int order) = 0; + + /*! @internal Sets order for \a column: -1: descending, 1: ascending, + 0: invert order */ + virtual void sortColumnInternal(int col, int order = 0); + + /*! @internal for implementation + Updates GUI after sorting. + After sorting you need to ensure current row and column + is visible to avoid user confusion. For exaple, in KexiTableView + implementation, current cell is centered (if possible) + and updateContents() is called. */ + virtual void updateGUIAfterSorting() = 0; + + /*! Emitted in initActions() to force reload actions + You should remove existing actions and add them again. + Define and emit reloadActions() signal here. */ + virtual void reloadActions() = 0; + + /*! Reloads data for this object. */ + virtual void reloadData(); + + /*! for implementation as a signal */ + virtual void itemSelected(KexiTableItem *) = 0; + + /*! for implementation as a signal */ + virtual void cellSelected(int col, int row) = 0; + + /*! for implementation as a signal */ + virtual void sortedColumnChanged(int col) = 0; + + /*! for implementation as a signal */ + virtual void rowEditTerminated(int row) = 0; + + /*! Clear temporary members like the pointer to current editor. + If you reimplement this method, don't forget to call this one. */ + virtual void clearVariables(); + + /*! @internal + Creates editor structure without filling it with data. + Used in createEditor() and few places to be able to display cell contents + dependending on its type. If \a ignoreMissingEditor is false (the default), + and editor cannot be instantiated, current row editing (if present) is cancelled. + */ + virtual KexiDataItemInterface *editor( int col, bool ignoreMissingEditor = false ) = 0; + + /*! Updates editor's position, size and shows its focus (not the editor!) + for \a row and \a col, using editor(). Does nothing if editor not found. */ + virtual void editorShowFocus( int row, int col ) = 0; + + /*! Redraws specified cell. */ + virtual void updateCell(int row, int col) = 0; + + /*! Redraws all cells of specified row. */ + virtual void updateRow(int row) = 0; + + /*! Updates contents of the widget. Just call update() here on your widget. */ + virtual void updateWidgetContents() = 0; + + /*! Updates widget's contents size e.g. using QScrollView::resizeContents(). */ + virtual void updateWidgetContentsSize() = 0; + + /*! Updates scrollbars of the widget. + QScrollView::updateScrollbars() will be usually called here. */ + virtual void updateWidgetScrollBars() = 0; + + /*! @internal + Updates row appearance after canceling row edit. + Used by cancelRowEdit(). By default just calls updateRow(m_curRow). + Reimplemented by KexiFormScrollView. */ + virtual void updateAfterCancelRowEdit(); + + /*! @internal + Updates row appearance after accepting row edit. + Used by acceptRowEdit(). By default just calls updateRow(m_curRow). + Reimplemented by KexiFormScrollView. */ + virtual void updateAfterAcceptRowEdit(); + + //! Handles KexiTableViewData::rowRepaintRequested() signal + virtual void slotRowRepaintRequested(KexiTableItem& item) { Q_UNUSED( item ); } + + //! Handles KexiTableViewData::aboutToDeleteRow() signal. Prepares info for slotRowDeleted(). + virtual void slotAboutToDeleteRow(KexiTableItem& item, KexiDB::ResultInfo* result, + bool repaint); + + //! Handles KexiTableViewData::rowDeleted() signal to repaint when needed. + virtual void slotRowDeleted(); + + //! Handles KexiTableViewData::rowInserted() signal to repaint when needed. + virtual void slotRowInserted(KexiTableItem *item, bool repaint); + + //! Like above, not db-aware version + virtual void slotRowInserted(KexiTableItem *item, uint row, bool repaint); + + virtual void slotRowsDeleted( const QValueList<int> & ) {} + + //! for sanity checks (return true if m_data is present; else: outputs warning) + inline bool hasData() const; + + /*! Only needed for forms: called by KexiDataAwareObjectInterface::setCursorPosition() + if cursor's position is really changed. */ + virtual void selectCellInternal() {} + + /*! Used in KexiDataAwareObjectInterface::slotRowDeleted() + to repaint tow \a row and all visible below. + Implemented if there is more than one row displayed, i.e. currently for KexiTableView. */ + virtual void updateAllVisibleRowsBelow(int row) { Q_UNUSED( row ); } + + //! Call this from the subclass. */ + virtual void focusOutEvent(QFocusEvent* e); + + /*! Handles verticalScrollBar()'s valueChanged(int) signal. + Called when vscrollbar's value has been changed. + Call this method from the subclass. */ + virtual void vScrollBarValueChanged(int v); + + /*! Handles sliderReleased() signal of the verticalScrollBar(). Used to hide the "row number" tooltip. */ + virtual void vScrollBarSliderReleased(); + + /*! Handles timeout() signal of the m_scrollBarTipTimer. If the tooltip is visible, + m_scrollBarTipTimerCnt is set to 0 and m_scrollBarTipTimerCnt is restarted; + else the m_scrollBarTipTimerCnt is just set to 0.*/ + virtual void scrollBarTipTimeout(); + + /*! Shows error message box suitable for \a resultInfo. This can be "sorry" or "detailedSorry" + message box or "queryYesNo" if resultInfo->allowToDiscardChanges is true. + \return code of button clicked: KMessageBox::Ok in case of "sorry" or "detailedSorry" messages + and KMessageBox::Yes or KMessageBox::No in case of "queryYesNo" message. */ + int showErrorMessageForResult(KexiDB::ResultInfo* resultInfo); + + /*! Prepares array of indices of visible values to search within. + This is per-interface global cache. + Needed for faster lookup because there could be lookup values. + Called whenever columns definition changes, i.e. in setData() and clearColumns(). + @see find() */ + void updateIndicesForVisibleValues(); + + //! data structure displayed for this object + KexiTableViewData *m_data; + + //! true if m_data member is owned by this object + bool m_owner : 1; + + //! cursor position + int m_curRow, m_curCol; + + //! current data item + KexiTableItem *m_currentItem; + + //! data item's iterator + KexiTableViewData::Iterator *m_itemIterator; + + //! item data for inserting + KexiTableItem *m_insertItem; + + //! when (current or new) row is edited - changed field values are temporary stored here +// KexiDB::RowEditBuffer *m_rowEditBuffer; + + /*! true if currently selected row is edited */ + bool m_rowEditing : 1; + + /*! true if new row is edited; implies: rowEditing==true. */ + bool m_newRowEditing : 1; + + /*! 'sorting by column' availability flag for widget */ + bool m_isSortingEnabled : 1; + + /*! true if filtering is enabled for the view. */ + bool m_isFilteringEnabled : 1; + + /*! Public version of 'acceptsRowEditAfterCellAcceptin' flag (available for a user). + It's OR'es together with above flag. + */ + bool m_acceptsRowEditAfterCellAccepting : 1; + + /*! Used in acceptEditor() to avoid infinite recursion, + eg. when we're calling acceptRowEdit() during cell accepting phase. */ + bool m_inside_acceptEditor : 1; + + /*! @internal if true, this object automatically accepts + row editing (using acceptRowEdit()) on accepting any cell's edit + (i.e. after acceptEditor()). */ + bool m_internal_acceptsRowEditAfterCellAccepting : 1; + + /*! true, if inserting empty rows are enabled (false by default) */ + bool m_emptyRowInsertingEnabled : 1; + + /*! Contains 1 if the object is readOnly, 0 if not; + otherwise (-1 means "do not know") the 'readOnly' flag from object's + internal data structure (KexiTableViewData *KexiTableView::m_data) is reused. + */ + int m_readOnly; + +//! @todo really keep this here and not in KexiTableView? + /*! true if currently double click action was is performed + (so accept/cancel editor shoudn't be executed) */ + bool m_contentsMousePressEvent_dblClick : 1; + + /*! like for readOnly: 1 if inserting is enabled */ + int m_insertingEnabled; + + /*! true, if initDataContents() should be called on show event. */ + bool m_initDataContentsOnShow : 1; + + /*! Set to true in setCursorPosition() to indicate that cursor position was set + before show() and it shouldn't be changed on show(). + Only used if initDataContentsOnShow is true. */ + bool m_cursorPositionSetExplicityBeforeShow : 1; + + /*! true if spreadSheetMode is enabled. False by default. + @see KexiTableView::setSpreadSheetMode() */ + bool m_spreadSheetMode : 1; + + /*! true, if this table accepts dropping data on the rows (false by default). */ + bool m_dropsAtRowEnabled : 1; + + /*! true, if this entire (visible) row should be updated when boving to other row. + False by default. For table view with 'row highlighting' flag enabled, it is true. */ + bool m_updateEntireRowWhenMovingToOtherRow : 1; + + DeletionPolicy m_deletionPolicy; + +//! @todo make generic interface out of KexiRecordMarker + KexiRecordMarker *m_verticalHeader; + +//! @todo make generic interface out of KexiTableViewHeader + KexiTableViewHeader *m_horizontalHeader; + + KexiDataItemInterface *m_editor; +// KexiTableEdit *m_editor; + + /*! Navigation panel, used if navigationPanelEnabled is true. */ + KexiRecordNavigator *m_navPanel; //!< main navigation widget + + bool m_navPanelEnabled : 1; + + /*! true, if certical header shouldn't be increased in + KexiTableView::slotRowInserted() because it was already done + in KexiTableView::createEditor(). */ + bool m_verticalHeaderAlreadyAdded : 1; + + /*! Row number that over which user drags a mouse pointer. + Used to indicate dropping possibility for that row. + Equal -1 if no indication is needed. */ + int m_dragIndicatorLine; + + /*! Context menu widget. */ + KPopupMenu *m_popupMenu; + + bool m_contextMenuEnabled : 1; + + //! Used by updateAfterCancelRowEdit() + bool m_alsoUpdateNextRow : 1; + + /*! Row number (>=0 or -1 == no row) that will be deleted in deleteRow(). + It is set in slotAboutToDeleteRow(KexiTableItem&,KexiDB::ResultInfo*,bool)) slot + received from KexiTableViewData member. + This value will be used in slotRowDeleted() after rowDeleted() signal + is received from KexiTableViewData member and then cleared (set to -1). */ + int m_rowWillBeDeleted; + + /*! Displays passive error popup label used when invalid data has been entered. */ + QGuardedPtr<KexiArrowTip> m_errorMessagePopup; + + /*! Used to enable/disable execution of vScrollBarValueChanged() + when users navigate through rows using keyboard, so vscrollbar tooltips are not visible. */ + bool m_vScrollBarValueChanged_enabled : 1; + + /*! True, if vscrollbar tooltips are enabled (true by default). */ + bool m_scrollbarToolTipsEnabled : 1; + + QLabel* m_scrollBarTip; //!< scrollbar tooltip + QTimer m_scrollBarTipTimer; //!< scrollbar tooltip's timer + uint m_scrollBarTipTimerCnt; //!< helper for timeout counting (scrollbar tooltip) + + //! Used to mark recently found value + class PositionOfValue { + public: + PositionOfValue() : firstCharacter(0), lastCharacter(0), exists(false) + {} + uint firstCharacter; + uint lastCharacter; + bool exists : 1; + }; + + /*! Used to mark recently found value. Updated on succesful execution of find(). + If the current cursor's position changes, or data in the current cell changes, + positionOfRecentlyFoundValue.exists is set to false. */ + PositionOfValue m_positionOfRecentlyFoundValue; + + /*! Used to compare whether we're looking for new value. */ + QVariant m_recentlySearchedValue; + + /*! Used to compare whether the search direction has changed. */ + KexiSearchAndReplaceViewInterface::Options::SearchDirection m_recentSearchDirection; + + //! Setup by updateIndicesForVisibleValues() and used by find() + QValueVector<uint> m_indicesForVisibleValues; +}; + +inline bool KexiDataAwareObjectInterface::hasData() const +{ + if (!m_data) + kdDebug() << "KexiDataAwareObjectInterface: No data assigned!" << endl; + return m_data!=0; +} + +inline KexiTableItem *KexiDataAwareObjectInterface::itemAt(int row) const +{ + KexiTableItem *item = m_data->at(row); + if (!item) + kdDebug() << "KexiTableView::itemAt(" << row << "): NO ITEM!!" << endl; + else { +/* kdDebug() << "KexiTableView::itemAt(" << row << "):" << endl; + int i=1; + for (KexiTableItem::Iterator it = item->begin();it!=item->end();++it,i++) + kdDebug() << i<<": " << (*it).toString()<< endl;*/ + } + return item; +} + +//! Convenience macro used for KexiDataAwareObjectInterface implementations. +#define KEXI_DATAAWAREOBJECTINTERFACE \ +public: \ + void connectCellSelectedSignal(const QObject* receiver, const char* intIntMember) { \ + connect(this, SIGNAL(cellSelected(int,int)), receiver, intIntMember); \ + } \ + void connectRowEditStartedSignal(const QObject* receiver, const char* intMember) { \ + connect(this, SIGNAL(rowEditStarted(int)), receiver, intMember); \ + } \ + void connectRowEditTerminatedSignal(const QObject* receiver, const char* voidMember) { \ + connect(this, SIGNAL(rowEditTerminated(int)), receiver, voidMember); \ + } \ + void connectReloadActionsSignal(const QObject* receiver, const char* voidMember) { \ + connect(this, SIGNAL(reloadActions()), receiver, voidMember); \ + } \ + void connectDataSetSignal(const QObject* receiver, \ + const char* kexiTableViewDataMember) { \ + connect(this, SIGNAL(dataSet(KexiTableViewData*)), receiver, kexiTableViewDataMember); \ + } \ + void connectToReloadDataSlot(const QObject* sender, const char* voidSignal) { \ + connect(sender, voidSignal, this, SLOT(reloadData())); \ + } + +#endif |