VirtualTreeDisplayData IBranch.GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData) { VirtualTreeDisplayData displayData = VirtualTreeDisplayData.Empty; SingleRingTypeInfo typeNode = mySingleNodes[row]; if (mySelectedCount != 0) { BitTracker selection = mySelectionTracker; bool isSelected = false; bool isImplied = false; bool isBold = false; if (selection[row]) { // Currently on, nothing to check isBold = isSelected = true; } else { // Current state depends on state of other rows int[] positionMap = myEnumValueToPositionMap; RingConstraintType[] relatedTypes = typeNode.ImpliedBy; if (relatedTypes != null) { for (int i = 0; i < relatedTypes.Length; ++i) { if (selection[positionMap[(int)relatedTypes[i]]]) { isImplied = true; break; } } } if (!isImplied && null != (relatedTypes = typeNode.ImpliedByCombination)) { isImplied = true; for (int i = 0; i < relatedTypes.Length; ++i) { if (!selection[positionMap[(int)relatedTypes[i]]]) { isImplied = false; break; } } } if (!isImplied) // Implied items are never bold { isBold = true; // Assume true, determine otherwise relatedTypes = typeNode.IncompatibleWith; for (int i = 0; i < relatedTypes.Length; ++i) { if (selection[positionMap[(int)relatedTypes[i]]]) { isBold = false; break; } } if (isBold && null != (relatedTypes = typeNode.IncompatibleWithCombination)) { isBold = false; for (int i = 0; i < relatedTypes.Length; ++i) { if (!selection[positionMap[(int)relatedTypes[i]]]) { isBold = true; break; } } } } } displayData.Bold = isBold; if (isSelected) { displayData.StateImageIndex = (short)StandardCheckBoxImage.CheckedFlat; } else if (isImplied) { displayData.StateImageIndex = (short)StandardCheckBoxImage.IndeterminateFlat; } else { displayData.StateImageIndex = (short)StandardCheckBoxImage.UncheckedFlat; } } else { displayData.StateImageIndex = (short)StandardCheckBoxImage.UncheckedFlat; } int imageIndex = myImageBase; if (imageIndex != -1) { displayData.SelectedImage = displayData.Image = (short)(imageIndex + (int)typeNode.Glyph); } return(displayData); }
StateRefreshChanges IBranch.ToggleState(int row, int column) { BitTracker tracker = mySelectionTracker; if (tracker[row]) { // Just turn it off, other states will display differently with the refresh mySelectionTracker[row] = false; --mySelectedCount; } else { // Turning this item on turns off implied and incompatible items. Find them and turn them off. int count = mySelectedCount; tracker[row] = true; ++count; SingleRingTypeInfo info = mySingleNodes[row]; int[] positionMap = myEnumValueToPositionMap; // Process single items RingConstraintType[] relatedTypes = info.ImpliedBy; bool checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = info.IncompatibleWith; } while (relatedTypes != null) { for (int i = 0; i < relatedTypes.Length; ++i) { int position = positionMap[(int)relatedTypes[i]]; if (tracker[position]) { tracker[position] = false; --count; } } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = info.IncompatibleWith; } } // Turn off full combination items relatedTypes = info.ImpliedByCombination; checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = info.IncompatibleWithCombination; } while (relatedTypes != null) { int i = 0; int combinationCount = relatedTypes.Length; for (; i < combinationCount; ++i) { if (!tracker[positionMap[(int)relatedTypes[i]]]) { break; } } if (i == combinationCount) { // Turn them all off for (i = 0; i < combinationCount; ++i) { tracker[positionMap[(int)relatedTypes[i]]] = false; } count -= combinationCount; } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = info.IncompatibleWithCombination; } } // Check if this is part of a complete combination and // make sure the combined item is turned off RingConstraintType[] usedInCombination = info.UsedInCombinationBy; if (usedInCombination != null) { for (int j = 0; j < usedInCombination.Length; ++j) { int usedByPosition = positionMap[(int)usedInCombination[j]]; if (tracker[usedByPosition]) { SingleRingTypeInfo usedByInfo = mySingleNodes[usedByPosition]; relatedTypes = usedByInfo.ImpliedByCombination; checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = usedByInfo.IncompatibleWithCombination; } while (relatedTypes != null) { int i = 0; int combinationCount = relatedTypes.Length; for (; i < combinationCount; ++i) { if (!tracker[positionMap[(int)relatedTypes[i]]]) { break; } } if (i == combinationCount) { tracker[usedByPosition] = false; --count; break; } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = usedByInfo.IncompatibleWithCombination; } } } } } mySelectionTracker = tracker; mySelectedCount = count; } return(StateRefreshChanges.Entire); }
/// <summary> /// Create a ring type branch with default settings /// </summary> /// <param name="element">An ring constraint element, although any element will do. /// Used to initialize glyph information only.</param> public RingTypeBranch(ModelElement element) { if (mySingleNodes == null) { string[] enumNames = Utility.GetLocalizedEnumNames(typeof(RingConstraintType), true); // List nodes by relative strength with negative ring types first, then positive ring types SingleRingTypeInfo[] singleNodes = new SingleRingTypeInfo[] { new SingleRingTypeInfo( RingConstraintType.Irreflexive, new RingConstraintType[] { RingConstraintType.Reflexive, RingConstraintType.Antisymmetric, RingConstraintType.PurelyReflexive }, // Antisymmetric and Irreflexive make Asymmetric, don't allow both to be selected new RingConstraintType[] { RingConstraintType.Symmetric, RingConstraintType.Transitive }, new RingConstraintType[] { RingConstraintType.Asymmetric, RingConstraintType.Intransitive, RingConstraintType.StronglyIntransitive, RingConstraintType.Acyclic }, null, null, enumNames[(int)RingConstraintType.Irreflexive], ResourceStrings.RingConstraintTypeDescriptionIrreflexive, SurveyQuestionGlyph.RingIrreflexive) , new SingleRingTypeInfo( RingConstraintType.Antisymmetric, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Intransitive, RingConstraintType.StronglyIntransitive, RingConstraintType.Symmetric, RingConstraintType.PurelyReflexive }, null, new RingConstraintType[] { RingConstraintType.Asymmetric, RingConstraintType.Acyclic }, null, null, enumNames[(int)RingConstraintType.Antisymmetric], ResourceStrings.RingConstraintTypeDescriptionAntisymmetric, SurveyQuestionGlyph.RingAntisymmetric) , new SingleRingTypeInfo( RingConstraintType.Asymmetric, new RingConstraintType[] { RingConstraintType.Antisymmetric, RingConstraintType.Irreflexive, RingConstraintType.Reflexive, RingConstraintType.Symmetric, RingConstraintType.PurelyReflexive }, null, new RingConstraintType[] { RingConstraintType.Acyclic }, null, null, enumNames[(int)RingConstraintType.Asymmetric], ResourceStrings.RingConstraintTypeDescriptionAsymmetric, SurveyQuestionGlyph.RingAsymmetric) , new SingleRingTypeInfo( RingConstraintType.Intransitive, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Antisymmetric, RingConstraintType.Transitive, RingConstraintType.Reflexive, RingConstraintType.PurelyReflexive }, null, new RingConstraintType[] { RingConstraintType.StronglyIntransitive }, null, null, enumNames[(int)RingConstraintType.Intransitive], ResourceStrings.RingConstraintTypeDescriptionIntransitive, SurveyQuestionGlyph.RingIntransitive) , new SingleRingTypeInfo( RingConstraintType.StronglyIntransitive, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Antisymmetric, RingConstraintType.Intransitive, RingConstraintType.Transitive, RingConstraintType.Reflexive, RingConstraintType.PurelyReflexive }, null, null, null, null, enumNames[(int)RingConstraintType.StronglyIntransitive], ResourceStrings.RingConstraintTypeDescriptionStronglyIntransitive, SurveyQuestionGlyph.RingStronglyIntransitive) , new SingleRingTypeInfo( RingConstraintType.Acyclic, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Antisymmetric, RingConstraintType.Asymmetric, RingConstraintType.Reflexive, RingConstraintType.Symmetric, RingConstraintType.PurelyReflexive }, null, null, null, null, enumNames[(int)RingConstraintType.Acyclic], ResourceStrings.RingConstraintTypeDescriptionAcyclic, SurveyQuestionGlyph.RingAcyclic) , new SingleRingTypeInfo( RingConstraintType.PurelyReflexive, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Antisymmetric, RingConstraintType.Asymmetric, RingConstraintType.Intransitive, RingConstraintType.StronglyIntransitive, RingConstraintType.Acyclic, RingConstraintType.Reflexive, RingConstraintType.Symmetric, RingConstraintType.Transitive }, null, null, null, null, enumNames[(int)RingConstraintType.PurelyReflexive], ResourceStrings.RingConstraintTypeDescriptionPurelyReflexive, SurveyQuestionGlyph.RingPurelyReflexive) // Note that if any two of Reflexive/Symmetric/Transitive are selected then the // third remains bold (or implied if Symmetric/Transitive is selected). This is // slightly inconsistent with the other selections, but is reasonable from a // usability perspective as selecting the third positive ring type will simply // make reflexive implied, not turn it off. , new SingleRingTypeInfo( RingConstraintType.Reflexive, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Asymmetric, RingConstraintType.Intransitive, RingConstraintType.StronglyIntransitive, RingConstraintType.Acyclic }, null, new RingConstraintType[] { RingConstraintType.PurelyReflexive }, new RingConstraintType[] { RingConstraintType.Symmetric, RingConstraintType.Transitive }, null, enumNames[(int)RingConstraintType.Reflexive], ResourceStrings.RingConstraintTypeDescriptionReflexive, SurveyQuestionGlyph.RingReflexive) , new SingleRingTypeInfo( RingConstraintType.Symmetric, new RingConstraintType[] { RingConstraintType.Antisymmetric, RingConstraintType.Asymmetric, RingConstraintType.Acyclic }, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Transitive }, new RingConstraintType[] { RingConstraintType.PurelyReflexive }, null, new RingConstraintType[] { RingConstraintType.Reflexive, RingConstraintType.Irreflexive, RingConstraintType.Transitive }, enumNames[(int)RingConstraintType.Symmetric], ResourceStrings.RingConstraintTypeDescriptionSymmetric, SurveyQuestionGlyph.RingSymmetric) , new SingleRingTypeInfo( RingConstraintType.Transitive, new RingConstraintType[] { RingConstraintType.Intransitive, RingConstraintType.StronglyIntransitive, RingConstraintType.PurelyReflexive }, new RingConstraintType[] { RingConstraintType.Irreflexive, RingConstraintType.Symmetric }, null, null, new RingConstraintType[] { RingConstraintType.Reflexive, RingConstraintType.Irreflexive, RingConstraintType.Symmetric }, enumNames[(int)RingConstraintType.Transitive], ResourceStrings.RingConstraintTypeDescriptionTransitive, SurveyQuestionGlyph.RingTransitive) }; int[] enumToPositionMap = new int[SingleRingTypeCount + 1]; // Note that undefined is at 0, so real values start at 1 for (int i = 0; i < SingleRingTypeCount; ++i) { enumToPositionMap[(int)singleNodes[i].NodeType] = i; } mySingleNodes = singleNodes; myEnumValueToPositionMap = enumToPositionMap; } Store store; if (myImageBase == -1 && element != null && null != (store = Utility.ValidateStore(element.Store))) { // Find the base offset for the SurveyElementGlyph question in the image list. Type questionType = typeof(SurveyQuestionGlyph); foreach (ISurveyQuestionTypeInfo questionInfo in ((ISurveyQuestionProvider <Store>)store.GetDomainModel <ORMCoreDomainModel>()).GetSurveyQuestions(store, null)) { if (questionInfo.QuestionType == questionType) { myImageBase = questionInfo.MapAnswerToImageIndex(0); break; } } } mySelectionTracker.Resize(SingleRingTypeCount); mySelectedCount = 0; }