Parent

Class Index [+]

Quicksearch

TaskJuggler::PropertyList

The PropertyList is a utility class that can be used to hold a list of properties. It’s derived from an Array, so it can hold the properties in a well defined order. The order can be determined by an arbitrary number of sorting levels. A sorting level specifies an attribute who’s value should be used for sorting, a scenario index if necessary and the sorting direction (up/down). All nodes in the PropertyList must belong to the same PropertySet.

Attributes

query[W]
propertySet[R]
query[R]
sortingLevels[R]
sortingCriteria[R]
sortingUp[R]
scenarioIdx[R]

Public Class Methods

new(arg, copyItems = true) click to toggle source

A PropertyList is always bound to a certain PropertySet. All properties in the list must be of that set.

    # File lib/taskjuggler/PropertyList.rb, line 31
31:     def initialize(arg, copyItems = true)
32:       @items = copyItems ? arg.to_ary : []
33:       if arg.is_a?(PropertySet)
34:         # Create a PropertyList from the given PropertySet.
35:         @propertySet = arg
36:         # To keep the list sorted, we may have to access Property attributes.
37:         # Pre-scheduling, we can only use static attributes. Post-scheduling,
38:         # we can include dynamic attributes as well. This query template will
39:         # be used to query attributes when it has been set. Otherwise the list
40:         # can only be sorted by static attributes.
41:         @query = nil
42:         resetSorting
43:         addSortingCriteria('seqno', true, 1)
44:         sort!
45:       else
46:         # Create a PropertyList from a given other PropertyList.
47:         @propertySet = arg.propertySet
48:         @query = arg.query ? arg.query.dup : nil
49:         @sortingLevels = arg.sortingLevels
50:         @sortingCriteria = arg.sortingCriteria.dup
51:         @sortingUp = arg.sortingUp.dup
52:         @scenarioIdx = arg.scenarioIdx.dup
53:       end
54:     end

Public Instance Methods

append(list) click to toggle source

Append another Array of PropertyTreeNodes or a PropertyList to this. The list will be sorted again.

    # File lib/taskjuggler/PropertyList.rb, line 85
85:     def append(list)
86:       if $DEBUG
87:         list.each do |node|
88:           unless node.propertySet == @propertySet
89:             raise "Fatal Error: All nodes must belong to the same PropertySet."
90:           end
91:         end
92:       end
93: 
94:       @items.concat(list)
95:       sort!
96:     end
index() click to toggle source

This function sets the index attribute of all the properties in the list. The index starts with 0 and increases for each property.

     # File lib/taskjuggler/PropertyList.rb, line 147
147:     def index
148:       i = 0
149:       @items.each do |p|
150:         p.set('index', i += 1)
151:       end
152:     end
itemIndex(item) click to toggle source

Return the Array index of item or nil.

     # File lib/taskjuggler/PropertyList.rb, line 141
141:     def itemIndex(item)
142:       @items.index(item)
143:     end
method_missing(func, *args, &block) click to toggle source

This class should be a derived class of Array. But since it re-defines sort!() and still needs to call Array::sort!() I took a different route. All missing methods will be propagated to the @items Array.

    # File lib/taskjuggler/PropertyList.rb, line 59
59:     def method_missing(func, *args, &block)
60:       @items.method(func).call(*args, &block)
61:     end
resetSorting() click to toggle source

Clear all sorting levels.

    # File lib/taskjuggler/PropertyList.rb, line 76
76:     def resetSorting
77:       @sortingLevels = 0
78:       @sortingCriteria = []
79:       @sortingUp = []
80:       @scenarioIdx = []
81:     end
setSorting(modes) click to toggle source

Set all sorting levels as Array of triplets.

    # File lib/taskjuggler/PropertyList.rb, line 68
68:     def setSorting(modes)
69:       resetSorting
70:       modes.each do |mode|
71:         addSortingCriteria(*mode)
72:       end
73:     end
sort!() click to toggle source

Sort the properties according to the currently defined sorting criteria.

     # File lib/taskjuggler/PropertyList.rb, line 106
106:     def sort!
107:       if treeMode?
108:         # Tree sorting is somewhat complex. It will be based on the 'tree'
109:         # attribute of the PropertyTreeNodes but we have to update them first
110:         # based on the other sorting criteria.
111: 
112:         # Remove the tree sorting mode first.
113:         sc = @sortingCriteria.delete_at(0)
114:         su = @sortingUp.delete_at(0)
115:         si = @scenarioIdx.delete_at(0)
116:         @sortingLevels -= 1
117: 
118:         # Sort the list based on the rest of the modes.
119:         sortInternal
120:         # The update the 'index' attributes of the PropertyTreeNodes.
121:         index
122:         # An then the 'tree' attributes.
123:         indexTree
124: 
125:         # Restore the 'tree' sorting mode again.
126:         @sortingCriteria.insert(0, sc)
127:         @sortingUp.insert(0, su)
128:         @scenarioIdx.insert(0, si)
129:         @sortingLevels += 1
130: 
131:         # Sort again, now based on the updated 'tree' attributes.
132:         sortInternal
133:       else
134:         sortInternal
135:       end
136:       # Update indexes.
137:       index
138:     end
to_ary() click to toggle source
    # File lib/taskjuggler/PropertyList.rb, line 63
63:     def to_ary
64:       @items.dup
65:     end
treeMode?() click to toggle source

If the first sorting level is ‘tree’ the breakdown structure of the list is preserved. This is a somewhat special mode and this function returns true if the mode is set.

     # File lib/taskjuggler/PropertyList.rb, line 101
101:     def treeMode?
102:       @sortingLevels > 0 && @sortingCriteria[0] == 'tree'
103:     end

Private Instance Methods

addSortingCriteria(criteria, up, scIdx) click to toggle source

Append a new sorting level to the existing levels.

     # File lib/taskjuggler/PropertyList.rb, line 169
169:     def addSortingCriteria(criteria, up, scIdx)
170:       unless @propertySet.knownAttribute?(criteria) ||
171:              @propertySet.hasQuery?(criteria, scIdx)
172:         raise TjException.new,
173:               "Unknown attribute #{criteria} used for sorting criterium"
174:       end
175:       if scIdx == 1
176:         if @propertySet.scenarioSpecific?(criteria)
177:           raise TjException.new,
178:                 "Attribute #{criteria} is scenario specific." +
179:                 "You must specify a scenario id."
180:         end
181:       else
182:         if @propertySet.project.scenario(scIdx).nil?
183:           raise TjException.new, "Unknown scenario index #{scIdx} used."
184:         end
185:         if !@propertySet.scenarioSpecific?(criteria)
186:           raise TjException.new, "Attribute #{criteria} is not scenario specific"
187:         end
188:       end
189:       @sortingCriteria.push(criteria)
190:       @sortingUp.push(up)
191:       @scenarioIdx.push(scIdx)
192:       @sortingLevels += 1
193:     end
indexTree() click to toggle source

Update the ‘tree’ indicies that are needed for the ‘tree’ sorting mode.

     # File lib/taskjuggler/PropertyList.rb, line 196
196:     def indexTree
197:       @items.each do |property|
198:         # The indicies are an Array if the 'index' attributes for this
199:         # property and all its parents.
200:         treeIdcs = property.getIndicies
201:         # Now convert them to a String.
202:         tree = ''
203:         treeIdcs.each do |idx|
204:           # Prefix the level index with zeros so that we always have a 6
205:           # digit long String. 6 digits should be large enough for all
206:           # real-world projects.
207:           tree += idx.to_s.rjust(6, '0')
208:         end
209:         property.set('tree', tree)
210:       end
211:     end
sortInternal() click to toggle source
     # File lib/taskjuggler/PropertyList.rb, line 213
213:     def sortInternal
214:       @items.sort! do |a, b|
215:         res = 0
216:         @sortingLevels.times do |i|
217:           if @query
218:             # In case we have a Query reference, we get the two values with this
219:             # query.
220:             @query.scenarioIdx = @scenarioIdx[i] < 0 ? nil : @scenarioIdx[i]
221:             @query.attributeId = @sortingCriteria[i]
222: 
223:             @query.property = a
224:             @query.process
225:             aVal = @query.to_sort
226: 
227:             @query.property = b
228:             @query.process
229:             bVal = @query.to_sort
230:           else
231:             # In case we don't have a query, we use the static mechanism.
232:             # If the scenario index is negative we have a non-scenario-specific
233:             # attribute.
234:             if @scenarioIdx[i] < 0
235:               if @sortingCriteria[i] == 'id'
236:                 aVal = a.fullId
237:                 bVal = b.fullId
238:               else
239:                 aVal = a.get(@sortingCriteria[i])
240:                 bVal = b.get(@sortingCriteria[i])
241:               end
242:             else
243:               aVal = a[@sortingCriteria[i], @scenarioIdx[i]]
244:               bVal = b[@sortingCriteria[i], @scenarioIdx[i]]
245:             end
246:           end
247:           res = aVal <=> bVal
248:           # Invert the result if we have to sort in decreasing order.
249:           res = -res unless @sortingUp[i]
250:           # If the two elements are equal on this compare level we try the next
251:           # level.
252:           break if res != 0
253:         end
254:         res
255:       end
256:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.