Beispiel #1
0
void AMActionHistoryTreeView3::onEnteredIndex(const QModelIndex &index){
	AMActionHistoryModel3 *historyModel = qobject_cast<AMActionHistoryModel3*>(model());
	if(!historyModel)
		return;
	if(shiftKeyDown_){
		// If shift key is down and we don't already have the forbidden cursor and we're hovering over an item that is not a sibling then we can't shift click ... go forbidden
		if(!hasOverriddenShiftCursor_ && (index.parent() != lastClickedIndex_.parent()) ){
			hasOverriddenShiftCursor_ = true;
			setCursor(*forbiddenCursor_);
		}
		// Or if the shift key is down and we already have the forbidden cursor and we're hovering over an item that is a sibling then we can shift click ... go default
		// Also check lastClickWasDeselect ... we can never shift click if that sucker is on
		else if(hasOverriddenShiftCursor_ && (index.parent() == lastClickedIndex_.parent() && !lastClickWasDeselect_) ){
			hasOverriddenShiftCursor_ = false;
			setCursor(*regularCursor_);
		}
	}
	if(controlKeyDown_){
		ParentSelectMap selectMap = model()->data(index, AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>();
		// If control key is down and we have overridden the cursor ... go default
		if(hasOverriddenControlCursor_){
			hasOverriddenControlCursor_ = false;
			setCursor(*regularCursor_);
		}
		// If control key is down and we don't already have the forbidden cursor and this viewer is in the selection map and this index isn't parentSelected
		//  and we have a parent somewhere selected and our direct parent isn't selected one way or the other ... go forbidden
		// Just trying to make sure that you if you have three levels (A parents B, B parents C) if A or above is selected but B is not then you can't control-click in C or below ... what would that mean anyway
		if(!hasOverriddenControlCursor_ && selectMap.contains(this) && !selectMap.value(this) && hasSelectedParent(index) && !(selectionModel()->isSelected(index.parent()) || model()->data(index.parent(), AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>().value(this)) ){
			hasOverriddenControlCursor_ = true;
			setCursor(*forbiddenCursor_);
		}
	}
}
void AMActionHistoryModel3::markIndexGroup(const QModelIndex &index, QAbstractItemView *viewer, bool selected){
	// Just do the regular markParentSelected if this is a top-level action log item (parent index is invalid)
	if(!index.parent().isValid()){
		recurseMarkParentSelected(index, viewer, selected);
		return;
	}

	// Check if the action log item inherited the loop action (if so, then we need to multi-select/deselect the children)
	AMActionLogItem3 *item = logItem(index.parent());
	if(item->actionInheritedLoop()){
		// Figure out your index in the original loop, and select/deselect all of your siblings with the same loop index
		int actionsPerLoop = rowCount(index.parent())/item->numberOfLoops();
		int indexInLoop = (index.row()%actionsPerLoop);
		QModelIndex markingIndex;
		for(int x = 0; x < rowCount(index.parent()); x++){
			if(x%actionsPerLoop == indexInLoop){
				markingIndex = this->index(x, 0, index.parent());
				recurseMarkParentSelected(markingIndex, viewer, selected);
				emit dataChanged(markingIndex, markingIndex);
			}
		}
	}
	else
		recurseMarkParentSelected(index, viewer, selected);

	// Check to see if there are any children left at this level. If not, then deselect the parent as well (no point selecting a list or loop when the user has removed all of the contents)
	int siblingsSelected = 0;
	for(int x = 0; x < rowCount(index.parent()); x++){
		ParentSelectMap selectMap = data(this->index(x, 0, index.parent()), AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>();
		if(selectMap.contains(viewer) && selectMap.value(viewer))
			siblingsSelected++;
	}

	if(siblingsSelected == 0){
		// Actually deselect in the selection model if the parent was actually selected
		if(viewer->selectionModel()->isSelected(index.parent())){
			QItemSelectionModel::SelectionFlags deselectFlag = QItemSelectionModel::Deselect;
			viewer->selectionModel()->select(index.parent(), deselectFlag);
			ParentSelectMap selectMap = data(index.parent(), AMActionHistoryModel3::ParentSelectRole).value<ParentSelectMap>();
			if(selectMap.contains(viewer)){
				AMActionLogItem3 *item = logItem(index.parent());
				// Make sure it doesn't get parentSelected somehow
				item->setParentSelected(viewer, false);
			}
			emit dataChanged(index.parent(), index.parent());
		}
		// Otherwise just use the group deselect for the parentSelected mapping
		else
			markIndexGroupAsDeselected(index.parent(), viewer);
	}
}
Beispiel #3
0
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;
}
QVariant AMActionHistoryModel3::data(const QModelIndex &index, int role) const
{
	AMPointerTreeNode *indexNode = static_cast<AMPointerTreeNode*>(index.internalPointer());
	if(!indexNode){
		//NEM
		return QVariant();
	}
	AMActionLogItem3 *item = static_cast<AMActionLogItem3*>(indexNode->item());
	if(!item){
		AMErrorMon::alert(this, AMACTIONHISTORYMODEL_MODELDATA_BAD_ITEM, QString("The action history attempted to access data with a bad item (row: %1 column: %2). Please report this problem to the Acquaman developers ").arg(index.row()).arg(index.column()));
		return QVariant();
	}

	if(role == Qt::DisplayRole) {
		switch(index.column()) {
		case 0: return item->shortDescription();
		case 1: return QVariant();
		case 2: return item->failureMessage();
		case 3: return AMDateTimeUtils::prettyDateTime(item->endDateTime());
		case 4: return AMDateTimeUtils::prettyDuration(item->startDateTime(), item->endDateTime());
		}
	}
	else if(role == Qt::DecorationRole) {
		// column 0: return the action icon.
		if(index.column() == 0) {
			QString iconFileName = item->iconFileName();
			if(iconFileName.isEmpty())
				iconFileName = ":/64x64/generic-action.png";
			QPixmap p;
			if(QPixmapCache::find("AMActionLogItemIcon" % iconFileName, &p))
				return p;
			else {
				p.load(iconFileName);
				p = p.scaledToHeight(22, Qt::SmoothTransformation);
				QPixmapCache::insert("AMActionLogItemIcon" % iconFileName, p);
				return p;
			}
		}
		// column 1: return the status icon
		else if(index.column() == 1) {
			switch(item->finalState()) {
			case AMAction3::Succeeded: return succeededIcon_;
			case AMAction3::Cancelled: return cancelledIcon_;
			case AMAction3::Failed: return failedIcon_;
			default: return unknownIcon_;
			}
		}
		else
			return QVariant();
	}
	else if(role == Qt::SizeHintRole) {
		return QSize(-1, 32);
	}
	else if(role == Qt::ToolTipRole) {
		if(index.column() == 0) {

			// In case the item didn't (or isn't yet) in some sort of finished state
			if(item && item->canCopy() && !(item->finalState() == 7 || item->finalState() == 8 || item->finalState() == 9) )
				return "Cannot select this item, it has not yet completed";
			//In case a loop or list had no logged actions in it
			if(item && item->canCopy() && item->actionInheritedLoop() && (childrenCount(index) == 0) )
				return "Cannot select this item, it has no children.";
			//In case a loop or list had no logged actions in it
			if(item && item->canCopy() && item->actionInheritedLoop() && (successfulChildrenCount(index) == 0) )
				return "Cannot select this item, none of its children succeeded.";

			return item->longDescription();
		}
		else if(index.column() == 1) {
			switch(item->finalState()) {
			case AMAction3::Succeeded: return "Succeeded";
			case AMAction3::Cancelled: return "Cancelled";
			case AMAction3::Failed:
				if(item->failureMessage().isEmpty())
					return "Failed";
				else
					return QString("Failed with message: %1").arg(item->failureMessage());
			default: return "[?]";
			}
		}
		else if(index.column() == 2)
			return QString(item->failureMessage());
	}
	else if(role == Qt::BackgroundRole) {
		switch(item->finalState()) {
		case AMAction3::Succeeded:
			return QColor(126, 255, 106);// light green
		case AMAction3::Cancelled:
			return QColor(255, 176, 106);// light orange
		case AMAction3::Failed:
			return QColor(255, 104, 106);// light red
		default:
			return QVariant();
		}
	}
	else if(role == AMActionHistoryModel3::ParentSelectRole) {
		ParentSelectMap selectMap;
		ParentSelectMap::const_iterator i = item->allParentSelected().constBegin();
		while (i != item->allParentSelected().constEnd()) {
			selectMap.insert(i.key(), i.value());
			++i;
		}
		return QVariant::fromValue(selectMap);
	}

	return QVariant();
}