lib/reports/Navigator.rb in taskjuggler-0.0.3 vs lib/reports/Navigator.rb in taskjuggler-0.0.4
- old
+ new
@@ -1,70 +1,197 @@
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = Navigator.rb -- The TaskJuggler III Project Management Software
#
-# Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
+# Copyright (c) 2006, 2007, 2008, 2009, 2010 by Chris Schlaeger <cs@kde.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
require 'reports/ReportContext'
class TaskJuggler
+ class NavigatorElement
+
+ attr_reader :parent, :label
+ attr_accessor :url, :elements, :current
+
+ def initialize(parent, label = nil, url = nil)
+ @parent = parent
+ @label = label
+ @url = url
+ @elements = []
+ # True if the current report is included in this NavigatorElement or any
+ # of its sub elements.
+ @current = false
+ end
+
+ def to_html
+ first = true
+ html = (div = XMLElement.new('div'))
+
+ @elements.each do |element|
+ next unless label
+
+ if first
+ first = false
+ else
+ div << XMLText.new('|')
+ end
+
+ url = element.url
+ if !url
+ nEl = element
+ while nEl.elements[0]
+ break if nEl.current
+
+ if nEl.elements[0].url
+ url = nEl.elements[0].url
+ break
+ end
+ nEl = nEl.elements[0]
+ end
+ end
+ if url && url != currentUrl
+ div << (span = XMLElement.new('span', 'class' => 'navbar_other'))
+ span << (a = XMLElement.new('a', 'href' => url))
+ a << XMLText.new(element.label)
+ else
+ div << (span = XMLElement.new('span',
+ 'class' => 'navbar_current'))
+ span << XMLText.new(element.label)
+ end
+ end
+ @elements.each do |element|
+ if element.current && !element.elements.empty?
+ html << XMLElement.new('hr') unless first
+ html << element.to_html
+ end
+ end
+ html
+ end
+
+ # Return a text version of the tree. Currently used for debugging only.
+ def to_s(indent = 0)
+ @elements.each do |element|
+ puts "#{' ' * indent}#{element.current ? '<' : ''}" +
+ "#{element.label}#{element.current ? '>' : ''}" +
+ " -> #{element.url}"
+ element.to_s(indent + 1)
+ end
+ end
+
+ # Store the URL for the current report. Since the URL entry in the root
+ # node of the NavigatorElement tree is never used, we use it to store the
+ # current URL there.
+ def currentUrl=(url)
+ root.url = url
+ end
+
+ # Get the URL of the current report from the root node.
+ def currentUrl
+ root.url
+ end
+
+ # Traverse the tree all the way to the top and return the root element.
+ def root
+ p = self
+ while p.parent
+ p = p.parent
+ end
+ p
+ end
+
+ end
+
+ # A Navigator is an automatically generated menu to navigate a list of
+ # reports. The hierarchical structure of the reports will be reused to
+ # group them. The actual structure of the Navigator depends on the output
+ # format.
class Navigator
attr_reader :id
- attr_accessor :hideReport
+ attr_accessor :hideReport, :reportRoot
def initialize(id, project)
@id = id
@project = project
@hideReport = LogicalExpression.new(LogicalOperation.new(0))
+ @reportRoot = nil
+ @elements = []
end
- def to_html
- reports = filterReports
- return nil if reports.empty?
+ # Generate an output format independant version of the navigator. This is
+ # a tree of NavigatorElement objects.
+ def generate(reports, reportRoot, parentElement)
+ raise "Report context missing" unless @project.reportContext.report
- first = true
- html = []
- html << (div = XMLElement.new('div'))
reports.each do |report|
- next unless report.get('formats').include?(:html)
+ hasURL = report.get('formats').include?(:html)
+ next if (report.parent != reportRoot) ||
+ (report.leaf? && !hasURL)
- if first
- first = false
- else
- div << XMLText.new('|')
+ label = report.get('title') || report.name
+ # Determine the URL for this element.
+ if hasURL
+ url = report.name + '.html'
+ url = normalizeURL(url, @project.reportContext.report.name)
end
+ parentElement.elements <<
+ (element = NavigatorElement.new(parentElement, label, url))
+
if report == @project.reportContext.report
- div << (span = XMLElement.new('span',
- 'style' => 'class:navbar_current'))
- span << XMLText.new(report.name)
- else
- div << (span = XMLElement.new('span', 'style' => 'class:navbar_other'))
- span << (a = XMLElement.new('a', 'href' => report.name + '.html'))
- a << XMLText.new(report.name)
+ element.currentUrl = url
+ # Mark this element and all its parents as current.
+ nEl = element
+ while nEl
+ nEl.current = true
+ nEl = nEl.parent
+ end
end
+
+ generate(reports, report, element)
end
- html
end
+ def to_html
+ reports = filterReports
+ return nil if reports.empty?
+
+ generate(reports, nil, content = NavigatorElement.new(nil))
+ content.to_html
+ end
+
private
def filterReports
list = PropertyList.new(@project.reports)
list.setSorting([[ 'seqno', true, -1 ]])
list.sort!
# Remove all reports that the user doesn't want to have include.
+ query = @project.reportContext.query.dup
+ query.scopeProperty = nil
list.delete_if do |property|
- @hideReport.eval(property, nil)
+ query.property = property
+ @hideReport.eval(query)
end
list
+ end
+
+ # Remove the URL or directory path from _url1_ that is identical to
+ # _url2_.
+ def normalizeURL(url1, url2)
+ cut = 0
+ 0.upto(url1.length - 1) do |i|
+ return url1[cut, url1.length - cut] if url1[i] != url2[i]
+ cut = i + 1 if url1[i] == ?/
+ end
+
+ url1
end
end
end