Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/widget/wtracktableviewheader.cpp

Go to the documentation of this file.
00001 // wtracktableviewheader.cpp
00002 // Created 1/2/2010 by RJ Ryan (rryan@mit.edu)
00003 
00004 #include <QtDebug>
00005 
00006 #include "widget/wtracktableviewheader.h"
00007 #include "library/trackmodel.h"
00008 
00009 #define WTTVH_MINIMUM_SECTION_SIZE 20
00010 
00011 WTrackTableViewHeader::WTrackTableViewHeader(Qt::Orientation orientation,
00012                                              QWidget* parent)
00013         : QHeaderView(orientation, parent),
00014           m_menu(tr("Show or hide columns."), this),
00015           m_signalMapper(this) {
00016     connect(&m_signalMapper, SIGNAL(mapped(int)),
00017             this, SLOT(showOrHideColumn(int)));
00018 }
00019 
00020 WTrackTableViewHeader::~WTrackTableViewHeader() {
00021 }
00022 
00023 void WTrackTableViewHeader::contextMenuEvent(QContextMenuEvent* event) {
00024     m_menu.popup(event->globalPos());
00025 }
00026 
00027 void WTrackTableViewHeader::setModel(QAbstractItemModel* model) {
00028     TrackModel* oldTrackModel = getTrackModel();
00029 
00030     if (dynamic_cast<QAbstractItemModel*>(oldTrackModel) == model) {
00031         // If the models are the same, do nothing but the redundant call.
00032         QHeaderView::setModel(model);
00033         return;
00034     }
00035 
00036     // Won't happen in practice since the WTrackTableView new's a new
00037     // WTrackTableViewHeader each time a new TrackModel is loaded.
00038     // if (oldTrackModel) {
00039     //     saveHeaderState();
00040     // }
00041 
00042     // First clear all the context menu actions for the old model.
00043     clearActions();
00044 
00045     // Now set the header view to show the new model
00046     QHeaderView::setModel(model);
00047 
00048     // Now build actions for the new TrackModel
00049     TrackModel* trackModel = dynamic_cast<TrackModel*>(model);
00050 
00051     if (!trackModel) {
00052         return;
00053     }
00054 
00055     // Restore saved header state to get sizes, column positioning, etc. back.
00056     restoreHeaderState();
00057 
00058     // Here we can override values to prevent restoring corrupt values from database
00059     setMovable(true);
00060     setCascadingSectionResizes(true);
00061     setMinimumSectionSize(WTTVH_MINIMUM_SECTION_SIZE);
00062 
00063     int columns = model->columnCount();
00064     for (int i = 0; i < columns; ++i) {
00065         if (trackModel->isColumnInternal(i)) {
00066             continue;
00067         }
00068 
00069         QString title = model->headerData(i, orientation()).toString();
00070         QAction* action = new QAction(title, &m_menu);
00071         action->setCheckable(true);
00072 
00073         /* If Mixxx starts the first time or the header states have been cleared
00074          * due to database schema evolution we gonna hide all columns that may
00075          * contain a potential large number of NULL values.  Here we uncheck
00076          * item in the context menu that are hidden by defualt (e.g., key
00077          * column)
00078          */
00079         if (!hasPersistedHeaderState() &&
00080             trackModel->isColumnHiddenByDefault(i)) {
00081             action->setChecked(false);
00082         } else {
00083             action->setChecked(!isSectionHidden(i));
00084         }
00085 
00086         // Map this action's signals via our QSignalMapper
00087         m_signalMapper.setMapping(action, i);
00088         m_columnActions.insert(i, action);
00089         connect(action, SIGNAL(triggered()),
00090                 &m_signalMapper, SLOT(map()));
00091         m_menu.addAction(action);
00092 
00093         // force the section size to be a least WTTVH_MINIMUM_SECTION_SIZE
00094         if (sectionSize(i) <  WTTVH_MINIMUM_SECTION_SIZE) {
00095             // This might happen if  WTTVH_MINIMUM_SECTION_SIZ has changed or
00096             // the header state from database was corrupt
00097             resizeSection(i,WTTVH_MINIMUM_SECTION_SIZE);
00098         }
00099     }
00100 
00101     // Safety check against someone getting stuck with all columns hidden
00102     // (produces an empty library table). Just re-show them all.
00103     if (hiddenCount() == columns) {
00104         for (int i = 0; i < columns; ++i) {
00105             showSection(i);
00106         }
00107     }
00108 }
00109 
00110 void WTrackTableViewHeader::saveHeaderState() {
00111     TrackModel* track_model = getTrackModel();
00112     if (!track_model) {
00113         return;
00114     }
00115     // Convert the QByteArray to a Base64 string and save it.
00116     QString headerState = QString(saveState().toBase64());
00117     bool result = track_model->setModelSetting("header_state", headerState);
00118     //qDebug() << "Saving old header state:" << result << headerState;
00119 }
00120 
00121 void WTrackTableViewHeader::restoreHeaderState() {
00122     TrackModel* track_model = getTrackModel();
00123 
00124     if (!track_model) {
00125         return;
00126     }
00127 
00128     QString headerStateString = track_model->getModelSetting("header_state");
00129     if (!headerStateString.isNull()) {
00130         // Load the previous header state (stored as a Base 64 string). Decode
00131         // it and restore it.
00132         //qDebug() << "Restoring header state" << headerStateString;
00133         QByteArray headerState = headerStateString.toAscii();
00134         headerState = QByteArray::fromBase64(headerState);
00135         restoreState(headerState);
00136     }
00137 }
00138 
00139 bool WTrackTableViewHeader::hasPersistedHeaderState() {
00140     TrackModel* track_model = getTrackModel();
00141     if (!track_model) {
00142         return false;
00143     }
00144     QString headerStateString = track_model->getModelSetting("header_state");
00145 
00146     if (!headerStateString.isNull()) return true;
00147     return false;
00148 
00149 }
00150 void WTrackTableViewHeader::clearActions() {
00151     // The QActions are parented to the menu, so clearing deletes them. Since
00152     // they are deleted we don't have to disconnect their signals from the
00153     // mapper.
00154     m_columnActions.clear();
00155     m_menu.clear();
00156 }
00157 
00158 void WTrackTableViewHeader::showOrHideColumn(int column) {
00159     if (!m_columnActions.contains(column)) {
00160         qDebug() << "WTrackTableViewHeader got invalid column" << column;
00161         return;
00162     }
00163 
00164     QAction* action = m_columnActions[column];
00165     if (action->isChecked()) {
00166         showSection(column);
00167     } else {
00168         // If the user hides every column then the table will disappear. This
00169         // guards against that. NB: hiddenCount reflects checked QAction's so
00170         // size-hiddenCount will be zero the moment they uncheck the last
00171         // section.
00172         if (m_columnActions.size() - hiddenCount() > 0) {
00173             hideSection(column);
00174         } else {
00175             // Otherwise, ignore the request and re-check this QAction.
00176             action->setChecked(true);
00177         }
00178     }
00179 }
00180 
00181 int WTrackTableViewHeader::hiddenCount() {
00182     int count = 0;
00183     for (QMap<int, QAction*>::iterator it = m_columnActions.begin();
00184          it != m_columnActions.end(); it++) {
00185         QAction* pAction = *it;
00186         if (!pAction->isChecked())
00187             count += 1;
00188     }
00189     return count;
00190 }
00191 
00192 TrackModel* WTrackTableViewHeader::getTrackModel() {
00193     TrackModel* trackModel = dynamic_cast<TrackModel*>(model());
00194     return trackModel;
00195 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines