1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = RTFQuery.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
# by Chris Schlaeger <cs@taskjuggler.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 'taskjuggler/RichText/RTFWithQuerySupport'
require 'taskjuggler/XMLElement'
require 'taskjuggler/Query'
class TaskJuggler
# This class is a specialized RichTextFunctionHandler that can be used to
# query the value of a project or property attribute.
class RTFQuery < RTFWithQuerySupport
def initialize(project, sourceFileInfo = nil)
@project = project
super('query', sourceFileInfo)
@blockMode = false
end
# Return the result of the query as String.
def to_s(args)
return '' unless (query = prepareQuery(args))
if query.ok
query.to_s
else
error('query_error', query.errorMessage + recreateQuerySyntax(args))
'Query Error: ' + query.errorMessage
end
end
# Return a XMLElement tree that represents the navigator in HTML code.
def to_html(args)
return nil unless (query = prepareQuery(args))
if query.ok
if (rti = query.to_rti)
rti.to_html
elsif (str = query.to_s)
XMLText.new(str)
else
nil
end
else
error('query_error', query.errorMessage + recreateQuerySyntax(args))
font = XMLElement.new('font', 'color' => '#FF0000')
font << XMLText.new('Query Error: ' + query.errorMessage)
font
end
end
# Not supported for this function.
def to_tagged(args)
nil
end
private
def prepareQuery(args)
unless @query
raise "No Query has been registered for this RichText yet!"
end
query = @query.dup
# Check the user provided arguments. Only the following list is allowed.
validArgs = %w( attribute currencyformat end family journalattributes
journalmode loadunit numberformat property scenario
scopeproperty start timeformat )
expandedArgs = {}
args.each do |arg, value|
unless validArgs.include?(arg)
error('bad_query_parameter', "Unknown query parameter '#{arg}'. " +
"Use one of #{validArgs.join(', ')}!")
return nil
end
expandedArgs[arg] =
SimpleQueryExpander.new(value, @query, @sourceFileInfo).expand
end
if ((expandedArgs['property'] && expandedArgs['property'][0] != '!') ||
expandedArgs['scopeproperty']) &&
!(expandedArgs['family'] || @query.propertyType)
error('missing_family',
"If you provide a property or scope property you need to " +
"provide a family type as well.")
end
# Every provided query parameter will overwrite the corresponding value
# in the Query that was provided by the ReportContext. The name of the
# arguments don't always exactly match the Query variables Let's start
# with the easy ones.
if expandedArgs['property']
query.propertyId = expandedArgs['property']
query.property = nil unless query.propertyId[0] == '!'
end
if expandedArgs['scopeproperty']
query.scopePropertyId = expandedArgs['scopeproperty']
query.scopeProperty = nil
end
query.attributeId = expandedArgs['attribute'] if expandedArgs['attribute']
query.start = TjTime.new(expandedArgs['start']) if expandedArgs['start']
query.end = TjTime.new(expandedArgs['end']) if expandedArgs['end']
if expandedArgs['numberformat']
query.numberFormat = expandedArgs['numberformat']
end
query.timeFormat = expandedArgs['timeformat'] if expandedArgs['timeformat']
if expandedArgs['currencyformat']
query.currencyFormat = expandedArgs['currencyformat']
end
query.project = @project
# And now the slighly more complicated ones.
setScenarioIdx(query, expandedArgs)
setPropertyType(query, expandedArgs)
setLoadUnit(query, expandedArgs)
setJournalMode(query, expandedArgs)
setJournalAttributes(query, expandedArgs)
# Now that we have put together the query, we can process it and return
# the query object for result extraction.
query.process
query
end
# Regenerate the original query text based on the argument list.
def recreateQuerySyntax(args)
queryText = "\n<-query"
args.each do |a, v|
queryText += " #{a}=\"#{v}\""
end
queryText += "->"
end
def setPropertyType(query, args)
validTypes = { 'account' => :Account,
'task' => :Task,
'resource' => :Resource }
if args['family']
unless validTypes[args['family']]
error('rtfq_bad_query_family',
"Unknown query family type '#{args['family']}'. " +
"Use one of #{validTypes.keys.join(', ')}!")
end
query.propertyType = validTypes[args['family']]
if query.propertyType == :Task
query.scopePropertyType = :Resource
elsif query.propertyType == :Resource
query.scopePropertyType = :Task
end
end
end
def setLoadUnit(query, args)
units = {
'days' => :days, 'hours' => :hours, 'longauto' => :longauto,
'minutes' => :minutes, 'months' => :months, 'quarters' => :quarters,
'shortauto' => :shortauto, 'weeks' => :weeks, 'years' => :years
}
query.loadUnit = units[args['loadunit']] if args['loadunit']
end
def setScenarioIdx(query, args)
if args['scenario']
scenarioIdx = @project.scenarioIdx(args['scenario'])
unless scenarioIdx
error('rtfq_bad_scenario', "Unknown scenario #{args['scenario']}")
end
query.scenarioIdx = scenarioIdx
end
# Default to 0 in case no scenario was provided.
query.scenarioIdx = 0 unless query.scenarioIdx
end
def setJournalMode(query, args)
if (mode = args['journalmode'])
validModes = %w( journal journal_sub status_up status_down alerts_down )
unless validModes.include?(mode)
error('rtfq_bad_journalmode',
"Unknown journalmode #{mode}. Must be one of " +
"#{validModes.join(', ')}.")
end
query.journalMode = mode.intern
elsif !query.journalMode
query.journalMode = :journal
end
end
def setJournalAttributes(query, args)
if (attrListStr = args['journalattributes'])
attrs = attrListStr.split(', ').map { |a| a.delete(' ') }
query.journalAttributes = []
validAttrs = %w( author date details flags headline property propertyid
summary timesheet )
attrs.each do |attr|
if validAttrs.include?(attr)
query.journalAttributes << attr
else
error('rtfq_bad_journalattr',
"Unknown journalattribute #{attr}. Must be one of " +
"#{validAttrs.join(', ')}.")
end
end
elsif !query.journalAttributes
query.journalAttributes = %w( date summary details )
end
end
end
end
|