C++ (Qt)bool SqlTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent){ if (action == Qt::IgnoreAction) return true; if (action != Qt::MoveAction) return false; if (!data->hasFormat("sqltreemodel/data.list")) return false; if (column > 0) return false; int beginRow; if (row != -1) beginRow = row; else if (parent.isValid()) beginRow = rowCount(parent); else beginRow = rowCount(index(0,0,QModelIndex())); TreeItem *item; QModelIndex ind; QByteArray encodedData = data->data("sqltreemodel/data.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList<int> moveIds; while (!stream.atEnd()) { int id; stream >> id; moveIds << id; } foreach (int id, moveIds) { item = search(rootItemData, id); ind = indexFromItemData(item); if(parent == QModelIndex()) moveItem(ind,index(0,0,QModelIndex()),beginRow); else moveItem(ind,parent,beginRow); beginRow++; } return true;}
C++ (Qt)void SqlTreeModel::moveItem(const QModelIndex& indexFrom, const QModelIndex& indexTo, int position){ TreeItem *newParent; TreeItem *item; newParent = itemDataFromIndex(indexTo); item = itemDataFromIndex(indexFrom); emit layoutAboutToBeChanged(); if(item->moveTo(position,newParent)) changePersistentIndex(index(position,0,indexTo),indexFrom); emit layoutChanged();}
C++ (Qt)bool TreeItem::moveTo(int position, TreeItem *newParent){ if (position < 0 || position > newParent->children.size()) return false; int num; num = childNumber(); parentItem->children.removeAt(num); parentItem = newParent; newParent->children.insert(position,this); return true;}
bool Tmodel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent){ .......... if(action == Qt::MoveAction && !success) { emit dropNotSuccess(); return false; }}
#pragma once#include <QAbstractItemModel>#include <QTreeView>#include <QKeyEvent>#include <QSqlRecord>#include "SqlTreeModel_BranchProxy.h"#include "DebugLog.h"class CSqlTreeModel : public QAbstractItemModel{ Q_OBJECTpublic: // Construction/destruction CSqlTreeModel(); ~CSqlTreeModel(); void setTableName( const QString& sVal ); // Object linkage void setRootID( int nRootID ); // Model hierarchy virtual QModelIndex index( int row, int column, const QModelIndex& parent ) const; virtual QModelIndex parent( const QModelIndex& index ) const; // Index enumeration virtual int rowCount( const QModelIndex& parent ) const; virtual int columnCount( const QModelIndex& parent ) const; // Data retrieval virtual QVariant data( const QModelIndex& index, int role ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; virtual bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex() ); virtual bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() ); // Data set virtual Qt::ItemFlags flags( const QModelIndex& index ) const; virtual bool setData( const QModelIndex& index, const QVariant& value, int role ); // Simple Helper Function QModelIndex addChild( const QModelIndex& index ); QModelIndex addSibling( const QModelIndex& index ); void delRow( const QModelIndex& index ); // Data proxy from index retrieval QModelIndex getIndex( CSqlTreeModel_BranchProxy * pData ) const; CSqlTreeModel_BranchProxy * getProxy( const QModelIndex& index ) const; CSqlTreeModel_BranchProxy * getProxyOrRoot( const QModelIndex& index ) const; QSqlQuery& select_Root_Q() { return m_qSelectRoot; } QSqlQuery& select_Child_Q() { return m_qSelectChild; } QSqlQuery& remove_Child_Q() { return m_qRemoveChild; } QSqlQuery& insert_Child_Q() { return m_qInsertChild; } QSqlQuery& update_Q() { return m_qUpdate; } QSqlQuery& gen_ROW_ID_Q() { return m_qGen_ROW_ID; } inline QHash<int, QString>& columnsHash() { return m_columnsHash;} virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } QStringList mimeTypes() const; QMimeData * mimeData(const QModelIndexList &indexes) const; virtual bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent);private: QSqlQuery m_qSelectRoot; QSqlQuery m_qSelectChild; QSqlQuery m_qRemoveChild; QSqlQuery m_qInsertChild; QSqlQuery m_qChangeParent; QSqlQuery m_qUpdate; QSqlQuery m_qGen_ROW_ID; mutable CSqlTreeModel_BranchProxy m_Root; QHash<int, QString> m_columnsHash;};class CSqlTreeView_EventFilter : public QObject{ CSqlTreeModel * m_pSqlTreeModel = 0; QTreeView * m_pView = 0;public: CSqlTreeView_EventFilter( QObject * parent = 0 ) : QObject (parent) { m_pView = qobject_cast<QTreeView*>( parent ); m_pSqlTreeModel = qobject_cast<CSqlTreeModel*>( m_pView->model() ); }protected: bool eventFilter( QObject * obj, QEvent *event ) { if (event->type() == QEvent::KeyPress) { switch ( event->type() ) { case QEvent::KeyPress: case QEvent::KeyRelease: { QKeyEvent * keyEvent = static_cast<QKeyEvent *>( event ); switch ( keyEvent->key() ) { case ( Qt::Key_Insert ): { QModelIndex index = m_pView->selectionModel()->currentIndex(); QModelIndex newIndex; if ( index.isValid() ) { if ( keyEvent->modifiers() & Qt::ShiftModifier ) { m_pView->expand( index ); newIndex = m_pSqlTreeModel->addChild( index ); } else { newIndex = m_pSqlTreeModel->addSibling( index ); } }; if ( newIndex.isValid() ) m_pView->selectionModel()->setCurrentIndex( newIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); return true; }; case ( Qt::Key_Delete ): { QModelIndex index = m_pView->selectionModel()->currentIndex(); if ( index.isValid() ) { m_pView->expand( index ); m_pSqlTreeModel->delRow( index ); } return true; }; default:; }; }; default:; } }; return QObject::eventFilter(obj, event); }};
#include "SqlTreeModel.h"#include <QDebug>#include <QFont>#include <QBrush>#include <QMimeData>#include <QSqlError>#include "SqlUtils.h"#define ROW_ID_LIST_MIME_TYPE "application/row_id.list"CSqlTreeModel::CSqlTreeModel() :m_Root(this){ m_columnsHash.insert( 0, "TITLE" ); m_columnsHash.insert( 1, "CHILD_COUNT" ); m_columnsHash.insert( 2, ROW_ID_FIELD_NAME );}CSqlTreeModel::~CSqlTreeModel(){}void CSqlTreeModel::setTableName( const QString& sVal ){ m_qSelectRoot.prepare( "SELECT a.ROW_ID, a.TITLE, a.PARENT_ID, ( select count(*) from " + sVal + " b where b.PARENT_ID = :PARENT_ID ) CHILD_COUNT " "FROM " + sVal + " a WHERE a.ROW_ID = :PARENT_ID" ); m_qSelectChild.prepare( "select p.ROW_ID, p.TITLE, p.PARENT_ID, (select count(*) from " + sVal + " fp where fp.PARENT_ID = p.ROW_ID ) CHILD_COUNT " "from " + sVal + " p where PARENT_ID = :PARENT_ID " "order by p.TITLE"); m_qRemoveChild.prepare( "delete from " + sVal + " where ROW_ID = :ROW_ID"); m_qInsertChild.prepare( "insert into " + sVal + "(ROW_ID, TITLE, PARENT_ID) values(:ROW_ID, :TITLE, :PARENT_ID)"); m_qChangeParent.prepare( "update " + sVal + " set PARENT_ID = :PARENT_ID where ROW_ID = :ROW_ID" ); m_qUpdate.prepare( "update " + sVal + " p set p.TITLE = :TITLE where p.ROW_ID = :ROW_ID" ); m_qGen_ROW_ID.prepare( "select gen_id( GEN_" + sVal + "_ID, 1 ) from RDB$DATABASE" );}void CSqlTreeModel::setRootID(int nRootID ){ m_Root.setID( nRootID );}QModelIndex CSqlTreeModel::index( int row, int column, const QModelIndex& parent ) const{ if( !hasIndex( row, column, parent ) ) return QModelIndex(); CSqlTreeModel_BranchProxy * pParent = getProxyOrRoot( parent ); CSqlTreeModel_BranchProxy * pChild = pParent->child(row); if( pChild ) return createIndex( row, column, pChild ); else return QModelIndex();}QModelIndex CSqlTreeModel::parent( const QModelIndex& index ) const{ if( !index.isValid() ) return QModelIndex(); CSqlTreeModel_BranchProxy * pProxy = getProxy( index ); if( !pProxy ) return QModelIndex(); CSqlTreeModel_BranchProxy * pParent = pProxy->parent(); if( !pParent ) return QModelIndex(); return getIndex( pParent );}int CSqlTreeModel::rowCount( const QModelIndex& parent ) const{ return getProxyOrRoot( parent )->childrenCount();}int CSqlTreeModel::columnCount( const QModelIndex& parent ) const{ int nCount = m_columnsHash.count(); return nCount > 0 ? nCount : 4;}QVariant CSqlTreeModel::data( const QModelIndex& index, int role ) const{ if( !index.isValid() ) return QVariant(); CSqlTreeModel_BranchProxy * pProxy = getProxy( index ); switch( role ) {// case Qt::CheckStateRole:// {// if ( index.column() == 0 )// if ( getProxy( index )->childrenCount() == 0 )// return Qt::PartiallyChecked;// break;// } case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: { switch( index.column() ) { case 0: return pProxy->title(); case 1: return pProxy->childrenCount(); case 2: return pProxy->rowID(); default: return QVariant(); } }// case Qt::FontRole:// {// QFont font;// font.setItalic( pProxy->isPrivate() );// font.setBold( !pProxy->isStatic() );// return font;// }// case Qt::ForegroundRole:// {// if( pProxy->isStatic() )// return QBrush( Qt::black );// else// return QBrush( Qt::darkRed );// } default: return QVariant(); } return QVariant();}QVariant CSqlTreeModel::headerData( int section, Qt::Orientation orientation, int role ) const{ if( orientation != Qt::Horizontal ) return QVariant(); switch( role ) { case Qt::DisplayRole: { if ( m_columnsHash.contains( section ) ) return m_columnsHash.value( section ); else return QVariant(); break; } default: return QVariant(); }}bool CSqlTreeModel::insertRows(int row, int count, const QModelIndex & parent ){ CSqlTreeModel_BranchProxy * pParent = getProxyOrRoot( parent ); beginInsertRows( parent, row, row + (count-1) ); bool b = true; for ( int i=0; i < count; ++i ) b = b && pParent->insertChild( row + i ); endInsertRows(); //emit layoutChanged(); emit dataChanged( parent, parent ); return b;}bool CSqlTreeModel::removeRows ( int row, int count, const QModelIndex & parent ){ qDebug() << "111"; CSqlTreeModel_BranchProxy * pParent = getProxyOrRoot( parent ); beginRemoveRows( parent, row, row + (count-1) ); bool b = true; for ( int i=0; i < count; ++i ) b = b && pParent->removeChild( row + i ); endRemoveRows(); emit dataChanged( parent, parent ); return b;}Qt::ItemFlags CSqlTreeModel::flags( const QModelIndex& index ) const{ if( !index.isValid() ) return 0; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;// CModelObjDataProxy * pProxy = getProxy( index );// OldBaseType nType = pProxy->type(); bool bEditable = index.column() == 0;// if( bEditable )// bEditable &=// ( ( nType != btObject ) &&// ( nType != btUndefined ) &&// ( nType != btQByteArray ) ); if( bEditable ) flags |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; return flags;}bool CSqlTreeModel::setData( const QModelIndex& index, const QVariant& value, int role ){ if( !index.isValid() ) return false; if( role != Qt::EditRole ) return false; if ( index.column() != 0 ) return false; CSqlTreeModel_BranchProxy * pProxy = getProxy( index ); pProxy->setTitle( value.toString() ); emit dataChanged( index, index ); return true;}QModelIndex CSqlTreeModel::addChild( const QModelIndex& index ){ CSqlTreeModel_BranchProxy * pProxy = getProxy( index ); int nRow = pProxy->childrenCount(); bool b = insertRow( nRow, index ); return b ? getIndex( pProxy->child( nRow ) ) : QModelIndex();}QModelIndex CSqlTreeModel::addSibling( const QModelIndex& index ){ int nRow = index.row() + 1; QModelIndex parent = index.parent(); bool b = insertRow( nRow, parent ); return b ? getIndex( getProxyOrRoot( parent )->child( nRow ) ) : QModelIndex();}void CSqlTreeModel::delRow( const QModelIndex& index ){ removeRow( index.row(), index.parent() );}QModelIndex CSqlTreeModel::getIndex( CSqlTreeModel_BranchProxy * pData ) const{ if( pData == &m_Root ) return QModelIndex(); return createIndex( pData->row(), 0, pData );}CSqlTreeModel_BranchProxy *CSqlTreeModel::getProxy( const QModelIndex& index ) const{ return static_cast<CSqlTreeModel_BranchProxy*>( index.internalPointer() );}CSqlTreeModel_BranchProxy * CSqlTreeModel::getProxyOrRoot( const QModelIndex& index ) const{ return index.isValid() ? static_cast<CSqlTreeModel_BranchProxy*>( index.internalPointer() ) : &m_Root;}QStringList CSqlTreeModel::mimeTypes() const{ QStringList types; types << ROW_ID_LIST_MIME_TYPE; return types;}QMimeData *CSqlTreeModel::mimeData(const QModelIndexList &indexes) const{ QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (const QModelIndex &index, indexes) { if (index.isValid()) { CSqlTreeModel_BranchProxy * pProxy = getProxy( index ); //QString text = data(index, Qt::DisplayRole).toString(); stream << pProxy->rowID(); } } mimeData->setData( ROW_ID_LIST_MIME_TYPE, encodedData); return mimeData;}bool CSqlTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent){ if ( action != Qt::MoveAction ) return false; if ( !parent.isValid() ) return false; CSqlTreeModel_BranchProxy * pNewParent_Proxy = getProxy( parent ); QByteArray encodedData = data->data( ROW_ID_LIST_MIME_TYPE ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList<int> listROW_ID; while (!stream.atEnd()) { QString text; int nROW_ID; stream >> nROW_ID; listROW_ID << nROW_ID; } bool b = true; foreach( int nROW_ID, listROW_ID ) { m_qChangeParent.bindValue( ":PARENT_ID", pNewParent_Proxy->rowID() ); m_qChangeParent.bindValue( ":ROW_ID", nROW_ID ); m_qChangeParent.exec(); if ( m_qChangeParent.lastError().type() != QSqlError::NoError ) { qCritical() << m_qChangeParent.lastError().text(); b = b && false; continue; }; }// QByteArray encoded = data->data( mimeTypes().at(0) );// QDataStream stream(&encoded, QIODevice::ReadOnly); //qDebug() << listROW_ID; return true;}