as_table.cpp

changeset 1
d64aaa7d146f
child 3
c1941114ca88
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/as_table.cpp	Fri Nov 28 11:21:08 2008 +0100
     1.3 @@ -0,0 +1,251 @@
     1.4 +//
     1.5 +//  OSSP asgui - Accounting system graphical user interface
     1.6 +//  Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
     1.7 +//  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
     1.8 +//  Copyright (c) 2002-2004 Michael Schloh von Bennewitz <michael@schloh.com>
     1.9 +//  Copyright (c) 2002-2004 Cable & Wireless Telecommunications Services GmbH
    1.10 +//
    1.11 +//  This file is part of OSSP asgui, an accounting system graphical user
    1.12 +//  interface which can be found at http://www.ossp.org/pkg/tool/asgui/.
    1.13 +//
    1.14 +//  Permission to use, copy, modify, and distribute this software for
    1.15 +//  any purpose with or without fee is hereby granted, provided that
    1.16 +//  the above copyright notice and this permission notice appear in all
    1.17 +//  copies.
    1.18 +//
    1.19 +//  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    1.20 +//  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    1.21 +//  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    1.22 +//  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
    1.23 +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.24 +//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.25 +//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    1.26 +//  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    1.27 +//  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    1.28 +//  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    1.29 +//  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    1.30 +//  SUCH DAMAGE.
    1.31 +//
    1.32 +//  as_table.cpp: ISO C++ implementation
    1.33 +//
    1.34 +
    1.35 +#include <qheader.h>
    1.36 +
    1.37 +#include "as_const.h"
    1.38 +#include "as_table.h"
    1.39 +
    1.40 +
    1.41 +// Implements an event filter for catching header double click events
    1.42 +bool TiTable::eventFilter(QObject *pObject, QEvent *pEvent)
    1.43 +{
    1.44 +    if (pObject == horizontalHeader() && pEvent->type() == QEvent::MouseButtonDblClick)
    1.45 +        return true;
    1.46 +    if (pEvent->type() == QEvent::MouseButtonPress &&   // Ignore mid, right clicks
    1.47 +        ((QMouseEvent *)pEvent)->button() == QMouseEvent::RightButton ||
    1.48 +        ((QMouseEvent *)pEvent)->button() == QMouseEvent::MidButton)
    1.49 +        return true;
    1.50 +    else if (pEvent->type() == QEvent::KeyPress) {
    1.51 +        if (((QKeyEvent *)pEvent)->key() == Qt::Key_Tab) { // Handle tab key
    1.52 +            if (this->getEdition() >= 0) {
    1.53 +                int nIter = 1; // Logic to skip invisible or read only columns
    1.54 +                while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
    1.55 +                    || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
    1.56 +                    nIter++;
    1.57 +
    1.58 +                // Advance the column or both row and column possibly
    1.59 +                int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
    1.60 +                if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL) {
    1.61 +                    this->clearSelection(true);
    1.62 +                    this->setCurrentCell(currentRow() + 1, nColadvance);
    1.63 +//                    this->repaint(false);   // Really necessary?
    1.64 +                }
    1.65 +                else
    1.66 +                    this->setCurrentCell(currentRow(), nColadvance);
    1.67 +                this->setReadOnly(false);
    1.68 +                this->editCell(currentRow(), currentColumn());
    1.69 +                this->setEdition(currentColumn());
    1.70 +            }
    1.71 +            return true; // Handle the tab key event and cancel its progress
    1.72 +        }
    1.73 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Backtab) { // Handle shift tab key
    1.74 +            if (this->getEdition() >= 0) {
    1.75 +                int nIter = 1; // Logic to skip invisible or read only columns
    1.76 +                while (columnWidth((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL) <= 0
    1.77 +                    || isColumnReadOnly((currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL))
    1.78 +                    nIter++;
    1.79 +
    1.80 +                // Advance the column or both row and column possibly
    1.81 +                int nColadvance = (currentColumn() - nIter + TITRAQ_IDXTAIL) % TITRAQ_IDXTAIL;
    1.82 +                if ((currentColumn() - nIter) < 0) {
    1.83 +                    this->clearSelection(true);
    1.84 +                    this->setCurrentCell(currentRow() - 1, nColadvance);
    1.85 +//                    this->repaint(false);   // Really necessary?
    1.86 +                }
    1.87 +                else
    1.88 +                    this->setCurrentCell(currentRow(), nColadvance);
    1.89 +                this->setReadOnly(false);
    1.90 +                this->editCell(currentRow(), currentColumn());
    1.91 +                this->setEdition(currentColumn());
    1.92 +            }
    1.93 +            return true; // Handle the shift tab key event and cancel its progress
    1.94 +        }
    1.95 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return && this->getEdition() >= 0) { // Return key
    1.96 +            this->endEdit(currEditRow(), currEditCol(), true, false);
    1.97 +            this->setEdition();                             // Reset edition
    1.98 +            return true;                                    // Cancel progress
    1.99 +        }
   1.100 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter && this->getEdition() >= 0) { // Enter key
   1.101 +            this->endEdit(currEditRow(), currEditCol(), true, false);
   1.102 +            this->setEdition();                             // Reset edition
   1.103 +            return true;                                    // Cancel progress
   1.104 +        }
   1.105 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Return) { // Return key without edition
   1.106 +            this->setReadOnly(false);                       // Allow edition
   1.107 +            this->editCell(currentRow(), currentColumn());  // Begin edition
   1.108 +            this->setEdition(currentColumn());              // Store edition state
   1.109 +            return true;                                    // Cancel further progress
   1.110 +        }
   1.111 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Enter) { // Enter key without edition
   1.112 +            this->setReadOnly(false);                       // Allow edition
   1.113 +            this->editCell(currentRow(), currentColumn());  // Begin edition
   1.114 +            this->setEdition(currentColumn());              // Store edition state
   1.115 +            return true;                                    // Cancel further progress
   1.116 +        }
   1.117 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Escape)    // Handle escape key
   1.118 +            this->setEdition();
   1.119 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Up && this->getEdition() >= 0) // Handle up key
   1.120 +            return true;                                            // Capture
   1.121 +        else if (((QKeyEvent *)pEvent)->key() == Qt::Key_Down && this->getEdition() >= 0) // Handle down key
   1.122 +            return true;                                            // Capture
   1.123 +
   1.124 +        // Forward incompletely handled key events
   1.125 +        return QTable::eventFilter(pObject, pEvent);
   1.126 +    }
   1.127 +    else // Default behaviour is to pass the event onwards
   1.128 +        return QTable::eventFilter(pObject, pEvent);
   1.129 +}
   1.130 +
   1.131 +// Overridden member hack to allow externally connected control
   1.132 +// widgets to influence dirty or clean state of table data
   1.133 +void TiTable::setText(int nRow, int nCol, const QString &nText)
   1.134 +{
   1.135 +    if (this->numRows() > 0) {
   1.136 +        // If a cell was edited, emit a signal indicating so
   1.137 +        // We can't rely on valueChanged for unknown reasons
   1.138 +        if (nText != this->text(nRow, nCol) && nCol != TITRAQ_IDXLINE)
   1.139 +            emit textEdited(nRow, nCol);
   1.140 +
   1.141 +        QTable::setText(nRow, nCol, nText);
   1.142 +    }
   1.143 +}
   1.144 +
   1.145 +// Overridden member hack to allow externally connected control
   1.146 +// widgets to influence dirty or clean state of table data
   1.147 +void TiTable::sortColumn(int nCol, bool bAscend, bool bWhole)
   1.148 +{
   1.149 +    // Guard against a repeat sort behaviour
   1.150 +    if (nCol == this->getSortcol() && bAscend == this->getSortdir())
   1.151 +        this->setSortdir(!bAscend);
   1.152 +    else
   1.153 +        this->setSortdir(bAscend);
   1.154 +
   1.155 +    this->setSortcol(nCol);
   1.156 +    QTable::sortColumn(nCol, this->getSortdir(), true);
   1.157 +
   1.158 +//    // Announce sorting policy with multiple selections
   1.159 +//    QTableSelection Testsel = this->selection(this->currentSelection());
   1.160 +//    if (Testsel.topRow() != Testsel.bottomRow())
   1.161 +//        m_pStatbar->message(trUtf8("Multiple selections dropped when sorting"), 4000);
   1.162 +
   1.163 +    // Move and display the selection highlight
   1.164 +    this->removeSelection(this->currentSelection());
   1.165 +    this->selectRow(this->currentRow());
   1.166 +    this->ensureCellVisible(this->currentRow(), 0);
   1.167 +
   1.168 +    // Write nonsaving line numbers for all rows
   1.169 +    for (int nIter = this->numRows() - 1; nIter >= 0; nIter--)
   1.170 +        this->setText(nIter, TITRAQ_IDXLINE, QString::number(nIter).rightJustify(4, QChar('0')));
   1.171 +}
   1.172 +
   1.173 +// Overriden member to render edge rows differently according to a sort key
   1.174 +void TiTable::paintCell(QPainter *pPainter, int nRow, int nCol, const QRect &Recto, bool bSelect, const QColorGroup &Colgroup)
   1.175 +{
   1.176 +    QColorGroup Cgroup(Colgroup);
   1.177 +    int nRed, nGreen, nBlue;
   1.178 +
   1.179 +    nRed = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTRED, TITRAQ_DEFLIGHTRED);
   1.180 +    nGreen = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTGREEN, TITRAQ_DEFLIGHTGREEN);
   1.181 +    nBlue = m_pTiprefs->getNumber(TITRAQ_PREFLIGHTBLUE, TITRAQ_DEFLIGHTBLUE);
   1.182 +    QColor Bright = QColor(nRed, nGreen, nBlue);
   1.183 +    nRed = m_pTiprefs->getNumber(TITRAQ_PREFDARKRED, TITRAQ_DEFDARKRED);
   1.184 +    nGreen = m_pTiprefs->getNumber(TITRAQ_PREFDARKGREEN, TITRAQ_DEFDARKGREEN);
   1.185 +    nBlue = m_pTiprefs->getNumber(TITRAQ_PREFDARKBLUE, TITRAQ_DEFDARKBLUE);
   1.186 +    QColor Dark = QColor(nRed, nGreen, nBlue);
   1.187 +
   1.188 +    // Alternate color for nonmatching sort keys
   1.189 +    QString Cur = this->text(nRow, this->getSortcol());
   1.190 +    QString Las = this->text(nRow - 1, this->getSortcol());
   1.191 +
   1.192 +    // A nice cascade of conditions providing a linewise base color test and set
   1.193 +    // The algorythm:
   1.194 +    //   1  Determine if the current row's index key differs from the former one
   1.195 +    //   2a If they are the same, then current row should have the same color
   1.196 +    //   2b If they are different, then current row should have an alt color
   1.197 +    //   3  Store information about which color we chose for the current row
   1.198 +    if (!Cur.isNull() && !Las.isNull() && Cur == Las) { // Set the base color conditionally
   1.199 +        if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
   1.200 +            Cgroup.setColor(QColorGroup::Base, Bright); // Bright
   1.201 +            if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
   1.202 +                this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
   1.203 +        }
   1.204 +        else {
   1.205 +            Cgroup.setColor(QColorGroup::Base, Dark);   // Dark
   1.206 +            if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK))
   1.207 +                this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK)));
   1.208 +        }
   1.209 +    }
   1.210 +    else {
   1.211 +        if (this->text(nRow - 1, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) == QChar(TITRAQ_BRIGHT)) {
   1.212 +            Cgroup.setColor(QColorGroup::Base, Dark);   // Dark
   1.213 +            if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_DARK))
   1.214 +                this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_DARK)));
   1.215 +        }
   1.216 +        else {
   1.217 +            Cgroup.setColor(QColorGroup::Base, Bright); // Bright
   1.218 +            if (this->text(nRow, TITRAQ_IDXSTATUS).at(TITRAQ_IDXSTATCOLOR) != QChar(TITRAQ_BRIGHT))
   1.219 +                this->setText(nRow, TITRAQ_IDXSTATUS, this->text(nRow, TITRAQ_IDXSTATUS).replace(TITRAQ_IDXSTATCOLOR, sizeof(char), QChar(TITRAQ_BRIGHT)));
   1.220 +        }
   1.221 +    }
   1.222 +
   1.223 +    QTable::paintCell(pPainter, nRow, nCol, Recto, bSelect, Cgroup);
   1.224 +};
   1.225 +
   1.226 +// Blah
   1.227 +void TiTable::activateNextCell(void)
   1.228 +{
   1.229 +    int nIter = 1; // Logic to skip invisible or read only columns
   1.230 +    while (columnWidth((currentColumn() + nIter) % TITRAQ_IDXTAIL) <= 0
   1.231 +        || isColumnReadOnly((currentColumn() + nIter) % TITRAQ_IDXTAIL))
   1.232 +        nIter++;
   1.233 +
   1.234 +    // Advance the column or both row and column possibly
   1.235 +    int nColadvance = ((currentColumn() + nIter) % TITRAQ_IDXTAIL);
   1.236 +    if ((currentColumn() + nIter) >= TITRAQ_IDXTAIL)
   1.237 +        this->setCurrentCell(currentRow() + 1, nColadvance);
   1.238 +    else
   1.239 +        this->setCurrentCell(currentRow(), nColadvance);
   1.240 +    this->setReadOnly(false);
   1.241 +    this->editCell(currentRow(), currentColumn());
   1.242 +    this->setEdition(currentColumn());
   1.243 +}
   1.244 +
   1.245 +// Overriden member to properly handle read only attribute after edition
   1.246 +void TiTable::endEdit(int nRow, int nCol, bool bAccept, bool bReplace)
   1.247 +{
   1.248 +    QTable::endEdit(nRow, nCol, bAccept, bReplace);
   1.249 +
   1.250 +    // Table read only attribute must be set to return to the normal
   1.251 +    // row highlight and selection behaviour of AS. The reason it was
   1.252 +    // reset in inplaceEdit() was to allow editing in the first place.
   1.253 +    this->setReadOnly(true);
   1.254 +}

mercurial