void CloudTableView::selectChanged(QModelIndexList lst) { m_selectedtems.clear(); foreach (QModelIndex idx, lst) { if (idx.column()!=0) lst.removeOne(idx); } foreach (QModelIndex idx, lst) { QString tmp = cs->fullPath + myProxyModel-> data(myProxyModel->index(idx.row(),0),Qt::DisplayRole).toString(); if (!tmp.contains("/..")) m_selectedtems << cs->fullPath + CTModel-> data(ConvertIndexToRealModel(myProxyModel->index(idx.row(),0)) ,Qt::DisplayRole).toString(); }
QItemSelectionModel::SelectionFlags AMActionHistoryTreeView3::selectionCommand(const QModelIndex &index, const QEvent *selectionEvent) const{ // Initialize by calling the parent version QItemSelectionModel::SelectionFlags retFlags = QTreeView::selectionCommand(index, selectionEvent); bool hasShiftModifier, hasControlModifier; // If we have a valid index we have a lot of work to do (also make sure this thing is actually an AMActionHistoryModel viewing tree) if(index.isValid()){ AMActionHistoryModel3 *historyModel = qobject_cast<AMActionHistoryModel3*>(model()); // We only care about the mouse button press events otherwise return the parent class call if( !historyModel || (selectionEvent->type() != QEvent::MouseButtonPress) ) return QTreeView::selectionCommand(index, selectionEvent); QMouseEvent *mouseEvent = (QMouseEvent*)selectionEvent; // Ignore clicks on non-selectable indices // We can ignore: not enabled indexes, and not selectable indexes if(!index.flags().testFlag(Qt::ItemIsEnabled) || !index.flags().testFlag(Qt::ItemIsSelectable)) return QTreeView::selectionCommand(index, selectionEvent); // Grab keyboard shift and control modifiers Qt::KeyboardModifiers currentModifiers = mouseEvent->modifiers(); hasControlModifier = currentModifiers&Qt::ControlModifier; hasShiftModifier = currentModifiers&Qt::ShiftModifier; ParentSelectMap selectMap = model()->data(index, AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>(); // This is pretty bad, you can tell too much is in here that doesn't belong when I need to do a const cast AMActionHistoryTreeView3 *checkViewer = const_cast<AMActionHistoryTreeView3*>(this); bool parentIsSelected = false; // Figure out if the parent is selected via the mapping or the selection model if(index.parent().isValid()){ ParentSelectMap parentsSelectMap = model()->data(index.parent(), AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>(); if(parentsSelectMap.contains(checkViewer)) parentIsSelected |= parentsSelectMap.value(checkViewer); parentIsSelected |= selectionModel()->isSelected(index.parent()); } // On control clicks where the parent is selected and this index is as well, do the group deselect and return noUpdate in the selection flags if(hasControlModifier && index.parent().isValid() && parentIsSelected && selectMap.contains(checkViewer) && selectMap.value(checkViewer)){ historyModel->markIndexGroupAsDeselected(index, checkViewer); return QItemSelectionModel::NoUpdate; } // On control clicks where the parent is selected and this index is not, do the group select and return noUpdate in the selection flags else if(hasControlModifier && index.parent().isValid() && parentIsSelected && selectMap.contains(checkViewer) && !selectMap.value(checkViewer)){ historyModel->markIndexGroupAsSelected(index, checkViewer); return QItemSelectionModel::NoUpdate; } // Ignore regular clicks on the an index that is already actually selected if it's the only one selected if( !hasControlModifier && (actuallySelectedByClickingCount_ == 1) && (selectionModel()->selectedIndexes().contains(index)) ){ return QItemSelectionModel::NoUpdate; } } // Log some flags ... might be an easier way now that I know how to use QFlag::testFlag() bool clearFlag = (retFlags&QItemSelectionModel::Clear); bool selectFlag = (retFlags&QItemSelectionModel::Select); bool deselectFlag = (retFlags&QItemSelectionModel::Deselect); bool toggleFlag = (retFlags&QItemSelectionModel::Toggle); bool indexAlreadyOn = selectionModel()->selectedIndexes().contains(index); bool noUpdateFlag = (retFlags&QItemSelectionModel::NoUpdate); // An actual selection! Selected OR (Toggled AND NOT Currently On) OR (noUpdate AND Currently On) bool selectedTrue = selectFlag || (toggleFlag && !indexAlreadyOn) || (noUpdateFlag && indexAlreadyOn); // An actual deselection! Deselected OR (Toggled AND Currently On) OR (noUpdate AND NOT Currently On) OR (Actually selected an invalid index) bool selectedFalse = deselectFlag || (toggleFlag && indexAlreadyOn) || (noUpdateFlag && !indexAlreadyOn) || (selectedTrue && !index.isValid()); // If we actually selected and the column is 0 (we only care about that one) log the state and emit actuallySelectedByClicking if(selectedTrue && (index.column() == 0) ){ lastClickWasDeselect_ = false; lastClickedIndex_ = index; emit actuallySelectedByClicking(index, clearFlag); } // If we actually deselected and the column is 0 (we only care about that one) log the state (particularily lastClickWasDeselect) and emit actuallyDeselectedByClicking else if(selectedFalse && (index.column() == 0) ){ QModelIndexList currentSelections = selectionModel()->selection().indexes(); if(currentSelections.count() == 2){ currentSelections.removeOne(index); lastClickedIndex_ = currentSelections.at(0); lastClickWasDeselect_ = false; } else lastClickWasDeselect_ = true; emit actuallyDeselectedByClicking(index, clearFlag); } // If neither selected nor deselected but clear flag is on then emit clearedByClicking else if(clearFlag){ lastClickWasDeselect_ = false; emit clearedByClicking(); } // Return the flags we have return retFlags; }
void AMActionHistoryTreeView3::mousePressEvent(QMouseEvent *event){ // Ignore mouse clicks if the cursor shows forbidden if(shiftKeyDown_ && hasOverriddenShiftCursor_){ event->ignore(); } // Actually handling valid shift-clicks else if(shiftKeyDown_){ AMActionHistoryModel3 *historyModel = qobject_cast<AMActionHistoryModel3*>(model()); QModelIndex index = indexAt(event->pos()); // We can ignore: bad models, invalid indexes, not enabled indexes, and not selectable indexes if(!historyModel || !index.isValid() || !index.flags().testFlag(Qt::ItemIsEnabled) || !index.flags().testFlag(Qt::ItemIsSelectable)) event->ignore(); // Grab current selection from model and the indices between the shift click QItemSelection currentSelection = selectionModel()->selection(); QItemSelection newSelection = historyModel->indicesBetween(index, lastClickedIndex_); // Call the selectionCommand function and merge the current and new selections QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); currentSelection.merge(newSelection, command); // Clear the selection and select the combined list selectionModel()->clearSelection(); selectionModel()->select(currentSelection, command); // Grab the list indices between the shift click so we can apply the right parentSelected states to them QModelIndexList interiorIndices = newSelection.indexes(); // We only care about lists that have interior elements, the indicesBetween call returns the ends as well if(interiorIndices.count() >= 2){ // Grab the clear flag for the signal emitted below bool clearFlag = command.testFlag(QItemSelectionModel::Clear); // Not sure if the indices are ordered correctly, so figure out the min and max to remove them (they should be the ends we don't care about) QModelIndex minRowIndex = interiorIndices.at(0); int minRowValue = minRowIndex.row(); QModelIndex maxRowIndex = interiorIndices.at(1); int maxRowValue = maxRowIndex.row(); for(int x = 0; x < interiorIndices.count(); x++){ if(interiorIndices.at(x).row() < minRowValue){ minRowIndex = interiorIndices.at(x); minRowValue = minRowIndex.row(); } if(interiorIndices.at(x).row() > maxRowValue){ maxRowIndex = interiorIndices.at(x); maxRowValue = maxRowIndex.row(); } } // Remove both ends interiorIndices.removeOne(maxRowIndex); interiorIndices.removeOne(minRowIndex); // For all interior indices emulate a click by emitting the actuallySelectedByClicking signal ... then the regular chain of events can happen to parentSelect the children for(int x = 0; x < interiorIndices.count(); x++) emit actuallySelectedByClicking(interiorIndices.at(x), clearFlag); } // Accept the event event->accept(); } // Ignore mouse clicks if the cursor shows forbidden else if(controlKeyDown_ && hasOverriddenControlCursor_){ event->ignore(); } // Falls through, call the parent class else QTreeView::mousePressEvent(event); }