<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -19,7 +19,7 @@ class TaskJuggler
   # 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.
-  class PropertyList &lt; Array
+  class PropertyList
 
     attr_writer :query
     attr_reader :propertySet, :query, :sortingLevels, :sortingCriteria,
@@ -28,7 +28,7 @@ class TaskJuggler
     # A PropertyList is always bound to a certain PropertySet. All properties
     # in the list must be of that set.
     def initialize(arg)
-      super(arg.to_ary)
+      @items = arg.to_ary
       if arg.is_a?(PropertySet)
         # Create a PropertyList from the given PropertySet.
         @propertySet = arg
@@ -40,7 +40,7 @@ class TaskJuggler
         @query = nil
         resetSorting
         addSortingCriteria('seqno', true, -1)
-        self.sort!
+        sort!
       else
         # Create a PropertyList from a given other PropertyList.
         @propertySet = arg.propertySet
@@ -52,6 +52,13 @@ class TaskJuggler
       end
     end
 
+    # 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.
+    def method_missing(func, *args, &amp;block)
+      @items.method(func).call(*args, &amp;block)
+    end
+
     # Set all sorting levels as Array of triplets.
     def setSorting(modes)
       resetSorting
@@ -68,8 +75,8 @@ class TaskJuggler
       @scenarioIdx = []
     end
 
-    # Append another Array of Tasks or a PropertyList to this. The list will be
-    # sorted again.
+    # Append another Array of PropertyTreeNodes or a PropertyList to this. The
+    # list will be sorted again.
     def append(list)
       if $DEBUG
         list.each do |node|
@@ -79,8 +86,8 @@ class TaskJuggler
         end
       end
 
-      concat(list)
-      self.sort!
+      @items.concat(list)
+      sort!
     end
 
     # Append a new sorting level to the existing levels.
@@ -95,6 +102,9 @@ class TaskJuggler
                 &quot;You must specify a scenario id.&quot;
         end
       else
+        if @propertySet.project.scenario(scIdx).nil?
+          raise TjException.new, &quot;Unknown scenario index #{scIdx} used.&quot;
+        end
         if !@propertySet.scenarioSpecific?(criteria)
           raise TjException.new, &quot;Attribute #{criteria} is not scenario specific&quot;
         end
@@ -114,7 +124,64 @@ class TaskJuggler
 
     # Sort the properties according to the currently defined sorting criteria.
     def sort!
-      super do |a, b|
+      if treeMode?
+        # Tree sorting is somewhat complex. It will be based on the 'tree'
+        # attribute of the PropertyTreeNodes but we have to update them first
+        # based on the other sorting criteria.
+
+        # Remove the tree sorting mode first.
+        sc = @sortingCriteria.delete_at(0)
+        su = @sortingUp.delete_at(0)
+        si = @scenarioIdx.delete_at(0)
+        @sortingLevels -= 1
+
+        # Sort the list based on the rest of the modes.
+        sortInternal
+        # The update the 'index' attributes of the PropertyTreeNodes.
+        index
+        # An then the 'tree' attributes.
+        @propertySet.indexTree(@items)
+
+        # Restore the 'tree' sorting mode again.
+        @sortingCriteria.insert(0, sc)
+        @sortingUp.insert(0, su)
+        @scenarioIdx.insert(0, si)
+        @sortingLevels += 1
+
+        # Sort again, now based on the updated 'tree' attributes.
+        sortInternal
+      else
+        sortInternal
+      end
+      # Update indexes.
+      index
+    end
+
+    # This function sets the index attribute of all the properties in the list.
+    # The index starts with 0 and increases for each property.
+    def index
+      i = 0
+      @items.each do |p|
+        p.set('index', i += 1)
+      end
+    end
+
+    # Turn the list into a String. This is only used for debugging.
+    def to_s # :nodoc:
+      res = &quot;Sorting: &quot;
+      @sortingLevels.times do |i|
+        res += &quot;#{@sortingCriteria[i]}/#{@sortingUp[i] ? 'up' : 'down'}/&quot; +
+               &quot;#{@scenarioIdx[i]}, &quot;
+      end
+      res += &quot;\n#{@items.length} properties:&quot;
+      @items.each { |i| res += &quot;#{i.get('id')}: #{i.get('name')}\n&quot; }
+      res
+    end
+
+    private
+
+    def sortInternal
+      @items.sort! do |a, b|
         res = 0
         @sortingLevels.times do |i|
           if @query
@@ -151,29 +218,6 @@ class TaskJuggler
         end
         res
       end
-      # Update indexes.
-      index
-    end
-
-    # This function sets the index attribute of all the properties in the list.
-    # The index starts with 0 and increases for each property.
-    def index
-      i = 0
-      each do |p|
-        p.set('index', i += 1)
-      end
-    end
-
-    # Turn the list into a String. This is only used for debugging.
-    def to_s # :nodoc:
-      res = &quot;Sorting: &quot;
-      @sortingLevels.times do |i|
-        res += &quot;#{@sortingCriteria[i]}/#{@sortingUp[i] ? 'up' : 'down'}/&quot; +
-               &quot;#{@scenarioIdx[i]}, &quot;
-      end
-      res += &quot;\n&quot;
-      each { |i| res += &quot;#{i.get('id')}: #{i.get('name')}\n&quot; }
-      res
     end
 
   end</diff>
      <filename>lib/PropertyList.rb</filename>
    </modified>
    <modified>
      <diff>@@ -224,19 +224,14 @@ class TaskJuggler
       @propertyMap[id]
     end
 
-    # Update the WBS and tree indicies. This method needs to be called whenever
-    # the set has been modified.
+    # Update the work-breakdown-structure (wbs) indicies. This method needs to
+    # be called whenever the set has been modified.
     def index
       each do |p|
         wbsIdcs = p.getWBSIndicies
-        tree = &quot;&quot;
         wbs = &quot;&quot;
         first = true
         wbsIdcs.each do |idx|
-          # Prefix the level index with zeros so that we always have a 5 digit
-          # long String. 5 digits should be large enough for all real-world
-          # projects.
-          tree += idx.to_s.rjust(5, '0')
           if first
             first = false
           else
@@ -245,10 +240,39 @@ class TaskJuggler
           wbs += idx.to_s
         end
         p.set('wbs', wbs)
-        # All elements of a node should have the same 'tree' value. So we
-        # delete the last 5 digits again.
-        tree = tree[0.. - 6] + '+' if p.leaf?
-        p.set('tree', tree)
+      end
+    end
+
+    # Update the 'tree' indicies that are needed for the 'tree' sorting mode.
+    def indexTree(list)
+      level = 0
+      # Since we don't know the number of nested levels upfront, we continue
+      # to increase them until we don't find any more PropertyTreeNodes on
+      # that level.
+      levelHasItems = true
+      while levelHasItems
+        levelHasItems = false
+        # Now search the list for items on that level.
+        list.each do |property|
+          if property.level == level
+            levelHasItems = true
+            # The indicies are an Array if the 'index' attributes for this
+            # property and all its parents.
+            wbsIdcs = property.getIndicies
+            # Now convert them to a String.
+            tree = ''
+            wbsIdcs.each do |idx|
+              # Prefix the level index with zeros so that we always have a 5
+              # digit long String. 5 digits should be large enough for all
+              # real-world projects.
+              tree += idx.to_s.rjust(5, '0')
+            end
+            # All elements of a node should have the same 'tree' value. So we
+            # delete the last 5 digits again.
+            property.set('tree', tree)
+          end
+        end
+        level += 1
       end
     end
 
@@ -303,7 +327,7 @@ class TaskJuggler
 
     # Return the set of PropertyTreeNode objects as flat Array.
     def to_ary
-      @properties
+      @properties.clone
     end
 
     def to_s</diff>
      <filename>lib/PropertySet.rb</filename>
    </modified>
    <modified>
      <diff>@@ -44,7 +44,7 @@ class TaskJuggler
       unless id
         tag = self.class.to_s.gsub(/TaskJuggler::/, '')
         id = '_' + tag + '_' + (propertySet.items + 1).to_s
-        id = parent.id + '.' + id if !@propertySet.flatNamespace &amp;&amp; parent
+        id = parent.fullId + '.' + id if !@propertySet.flatNamespace &amp;&amp; parent
       end
       if !@propertySet.flatNamespace &amp;&amp; id.include?('.')
         parentId = id[0..(id.rindex('.') - 1)]
@@ -251,6 +251,19 @@ class TaskJuggler
       idcs
     end
 
+    # Return the 'index' attributes of this property, prefixed by the 'index'
+    # attributes of all its parents. The result is an Array of Fixnums.
+    def getIndicies
+      idcs = []
+      p = self
+      begin
+        parent = p.parent
+        idcs.insert(0, p.get('index'))
+        p = parent
+      end while p
+      idcs
+    end
+
     # Add _child_ node as child to this node.
     def addChild(child)
       if $DEBUG &amp;&amp; child.propertySet != @propertySet</diff>
      <filename>lib/PropertyTreeNode.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2381,8 +2381,6 @@ specified by [[now]].
 EOT
          )
 
-    singlePattern('_tree')
-
     singlePattern('_wbs')
     descr('The hierarchical or work breakdown structure index')
 </diff>
      <filename>lib/TjpSyntaxRules.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>9c0146c7d4ad6cbe176ceee80de5c63a99ecdc9c</id>
    </parent>
  </parents>
  <author>
    <name>Chris Schlaeger</name>
    <email>cs@kde.org</email>
  </author>
  <url>http://github.com/jeremyz/taskjuggler3/commit/869ce9930065d2153fdb97be4ea06e20c72b7340</url>
  <id>869ce9930065d2153fdb97be4ea06e20c72b7340</id>
  <committed-date>2009-11-11T05:02:37-08:00</committed-date>
  <authored-date>2009-11-11T05:02:37-08:00</authored-date>
  <message>Fix tree sorting.</message>
  <tree>ff1a008bca76b81cb1ac9dfcc856c29d54d1d4fe</tree>
  <committer>
    <name>Chris Schlaeger</name>
    <email>cs@kde.org</email>
  </committer>
</commit>
