Class: TaskJuggler::PropertyTreeNode

Inherits:
Object
  • Object
show all
Includes:
MessageHandler
Defined in:
lib/taskjuggler/PropertyTreeNode.rb

Overview

This class is the base object for all Project properties. A Project property is a e. g. a Task, a Resource or other objects. Such properties can be arranged in tree form by assigning child properties to an existing property. The parent object needs to exist at object creation time. The PropertyTreeNode class holds all data and methods that are common to the different types of properties. Each property can have a set of predifined attributes. The PropertySet class holds collections of the same PropertyTreeNode objects and the defined attributes. Each PropertySet has a predefined set of attributes, but the attribute set can be extended by the user. E.g. a task has the predefined attribute ‘start’ and ‘end’ date. The user can extend tasks with a user defined attribute like an URL that contains more details about the task.

Direct Known Subclasses

Account, Report, Resource, Scenario, Shift, Task

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageHandler

#critical, #debug, #error, #fatal, #info, #warning

Constructor Details

#initialize(propertySet, id, name, parent) ⇒ PropertyTreeNode

Create a new PropertyTreeNode object. propertySet is the PropertySet that this PropertyTreeNode object belongs to. The PropertySet determines the attributes that are common to all Nodes in the set. id is a String that is unique in the namespace of the set. name is a user readable, short description of the object. parent is the PropertyTreeNode that sits above this node in the object hierachy. A root object has a parent of nil. For sets with hierachical name spaces, parent can be nil and specified by a hierachical id (e. g. ‘father.son’).



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 47

def initialize(propertySet, id, name, parent)
  @propertySet = propertySet
  @project = propertySet.project
  @parent = parent

  # Scenario specific data
  @data = nil

  # Attributes are created on-demand. We need to be careful that a pure
  # check for existance does not create them unecessarily.
  @attributes = Hash.new do |hash, attributeId|
    unless (aType = attributeDefinition(attributeId))
      raise ArgumentError,
        "Unknown attribute '#{attributeId}' requested for " +
        "#{self.class.to_s.sub(/TaskJuggler::/, '')} '#{fullId}'"
    end
    unless aType.scenarioSpecific
      hash[attributeId] = aType.objClass.new(@propertySet, aType, self)
    else
      raise ArgumentError, "Attribute '#{attributeId}' is scenario specific"
    end
  end
  @scenarioAttributes = Array.new(@project.scenarioCount) do |scenarioIdx|
    Hash.new do |hash, attributeId|
      unless (aType = attributeDefinition(attributeId))
        raise ArgumentError,
          "Unknown attribute '#{attributeId}' requested for " +
          "#{self.class.to_s.sub(/TaskJuggler::/, '')} '#{fullId}'"
      end
      if aType.scenarioSpecific
        hash[attributeId] = aType.objClass.new(@propertySet, aType,
                                               @data[scenarioIdx])
      else
        raise ArgumentError,
          "Attribute '#{attributeId}' is not scenario specific"
      end
    end
  end

  # If _id_ is still nil, we generate a unique id.
  unless id
    tag = self.class.to_s.gsub(/TaskJuggler::/, '')
    id = '_' + tag + '_' + (propertySet.items + 1).to_s
    id = parent.fullId + '.' + id if !@propertySet.flatNamespace && parent
  end
  if !@propertySet.flatNamespace && id.include?('.')
    parentId = id[0..(id.rindex('.') - 1)]
    # Set parent to the parent property if it's still nil.
    @parent = @propertySet[parentId] unless @parent
    if $DEBUG
      if !@parent || !@propertySet[@parent.fullId]
        raise "Fatal Error: parent must be member of same property set"
      end
      if parentId != @parent.fullId
        raise "Fatal Error: parent (#{@parent.fullId}) and parent ID " +
            "(#{@parentId}) don't match"
      end
    end
    @subId = id[(id.rindex('.') + 1).. -1]
  else
    @subId = id
  end
  # The attribute 'id' is either the short ID or the full hierarchical ID.
  set('id', fullId)

  # The name of the property.
  @name = name
  set('name', name)

  @level = -1
  @sourceFileInfo = nil

  @sequenceNo = @propertySet.items + 1
  set('seqno', @sequenceNo)
  # This is a list of the real sub nodes of this PropertyTreeNode.
  @children = []
  # This is a list of the adopted sub nodes of this PropertyTreeNode.
  @adoptees = []
  # In case we have a parent object, we register this object as child of
  # the parent.
  if (@parent)
    @parent.addChild(self)
  end
  # This is a list of the PropertyTreeNode objects that have adopted this
  # node.
  @stepParents = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(func, scenarioIdx = 0, *args, &block) ⇒ Object

Many PropertyTreeNode functions are scenario specific. These functions are provided by the class *Scenario classes. In case we can’t find a function called for the base class we try to find it in corresponding *Scenario class.



711
712
713
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 711

def method_missing(func, scenarioIdx = 0, *args, &block)
  @data[scenarioIdx].send(func, *args, &block)
end

Instance Attribute Details

#adopteesObject (readonly)

Returns the value of attribute adoptees.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def adoptees
  @adoptees
end

#childrenObject (readonly)

Returns the value of attribute children.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def children
  @children
end

#dataObject (readonly)

Returns the value of attribute data.



37
38
39
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 37

def data
  @data
end

#idObject (readonly)

Returns the value of attribute id.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def id
  @id
end

#nameObject

Returns the value of attribute name.



36
37
38
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 36

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def parent
  @parent
end

#projectObject (readonly)

Returns the value of attribute project.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def project
  @project
end

#propertySetObject (readonly)

Returns the value of attribute propertySet.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def propertySet
  @propertySet
end

#sequenceNoObject (readonly)

Returns the value of attribute sequenceNo.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def sequenceNo
  @sequenceNo
end

#sourceFileInfoObject

Returns the value of attribute sourceFileInfo.



36
37
38
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 36

def sourceFileInfo
  @sourceFileInfo
end

#subIdObject (readonly)

Returns the value of attribute subId.



34
35
36
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 34

def subId
  @subId
end

Instance Method Details

#[](attributeId, scenario) ⇒ Object

Return the value of the attribute with ID attributeId. For scenario-specific attributes, scenario must indicate the index of the Scenario.



501
502
503
504
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 501

def [](attributeId, scenario)
  @scenarioAttributes[scenario][attributeId]
  @data[scenario].instance_variable_get(('@' + attributeId).intern)
end

#[]=(attributeId, scenario, value) ⇒ Object

Set the scenario specific attribute with ID attributeId for the scenario with index scenario to value. If scenario is nil, the attribute must not be scenario specific. In case the attribute does not exist, an exception is raised.



454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 454

def []=(attributeId, scenario, value)
  overwrite = false

  if scenario
    if AttributeBase.mode == 0
      # If we get values in 'provided' mode, we copy them immedidately to
      # all derived scenarios.
      @project.scenario(scenario).all.each do |sc|
        scenarioIdx = @project.scenarioIdx(sc)
        attr = @scenarioAttributes[scenarioIdx][attributeId]

        if attr.provided && !attr.isList?
          # Assignments to list attributes always append. We don't
          # consider this an overwrite.
          overwrite = true
        end

        if scenarioIdx == scenario
          attr.set(value)
        else
          attr.inherit(value)
        end
      end
    else
      attr = @scenarioAttributes[scenario][attributeId]
      overwrite = attr.provided && !attr.isList?

      attr.set(value)
    end
  else
    attr = @attributes[attributeId]
    overwrite = attr.provided && !attr.isList?
    attr.set(value)
  end

  # We only raise the overwrite error after all scenarios have been
  # set. For some attributes the overwrite is actually allowed.
  if overwrite
    raise AttributeOverwrite,
      "Overwriting a previously provided value for attribute " +
      "#{attributeId}"
  end
end

#addChild(child) ⇒ Object

Add child node as child to this node.



347
348
349
350
351
352
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 347

def addChild(child)
  if $DEBUG && child.propertySet != @propertySet
    raise "Child nodes must belong to the same property set as the parent"
  end
  @children.push(child)
end

#adopt(property) ⇒ Object

Adopt property as a step child. Also register the new relationship with the child.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 153

def adopt(property)
  # A property cannot adopt itself.
  if self == property
    error('adopt_self', 'A property cannot adopt itself')
  end

  # A top level task must never contain the same leaf task more then once!
  allOfRoot = root.all
  property.allLeaves.each do |adoptee|
    if allOfRoot.include?(adoptee)
      error('adopt_duplicate_child',
            "The task '#{adoptee.fullId}' has already been adopted by " +
            "property '#{root.fullId}' or any of its sub-properties.")
    end
  end

  @adoptees << property
  property.getAdopted(self)
end

#allObject

Returns a list of this node and all transient sub nodes.



265
266
267
268
269
270
271
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 265

def all
  res = [ self ]
  kids.each do |c|
    res = res.concat(c.all)
  end
  res
end

#allLeaves(withoutSelf = false) ⇒ Object

Return a list of all leaf nodes of this node.



274
275
276
277
278
279
280
281
282
283
284
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 274

def allLeaves(withoutSelf = false)
  res = []
  if leaf?
    res << self unless withoutSelf
  else
    kids.each do |c|
      res += c.allLeaves
    end
  end
  res
end

#ancestors(includeStepParents = false) ⇒ Object

Return a list with all parent nodes of this node.



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 374

def ancestors(includeStepParents = false)
  nodes = []
  if includeStepParents
    parents.each do |parent|
      nodes << parent
      nodes += parent.ancestors(true)
    end
  else
    n = self
    while n.parent
      nodes << (n = n.parent)
    end
  end
  nodes
end

#attributeDefinition(attributeId) ⇒ Object

Return the type of the attribute with ID attributeId.



400
401
402
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 400

def attributeDefinition(attributeId)
  @propertySet.attributeDefinitions[attributeId]
end

#backupAttributesObject

This method creates a shallow copy of all attributes and returns them as an Array that can be used with restoreAttributes().



194
195
196
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 194

def backupAttributes
  [ @attributes.clone, @scenarioAttributes.clone ]
end

#checkFailsAndWarningsObject



548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 548

def checkFailsAndWarnings
  if @attributes.has_key?('fail') || @attributes.has_key?('warn')
    propertyType = case self
                   when Task
                     'task'
                   when Resource
                     'resource'
                   else
                     'unknown'
                   end
    queryAttrs = { 'project' => @project,
                   'property' => self,
                   'scopeProperty' => nil,
                   'start' => @project['start'],
                   'end' => @project['end'],
                   'loadUnit' => :days,
                   'numberFormat' => @project['numberFormat'],
                   'timeFormat' => nil,
                   'currencyFormat' => @project['currencyFormat'] }
    query = Query.new(queryAttrs)
    if @attributes['fail']
      @attributes['fail'].get.each do |expr|
        if expr.eval(query)
          error("#{propertyType}_fail_check",
                "User defined check failed for #{propertyType} " +
                "#{fullId} \n" +
                "Condition: #{expr.to_s}\n" +
          "Result:    #{expr.to_s(query)}")
        end
      end
    end
    if @attributes['warn']
      @attributes['warn'].get.each do |expr|
        if expr.eval(query)
          warning("#{propertyType}_warn_check",
                  "User defined warning triggered for #{propertyType} " +
                  "#{fullId} \n" +
                  "Condition: #{expr.to_s}\n" +
          "Result:    #{expr.to_s(query)}")
        end
      end
    end
  end
end

#container?Boolean

Return true if the node has children.

Returns:

  • (Boolean)


369
370
371
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 369

def container?
  !@children.empty? || !@adoptees.empty?
end

#deep_cloneObject

We only use deep_clone for attributes, never for properties. Since attributes may reference properties these references should remain references.



138
139
140
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 138

def deep_clone
  self
end

#force(attributeId, value) ⇒ Object

Set the non-scenario-specific attribute with ID attributeId to value. No further checks are done.



428
429
430
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 428

def force(attributeId, value)
  @attributes[attributeId].set(value)
end

#fullIdObject

Return the full id of this node. For PropertySet objects with a flat namespace, this is just the ID. Otherwise, the full ID is composed of all IDs from the root node to this node, separating the IDs by a dot.



293
294
295
296
297
298
299
300
301
302
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 293

def fullId
  res = @subId
  unless @propertySet.flatNamespace
    t = self
    until (t = t.parent).nil?
      res = t.subId + "." + res
    end
  end
  res
end

#get(attributeId) ⇒ Object

Return the value of the non-scenario-specific attribute with ID attributeId. This method works for built-in attributes as well. In case the attribute does not exist, an exception is raised.



407
408
409
410
411
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 407

def get(attributeId)
  # Make sure the attribute gets created if it doesn't exist already.
  @attributes[attributeId]
  instance_variable_get(('@' + attributeId).intern)
end

#getAdopted(property) ⇒ Object

Get adopted by property. Also register the new relationship with the step parent. This method is for internal use only. Other classes should alway use PropertyTreeNode::adopt().



176
177
178
179
180
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 176

def getAdopted(property) # :nodoc:
  return if @stepParents.include?(property)

  @stepParents << property
end

#getAttribute(attributeId, scenarioIdx = nil) ⇒ Object

Return the value of the attribute with ID attributeId. This method works for built-in attributes as well. In case this is a scenario-specific attribute, the scenario index needs to be provided by scenarioIdx, otherwise it must be nil. In case the attribute does not exist, an exception is raised.



418
419
420
421
422
423
424
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 418

def getAttribute(attributeId, scenarioIdx = nil)
  if scenarioIdx
    @scenarioAttributes[scenarioIdx][attributeId]
  else
    @attributes[attributeId]
  end
end

#getBSIndiciesObject

Return the hierarchical index of this node. In project management lingo this is called the Breakdown Structure Index (BSI). The result is an Array with an index for each level from the root to this node.



321
322
323
324
325
326
327
328
329
330
331
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 321

def getBSIndicies
  idcs = []
  p = self
  begin
    parent = p.parent
    idcs.insert(0, parent ? parent.levelSeqNo(p) :
                            @propertySet.levelSeqNo(p))
    p = parent
  end while p
  idcs
end

#getIndiciesObject

Return the ‘index’ attributes of this property, prefixed by the ‘index’ attributes of all its parents. The result is an Array of Integers.



335
336
337
338
339
340
341
342
343
344
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 335

def getIndicies
  idcs = []
  p = self
  begin
    parent = p.parent
    idcs.insert(0, p.get('index'))
    p = parent
  end while p
  idcs
end

#inheritAttributesObject

Inherit values for the attributes from the parent node or the Project.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 217

def inheritAttributes
  # Inherit non-scenario-specific values
  @propertySet.eachAttributeDefinition do |attrDef|
    next if attrDef.scenarioSpecific || !attrDef.inheritedFromParent

    aId = attrDef.id
    if parent
      # Inherit values from parent property
      if parent.provided(aId) || parent.inherited(aId)
        @attributes[aId].inherit(parent.get(aId))
      end
    else
      # Inherit selected values from project if top-level property
      if attrDef.inheritedFromProject
        if @project[aId]
          @attributes[aId].inherit(@project[aId])
        end
      end
    end
  end

  # Inherit scenario-specific values
  @propertySet.eachAttributeDefinition do |attrDef|
    next if !attrDef.scenarioSpecific || !attrDef.inheritedFromParent

    @project.scenarioCount.times do |scenarioIdx|
      if parent
        # Inherit scenario specific values from parent property
        if parent.provided(attrDef.id, scenarioIdx) ||
           parent.inherited(attrDef.id, scenarioIdx)
          @scenarioAttributes[scenarioIdx][attrDef.id].inherit(
              parent[attrDef.id, scenarioIdx])
        end
      else
        # Inherit selected values from project if top-level property
        if attrDef.inheritedFromProject
          if @project[attrDef.id] &&
             @scenarioAttributes[scenarioIdx][attrDef.id]
            @scenarioAttributes[scenarioIdx][attrDef.id].inherit(
                @project[attrDef.id])
          end
        end
      end
    end
  end
end

#inherited(attributeId, scenarioIdx = nil) ⇒ Object

Returns true if the value of the attribute attributeId (in scenario scenarioIdx) has been inherited from a parent node or scenario.



522
523
524
525
526
527
528
529
530
531
532
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 522

def inherited(attributeId, scenarioIdx = nil)
  if scenarioIdx
    unless @scenarioAttributes[scenarioIdx].has_key?(attributeId)
      return false
    end
    @scenarioAttributes[scenarioIdx][attributeId].inherited
  else
    return false unless @attributes.has_key?(attributeId)
    @attributes[attributeId].inherited
  end
end

#isChildOf?(ancestor) ⇒ Boolean

Find out if this property is a direct or indirect child of ancestor.

Returns:

  • (Boolean)


355
356
357
358
359
360
361
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 355

def isChildOf?(ancestor)
  parent = self
  while parent = parent.parent
    return true if (parent == ancestor)
  end
  false
end

#kidsObject

Return a list of all children including adopted kids.



183
184
185
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 183

def kids
  @children + @adoptees
end

#leaf?Boolean

Return true if the node is a leaf node (has no children).

Returns:

  • (Boolean)


364
365
366
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 364

def leaf?
  @children.empty? && @adoptees.empty?
end

#levelObject

Returns the level that this property is on. Top-level properties return 0, their children 1 and so on. This value is cached internally, so it does not have to be calculated each time the function is called.



307
308
309
310
311
312
313
314
315
316
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 307

def level
  return @level if @level >= 0

  t = self
  @level = 0
  until (t = t.parent).nil?
    @level += 1
  end
  @level
end

#levelSeqNo(node) ⇒ Object

Return the index of the child node.



212
213
214
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 212

def levelSeqNo(node)
  @children.index(node) + 1
end

#logicalIdObject



286
287
288
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 286

def logicalId
  fullId
end

#modified?(attributeId, scenarioIdx = nil) ⇒ Boolean

Returns:

  • (Boolean)


534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 534

def modified?(attributeId, scenarioIdx = nil)
  if scenarioIdx
    unless @scenarioAttributes[scenarioIdx].has_key?(attributeId)
      return false
    end

    @scenarioAttributes[scenarioIdx][attributeId].provided ||
    @scenarioAttributes[scenarioIdx][attributeId].inherited
  else
    return false unless @attributes.has_key?(attributeId)
    @attributes[attributeId].provided || @attributes[attributeId].inherited
  end
end

#parentsObject

Return a list of all parents including step parents.



188
189
190
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 188

def parents
  (@parent ? [ @parent ] : []) + @stepParents
end

#provided(attributeId, scenarioIdx = nil) ⇒ Object

Returns true if the value of the attribute attributeId (in scenario scenarioIdx) has been provided by the user.



508
509
510
511
512
513
514
515
516
517
518
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 508

def provided(attributeId, scenarioIdx = nil)
  if scenarioIdx
    unless @scenarioAttributes[scenarioIdx].has_key?(attributeId)
      return false
    end
    @scenarioAttributes[scenarioIdx][attributeId].provided
  else
    return false unless @attributes.has_key?(attributeId)
    @attributes[attributeId].provided
  end
end

#ptnObject

We often use PTNProxy objects to represent PropertyTreeNode objects. The proxy usually does a good job acting like a PropertyTreeNode. But in some situations, we want to make sure to operate on the PropertyTreeNode and not the PTNProxy. Both classes provide a ptn() method that always return the PropertyTreeNode.



147
148
149
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 147

def ptn
  self
end

#query_alert(query) ⇒ Object



615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 615

def query_alert(query)
  journal = @project['journal']
  query.sortable = query.numerical = alert =
    journal.alertLevel(query.end, self, query)
  alertLevel = @project['alertLevels'][alert]
  query.string = alertLevel.name
  rText = "<fcol:#{alertLevel.color}><nowiki>#{alertLevel.name}" +
          "</nowiki></fcol>"
  unless (rti = RichText.new(rText, RTFHandlers.create(@project)).
          generateIntermediateFormat)
    warning('ptn_journal', "Syntax error in journal message")
    return nil
  end
  rti.blockMode = false
  query.rti = rti
end

#query_alertmessages(query) ⇒ Object



632
633
634
635
636
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 632

def query_alertmessages(query)
  journalMessages(@project['journal'].alertEntries(query.end, self, 1,
                                                   query.start, query),
                  query, true)
end

#query_alertsummaries(query) ⇒ Object



638
639
640
641
642
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 638

def query_alertsummaries(query)
  journalMessages(@project['journal'].alertEntries(query.end, self, 1,
                                                   query.start, query),
                  query, false)
end

#query_alerttrend(query) ⇒ Object



658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 658

def query_alerttrend(query)
  journal = @project['journal']
  startAlert = journal.alertLevel(query.start, self, query)
  endAlert = journal.alertLevel(query.end, self, query)
  if startAlert < endAlert
    query.sortable = 0
    query.string = 'Up'
  elsif startAlert > endAlert
    query.sortable = 2
    query.string = 'Down'
  else
    query.sortable = 1
    query.string = 'Flat'
  end
end

#query_children(query) ⇒ Object



593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 593

def query_children(query)
  list = []
  kids.each do |property|
    if query.listItem
      rti = RichText.new(query.listItem, RTFHandlers.create(@project)).
        generateIntermediateFormat
      q = query.dup
      q.property = property
      rti.setQuery(q)
      list << "<nowiki>#{rti.to_s}</nowiki>"
    else
      list << "<nowiki>#{property.name} (#{property.fullId})</nowiki>"
    end
  end

  query.assignList(list)
end

#query_journal(query) ⇒ Object



611
612
613
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 611

def query_journal(query)
  @project['journal'].to_rti(query)
end

#query_journalmessages(query) ⇒ Object



644
645
646
647
648
649
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 644

def query_journalmessages(query)
  journalMessages(@project['journal'].currentEntries(query.end, self, 0,
                                                     query.start,
                                                     query.hideJournalEntry),
                  query, true)
end

#query_journalsummaries(query) ⇒ Object



651
652
653
654
655
656
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 651

def query_journalsummaries(query)
  journalMessages(@project['journal'].currentEntries(query.end, self, 0,
                                                     query.start,
                                                     query.hideJournalEntry),
                  query, false)
end

#removeReferences(property) ⇒ Object

Remove any references in the stored data that references the property.



205
206
207
208
209
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 205

def removeReferences(property)
  @children.delete(property)
  @adoptees.delete(property)
  @stepParents.delete(property)
end

#restoreAttributes(backup) ⇒ Object

Restore the attributes to a previously saved state. backup is an Array generated by backupAttributes().



200
201
202
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 200

def restoreAttributes(backup)
  @attributes, @scenarioAttributes = backup
end

#rootObject

Return the top-level node for this node.



391
392
393
394
395
396
397
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 391

def root
  n = self
  while n.parent
    n = n.parent
  end
  n
end

#set(attributeId, value) ⇒ Object

Set the non-scenario-specific attribute with ID attributeId to value. In case an already provided value is overwritten again, an exeception is raised.



435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 435

def set(attributeId, value)
  attr = @attributes[attributeId]
  # Assignments to list attributes always append. We don't
  # consider this an overwrite.
  overwrite = attr.provided && !attr.isList?
  attr.set(value)

  # We only raise the overwrite error after the value has been set.
  if overwrite
    raise AttributeOverwrite,
      "Overwriting a previously provided value for attribute " +
      "#{attributeId}"
  end
end

#to_sObject Also known as: to_str

Dump the class data in human readable form. Used for debugging only.



675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
# File 'lib/taskjuggler/PropertyTreeNode.rb', line 675

def to_s # :nodoc:
  res = "#{self.class} #{fullId} \"#{@name}\"\n" +
        "  Sequence No: #{@sequenceNo}\n"

  res += "  Parent: #{@parent.fullId}\n" if @parent
  children = ""
  @children.each do |c|
    children += ', ' unless children.empty?
    children += c.fullId
  end
  res += '  Children: ' + children + "\n"  unless children.empty?
  @attributes.sort.each do |key, attr|
    res += indent("  #{key}: ", attr.to_s)
  end
  unless @scenarioAttributes.empty?
    project.scenarioCount.times do |sc|
      break if @scenarioAttributes[sc].nil?
      headerShown = false
      @scenarioAttributes[sc].sort.each do |key, attr|
        unless headerShown
          res += "  Scenario #{project.scenario(sc).get('id')} (#{sc})\n"
          headerShown = true
        end
        res += indent("    #{key}: ", attr.to_s)
      end
    end
  end
  res += '-' * 75 + "\n"
end