Sandboxie/SandboxiePlus/MiscHelpers/Common/TreeViewEx.h

350 lines
8.6 KiB
C++

#pragma once
#include <QStyledItemDelegate>
__inline uint qHash( const QVariant & var )
{
if ( !var.isValid() /*|| var.isNull()*/ )
//return -1;
Q_ASSERT(0);
switch ( var.type() )
{
case QVariant::Int:
return qHash( var.toInt() );
break;
case QVariant::UInt:
return qHash( var.toUInt() );
break;
case QVariant::Bool:
return qHash( var.toUInt() );
break;
case QVariant::Double:
return qHash( var.toUInt() );
break;
case QVariant::LongLong:
return qHash( var.toLongLong() );
break;
case QVariant::ULongLong:
return qHash( var.toULongLong() );
break;
case QVariant::String:
return qHash( var.toString() );
break;
case QVariant::Char:
return qHash( var.toChar() );
break;
case QVariant::StringList:
return qHash( var.toString() );
break;
case QVariant::ByteArray:
return qHash( var.toByteArray() );
break;
case QVariant::Date:
case QVariant::Time:
case QVariant::DateTime:
case QVariant::Url:
case QVariant::Locale:
//case QVariant::RegExp:
// return qHash( var.toString() );
break;
case QVariant::Map:
case QVariant::List:
case QVariant::BitArray:
case QVariant::Size:
case QVariant::SizeF:
case QVariant::Rect:
case QVariant::LineF:
case QVariant::Line:
case QVariant::RectF:
case QVariant::Point:
case QVariant::PointF:
// not supported yet
break;
case QVariant::UserType:
case QVariant::Invalid:
default:
return -1;
}
// could not generate a hash for the given variant
return -1;
}
#include "../mischelpers_global.h"
class MISCHELPERS_EXPORT QAbstractItemModelEx : public QAbstractItemModel
{
Q_OBJECT
public:
QAbstractItemModelEx(QObject *parent = 0) : QAbstractItemModel(parent) {}
virtual ~QAbstractItemModelEx() {}
bool IsColumnEnabled(int column)
{
return !m_ColumnsOff.contains(column);
}
void SetColumnEnabled(int column, bool set)
{
if (!set)
m_ColumnsOff.insert(column);
else
m_ColumnsOff.remove(column);
}
protected:
QSet<int> m_ColumnsOff;
};
class MISCHELPERS_EXPORT QTreeViewEx: public QTreeView
{
Q_OBJECT
public:
QTreeViewEx(QWidget *parent = 0) : QTreeView(parent)
{
setUniformRowHeights(true);
m_ColumnReset = 1;
header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header(), SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenuRequested(const QPoint &)));
m_pMenu = new QMenu(this);
}
void setColumnReset(int iMode)
{
m_ColumnReset = iMode;
}
void setColumnFixed(int column, bool fixed)
{
if (fixed)
m_FixedColumns.insert(column);
else
m_FixedColumns.remove(column);
}
bool isColumnFixed(int column) const
{
return m_FixedColumns.contains(column);
}
QModelIndexList selectedRows() const
{
int Column = 0;
QAbstractItemModel* pModel = model();
for (int i = 0; i < pModel->columnCount(); i++)
{
if (!isColumnHidden(i))
{
Column = i;
break;
}
}
QModelIndexList IndexList;
foreach(const QModelIndex& Index, selectedIndexes())
{
if (Index.column() == Column)
IndexList.append(Index);
}
return IndexList;
}
template<class T>
void StartUpdatingWidgets(T& OldMap, T& Map)
{
for(typename T::iterator I = Map.begin(); I != Map.end();)
{
if(I.value().first == NULL)
I = Map.erase(I);
else
{
OldMap.insert(I.key(), I.value());
I++;
}
}
}
template<class T>
void EndUpdatingWidgets(T& OldMap, T& Map)
{
for(typename T::iterator I = OldMap.begin(); I != OldMap.end(); I++)
{
Map.remove(I.key());
if(I.value().second.isValid())
setIndexWidget(I.value().second, NULL);
}
}
bool restoreState(const QByteArray &state)
{
bool bRet = header()->restoreState(state);
SyncColumnsWithModel();
return bRet;
}
QByteArray saveState() const
{
return header()->saveState();
}
QAbstractItemModelEx* modelEx() const
{
QAbstractItemModelEx* pModel = qobject_cast<QAbstractItemModelEx*>(model());
if (!pModel)
{
QSortFilterProxyModel* pProxyModel = qobject_cast<QSortFilterProxyModel*>(model());
if(pProxyModel)
pModel = qobject_cast<QAbstractItemModelEx*>(pProxyModel->sourceModel());
}
return pModel;
}
void SetColumnHidden(int column, bool hide, bool fixed = false)
{
if (!fixed && isColumnFixed(column))
return; // can not change fixed columns
setColumnHidden(column, hide);
if(QAbstractItemModelEx* pModel = modelEx())
pModel->SetColumnEnabled(column, !hide);
if (fixed)
setColumnFixed(column, true);
emit ColumnChanged(column, !hide);
}
static QString m_ResetColumns;
signals:
void ColumnChanged(int column, bool visible);
void ResetColumns();
public slots:
void SyncColumnsWithModel()
{
if(QAbstractItemModelEx* pModel = modelEx())
{
for (int i = 0; i < pModel->columnCount(); i++)
pModel->SetColumnEnabled(i, !isColumnHidden(i));
}
}
void OnResetColumns()
{
QAbstractItemModel* pModel = model();
for (int i = 0; i < pModel->columnCount(); i++) {
SetColumnHidden(i, false);
QTreeView::resizeColumnToContents(i);
}
}
private slots:
void OnMenuRequested(const QPoint &point)
{
QAbstractItemModel* pModel = model();
if(m_pMenu->actions().isEmpty())
{
for(int i=0; i < pModel->columnCount(); i++)
{
QString Label = pModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
if(Label.isEmpty() || m_FixedColumns.contains(i))
continue;
QAction* pAction = new QAction(Label, m_pMenu);
pAction->setCheckable(true);
pAction->setChecked(!isColumnHidden(i));
connect(pAction, SIGNAL(triggered()), this, SLOT(OnMenu()));
m_pMenu->addAction(pAction);
m_Columns[pAction] = i;
}
if (m_ColumnReset)
{
m_pMenu->addSeparator();
QAction* pAction = m_pMenu->addAction(m_ResetColumns);
if(m_ColumnReset == 1)
connect(pAction, SIGNAL(triggered()), this, SLOT(OnResetColumns()));
else
connect(pAction, SIGNAL(triggered()), this, SIGNAL(ResetColumns()));
}
}
for(QMap<QAction*, int>::iterator I = m_Columns.begin(); I != m_Columns.end(); I++)
I.key()->setChecked(!isColumnHidden(I.value()));
m_pMenu->popup(QCursor::pos());
}
void OnMenu()
{
QAction* pAction = (QAction*)sender();
int Column = m_Columns.value(pAction, -1);
SetColumnHidden(Column, !pAction->isChecked());
}
protected:
QMenu* m_pMenu;
QMap<QAction*, int> m_Columns;
QSet<int> m_FixedColumns;
int m_ColumnReset;
};
class MISCHELPERS_EXPORT QStyledItemDelegateMaxH : public QStyledItemDelegate
{
Q_OBJECT
public:
QStyledItemDelegateMaxH(int MaxHeight, QObject *parent = 0)
: QStyledItemDelegate(parent) {m_MaxHeight = MaxHeight;}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(m_MaxHeight);
return size;
}
int m_MaxHeight;
};
class MISCHELPERS_EXPORT CStyledGridItemDelegate : public QStyledItemDelegateMaxH
{
public:
explicit CStyledGridItemDelegate(int MaxHeight, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, false, parent) { }
explicit CStyledGridItemDelegate(int MaxHeight, QColor Color, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, Color, false, parent) { }
explicit CStyledGridItemDelegate(int MaxHeight, bool Tree, QObject * parent = 0) : CStyledGridItemDelegate(MaxHeight, QColor(Qt::darkGray), false, parent) { }
explicit CStyledGridItemDelegate(int MaxHeight, QColor Color, bool Tree, QObject * parent = 0) : QStyledItemDelegateMaxH(MaxHeight, parent) {
m_Color = Color;
m_Tree = Tree;
m_Grid = true;
}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QStyledItemDelegate::paint(painter, option, index);
if (m_Grid)
{
painter->save();
painter->setPen(m_Color);
//painter->drawRect(option.rect);
//painter->drawLine(option.rect.left(), option.rect.top(), option.rect.right(), option.rect.top());
painter->drawLine(option.rect.right(), option.rect.top(), option.rect.right(), option.rect.bottom());
painter->drawLine(option.rect.left() + (m_Tree && index.column() == 0 ? 24 : 0), option.rect.bottom(), option.rect.right(), option.rect.bottom());
painter->restore();
}
}
bool m_Grid;
bool m_Tree;
QColor m_Color;
};