Mega Code Archive

 
Categories / C++ / Qt
 

Model view controller

/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights.  These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef VIEW_H #define VIEW_H #include <QAbstractItemView> #include <QItemSelection> #include <QItemSelectionModel> #include <QModelIndex> #include <QRect> #include <QSize> #include <QWidget> class LinearView : public QAbstractItemView {     Q_OBJECT public:     LinearView(QWidget *parent = 0);     QRect itemViewportRect(const QModelIndex &index) const;     void ensureVisible(const QModelIndex &index);     QModelIndex itemAt(int x, int y) const; protected slots:     /*void dataChanged(const QModelIndex &topLeft, const QModelIndex     &bottomRight);*/     void rowsInserted(const QModelIndex &parent, int start, int end);     void rowsRemoved(const QModelIndex &parent, int start, int end);     /*void selectionChanged(const QItemSelection &deselected, const QItemSelection &selected);     void verticalScrollbarAction(int action);     void horizontalScrollbarAction(int action);*/ protected:     void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command);     QRect selectionViewportRect(const QItemSelection &selection) const;     QRect itemRect(const QModelIndex &item) const;     bool isIndexHidden(const QModelIndex &index) const;     int horizontalOffset() const;     int verticalOffset() const;     QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,                            Qt::KeyboardModifiers modifiers);     void paintEvent(QPaintEvent *event);     void resizeEvent(QResizeEvent *event);     QSize sizeHint() const; private:     int rows(const QModelIndex &index = QModelIndex()) const;     void updateGeometries(); }; #endif /*!     view.cpp     Provides a view to represent a one-dimensional sequence of integers     obtained from a list model as a series of rows. */ #include <QAbstractItemModel> #include <QBrush> #include <QItemSelection> #include <QPainter> #include <QPaintEvent> #include <QPen> #include <QPoint> #include <QResizeEvent> #include <QScrollBar> #include <QSizePolicy> #include "view.h" LinearView::LinearView(QWidget *parent)     : QAbstractItemView(parent) {     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } /*!     Returns the position of the item in viewport coordinates. */ QRect LinearView::itemViewportRect(const QModelIndex &index) const {     QRect rect = itemRect(index);     QRect result(rect.left() - horizontalScrollBar()->value(),                  rect.top() - verticalScrollBar()->value(),                  rect.width(), viewport()->height());     return result; } /*!     Returns the rectangle of the item at position \a index in the     model. The rectangle is in contents coordinates. */ QRect LinearView::itemRect(const QModelIndex &index) const {     if (!index.isValid())         return QRect();     else         return QRect(index.row(), 0, 1, 1); } void LinearView::ensureVisible(const QModelIndex &index) {     QRect area = viewport()->rect();     QRect rect = itemViewportRect(index);     if (rect.left() < area.left())         horizontalScrollBar()->setValue(             horizontalScrollBar()->value() - rect.left());     else if (rect.right() > area.right())         horizontalScrollBar()->setValue(             horizontalScrollBar()->value() + rect.left() - area.width()); } /*!     Returns the item that covers the coordinate given in the view. */ QModelIndex LinearView::itemAt(int x, int /* y */) const {     int row = x + horizontalScrollBar()->value();     return model()->index(row, 0, QModelIndex()); } //void LinearView::dataChanged(const QModelIndex &/* topLeft */, //    const QModelIndex &/* bottomRight */) //{ //    updateGeometries(); //    if (isVisible()) //        repaint(); //} void LinearView::rowsInserted(const QModelIndex &/* parent */, int /* start */,     int /* end */) {     updateGeometries();     if (isVisible())         repaint(); } void LinearView::rowsRemoved(const QModelIndex &/* parent */, int /* start */,     int /* end */) {     updateGeometries();     if (isVisible())         repaint(); } /* void LinearView::verticalScrollbarAction(int action) { } void LinearView::horizontalScrollbarAction(int action) { } */ /*!     Select the items in the model that lie within the rectangle specified by     \a rect, using the selection \a command. */ void LinearView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) {     QModelIndex leftIndex = itemAt(rect.left(), 0);     QModelIndex rightIndex = itemAt(rect.right(), 0);     QItemSelection selection(leftIndex, rightIndex);     selectionModel()->select(selection, command); } QModelIndex LinearView::moveCursor(QAbstractItemView::CursorAction cursorAction,                                    Qt::KeyboardModifiers) {     QModelIndex current = currentIndex();     switch (cursorAction) {     case MoveLeft:{         if (current.row() > 0)             return model()->index(current.row() - 1, 0, QModelIndex());         else             return model()->index(0, 0, QModelIndex());         break;}     case MoveRight:{         if (current.row() < rows(current) - 1)             return model()->index(current.row() + 1, 0, QModelIndex());         else             return model()->index(rows(current) - 1, 0,QModelIndex());         break;}     case MoveUp:         return current;     case MoveDown:         return current;     case MovePageUp:         return current;     case MovePageDown:         return current;     case MoveHome:         return model()->index(0, 0, QModelIndex());     case MoveEnd:         return model()->index(rows(current) - 1, 0, QModelIndex());     default:         return current;     } } int LinearView::horizontalOffset() const {     return horizontalScrollBar()->value(); } int LinearView::verticalOffset() const {     return verticalScrollBar()->value(); } /*!     Returns a rectangle corresponding to the selection in viewport cooridinates. */ QRect LinearView::selectionViewportRect(const QItemSelection &selection) const {     int ranges = selection.count();     if (ranges == 0)         return QRect();     // Note that we use the top and bottom functions of the selection range     // since the data is stored in rows.     int firstRow = selection.at(0).top();     int lastRow = selection.at(0).top();     for (int i = 0; i < ranges; ++i) {         firstRow = qMin(firstRow, selection.at(i).top());         lastRow = qMax(lastRow, selection.at(i).bottom());     }     QModelIndex firstItem = model()->index(qMin(firstRow, lastRow), 0,         QModelIndex());     QModelIndex lastItem = model()->index(qMax(firstRow, lastRow), 0,         QModelIndex());     QRect firstRect = itemViewportRect(firstItem);     QRect lastRect = itemViewportRect(lastItem);     return QRect(firstRect.left(), firstRect.top(),         lastRect.right() - firstRect.left(), firstRect.height()); } void LinearView::paintEvent(QPaintEvent *event) {     QPainter painter(viewport());     QRect updateRect = event->rect();     QBrush background(Qt::black);     QPen foreground(Qt::white);     painter.fillRect(updateRect, background);     painter.setPen(foreground);     QModelIndex firstItem = itemAt(updateRect.left(), updateRect.top());     if (!firstItem.isValid())         firstItem = model()->index(0, 0, QModelIndex());     QModelIndex lastItem = itemAt(updateRect.right(), updateRect.bottom());     if (!lastItem.isValid())         lastItem = model()->index(rows() - 1, 0, QModelIndex());     int x = updateRect.left();     //int top = updateRect.top();     //int bottom = updateRect.bottom();     int row = firstItem.row();     QModelIndex index = model()->index(row, 0, QModelIndex());     int value = model()->data(index, Qt::DisplayRole).toInt();     int midPoint = viewport()->height()/2;     int y2 = midPoint - int(value * midPoint/255.0);     while (row <= lastItem.row()) {         QModelIndex index = model()->index(row, 0, QModelIndex());         int value = model()->data(index, Qt::DisplayRole).toInt();         int y1 = y2;         y2 = midPoint - int(value * midPoint/255.0);         painter.drawLine(x-1, y1, x, y2);         ++row; ++x;     } } void LinearView::resizeEvent(QResizeEvent * /* event */) {     updateGeometries(); } void LinearView::updateGeometries() {     if (viewport()->width() < rows()) {         horizontalScrollBar()->setPageStep(viewport()->width());         horizontalScrollBar()->setRange(0, rows() - viewport()->width() - 1);     } } QSize LinearView::sizeHint() const {     return QSize(rows(), 200); } int LinearView::rows(const QModelIndex &index) const {     return model()->rowCount(model()->parent(index)); } bool LinearView::isIndexHidden(const QModelIndex &index) const {     return false; } #ifndef MODEL_H #define MODEL_H #include <QAbstractListModel> #include <QObject> #include <qvector.h> class LinearModel : public QAbstractListModel {     Q_OBJECT public:     LinearModel(QObject *parent = 0)         : QAbstractListModel(parent) {}     int rowCount(const QModelIndex &parent = QModelIndex()) const;     QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;     QVariant data(const QModelIndex &index, int role) const;     Qt::ItemFlags flags(const QModelIndex &index) const;     bool setData(const QModelIndex &index, const QVariant &value,                  int role = Qt::EditRole);     bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());     bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); private:     QVector<int> values; }; #endif /*   model.cpp   A simple model that uses a QVector as its data source. */ #include "model.h" /*!     Returns the number of items in the string list as the number of rows     in the model. */ int LinearModel::rowCount(const QModelIndex &parent) const {     Q_USING(parent);     return values.count(); } /*     Returns an appropriate value for the requested data.     If the view requests an invalid index, an invalid variant is returned.     If a header is requested then we just return the column or row number,     depending on the orientation of the header.     Any valid index that corresponds to a string in the list causes that     string to be returned. */ /*!     Returns a model index for other component to use when referencing the     item specified by the given row, column, and type. The parent index     is ignored. */ QModelIndex LinearModel::index(int row, int column, const QModelIndex &parent) const {     if (parent == QModelIndex() && row >= 0 && row < rowCount()         && column == 0)         return createIndex(row, column, 0);     else         return QModelIndex(); } QVariant LinearModel::data(const QModelIndex &index, int role) const {     Q_UNUSED(role);     if (!index.isValid())         return QVariant();     return values.at(index.row()); } /*!     Returns Qt::ItemIsEditable so that all items in the vector can be edited. */ Qt::ItemFlags LinearModel::flags(const QModelIndex &index) const {     // all items in the model are editable     return QAbstractListModel::flags(index) | Qt::ItemIsEditable; } /*!     Changes an item in the string list, but only if the following conditions     are met:     * The index supplied is valid.     * The index corresponds to an item to be shown in a view.     * The role associated with editing text is specified.     The dataChanged() signal is emitted if the item is changed. */ bool LinearModel::setData(const QModelIndex &index,                           const QVariant &value, int role) {     if (!index.isValid() || role != Qt::EditRole)         return false;     values.replace(index.row(), value.toInt());     emit dataChanged(index, index);     return true; } /*!     Inserts a number of rows into the model at the specified position. */ bool LinearModel::insertRows(int position, int rows, const QModelIndex &parent) {     beginInsertRows(parent, position, position + rows - 1);     values.insert(position, rows, 0);     endInsertRows();     return true; } /*!     Removes a number of rows from the model at the specified position. */ bool LinearModel::removeRows(int position, int rows, const QModelIndex &parent) {     beginRemoveRows(QModelIndex(), position, position+rows-1);     values.remove(position, rows);     endRemoveRows();     return true; } #ifndef WINDOW_H #define WINDOW_H #include <QMainWindow> #include <QString> #include <QWidget> #include "model.h" #include "view.h" class MainWindow : public QMainWindow {     Q_OBJECT public:     MainWindow::MainWindow(QWidget *parent = 0); public slots:     void selectOpenFile(); private:     void setupModelView();     void openFile(const QString &fileName);     LinearModel *model;     LinearView *view; }; #endif #include <QAction> #include <QDataStream> #include <QMenu> #include <QMenuBar> #include <QFile> #include <QFileDialog> #include <QListView> #include "window.h" MainWindow::MainWindow(QWidget *parent)     : QMainWindow(parent) {     setWindowTitle("Model/View example");     setupModelView();     QAction *openAction = new QAction(tr("&Open"), this);     QAction *quitAction = new QAction(tr("E&xit"), this);     QMenu *fileMenu = new QMenu(tr("&File"), this);     fileMenu->addAction(openAction);     fileMenu->addAction(quitAction);     menuBar()->addMenu(fileMenu);     connect(openAction, SIGNAL(triggered()), this, SLOT(selectOpenFile()));     connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));     setCentralWidget(view); } void MainWindow::setupModelView() {     model = new LinearModel(this);     view = new LinearView(this);     view->setModel(model); } void MainWindow::selectOpenFile() {     QString fileName = QFileDialog::getOpenFileName(this,         tr("Select a file to open"), "", tr("Sound files (*.wav)"));          if (!fileName.isEmpty())         openFile(fileName); } void MainWindow::openFile(const QString &fileName) {     QFile file(fileName);     int length = file.size();     if (file.open(QFile::ReadOnly)) {         model->removeRows(0, model->rowCount());         int rows = (length - 0x2c)/2;         model->insertRows(0, rows);         // Perform some dodgy tricks to extract the data from the file.         QDataStream stream(&file);         stream.setByteOrder(QDataStream::LittleEndian);         Q_INT16 left;         Q_INT16 right;         for (int row = 0; row < rows; ++row) {             QModelIndex index = model->index(row);             stream >> left >> right;             model->setData(index, int(left / 256));         }     } } /*     main.cpp     An example of a main window application that used a subclassed model     and view to display data from sound files. */ #include <QApplication> #include "model.h" #include "view.h" #include "window.h" /*!     The main function for the linear model example. This creates and     populates a model with long integers then displays the contents of the     model using a QListView widget. */ int main(int argc, char *argv[]) {     QApplication app(argc, argv);     MainWindow *window = new MainWindow;     window->show();     return app.exec(); }