taskjuggler 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (415) hide show
  1. data/CHANGELOG +119 -0
  2. data/benchmarks/allocatedSlots.tjp +1602 -0
  3. data/benchmarks/booking.tjp +40 -30
  4. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/css/tjmanual.css +0 -0
  5. data/{test/TestSuite/Scheduler/Correct → benchmarks}/css/tjreport.css +1 -0
  6. data/benchmarks/gantt.tjp +57 -0
  7. data/benchmarks/htmltaskreport.tjp +26 -1
  8. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/details.png +0 -0
  9. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/flag-green.png +0 -0
  10. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/flag-red.png +0 -0
  11. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/flag-yellow.png +0 -0
  12. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/resource.png +0 -0
  13. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/resourcegroup.png +0 -0
  14. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/task.png +0 -0
  15. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/taskgroup.png +0 -0
  16. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/trend-down.png +0 -0
  17. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/trend-flat.png +0 -0
  18. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/icons/trend-up.png +0 -0
  19. data/benchmarks/profile.clt +36082 -0
  20. data/benchmarks/profile.html +58182 -0
  21. data/benchmarks/runbench.rb +6 -0
  22. data/{test/TestSuite/ReportGenerator/Errors → benchmarks}/scripts/wz_tooltip.js +0 -0
  23. data/doc/AppConfig.html +85 -37
  24. data/doc/Arguments.html +11 -1
  25. data/doc/CHANGELOG.html +131 -2
  26. data/doc/COPYING.html +11 -1
  27. data/doc/Object.html +12 -3
  28. data/doc/README.html +11 -1
  29. data/doc/RuntimeConfig.html +11 -1
  30. data/doc/String.html +11 -1
  31. data/doc/StringIO.html +11 -1
  32. data/doc/TaskJuggler.html +250 -219
  33. data/doc/TaskJuggler/Account.html +11 -1
  34. data/doc/TaskJuggler/AccountAttribute.html +11 -1
  35. data/doc/TaskJuggler/AccountScenario.html +11 -1
  36. data/doc/TaskJuggler/Allocation.html +11 -1
  37. data/doc/TaskJuggler/AllocationAttribute.html +11 -1
  38. data/doc/TaskJuggler/AttributeBase.html +11 -1
  39. data/doc/TaskJuggler/AttributeDefinition.html +11 -1
  40. data/doc/TaskJuggler/BatchProcessor.html +11 -1
  41. data/doc/TaskJuggler/Booking.html +11 -1
  42. data/doc/TaskJuggler/BookingListAttribute.html +11 -1
  43. data/doc/TaskJuggler/BooleanAttribute.html +11 -1
  44. data/doc/TaskJuggler/CSVFile.html +12 -2
  45. data/doc/TaskJuggler/CellSettingPattern.html +11 -1
  46. data/doc/TaskJuggler/CellSettingPatternList.html +11 -1
  47. data/doc/TaskJuggler/Charge.html +11 -1
  48. data/doc/TaskJuggler/ChargeListAttribute.html +11 -1
  49. data/doc/TaskJuggler/ChargeSet.html +11 -1
  50. data/doc/TaskJuggler/ChargeSetListAttribute.html +11 -1
  51. data/doc/TaskJuggler/CollisionDetector.html +1063 -0
  52. data/doc/TaskJuggler/ColumnListAttribute.html +11 -1
  53. data/doc/TaskJuggler/ColumnTable.html +11 -1
  54. data/doc/TaskJuggler/Daemon.html +11 -1
  55. data/doc/TaskJuggler/{OnShiftCache.html → DataCache.html} +127 -139
  56. data/doc/TaskJuggler/DataCacheEntry.html +711 -0
  57. data/doc/TaskJuggler/DateAttribute.html +11 -1
  58. data/doc/TaskJuggler/DefinitionListAttribute.html +11 -1
  59. data/doc/TaskJuggler/DependencyListAttribute.html +11 -1
  60. data/doc/TaskJuggler/DurationAttribute.html +16 -5
  61. data/doc/TaskJuggler/FileList.html +11 -1
  62. data/doc/TaskJuggler/FileRecord.html +11 -1
  63. data/doc/TaskJuggler/FixnumAttribute.html +19 -9
  64. data/doc/TaskJuggler/FlagListAttribute.html +29 -19
  65. data/doc/TaskJuggler/FloatAttribute.html +23 -13
  66. data/doc/TaskJuggler/FormatListAttribute.html +19 -9
  67. data/doc/TaskJuggler/GanttChart.html +94 -133
  68. data/doc/TaskJuggler/GanttContainer.html +11 -1
  69. data/doc/TaskJuggler/GanttHeader.html +11 -1
  70. data/doc/TaskJuggler/GanttHeaderScaleItem.html +11 -1
  71. data/doc/TaskJuggler/GanttLine.html +11 -1
  72. data/doc/TaskJuggler/GanttLoadStack.html +11 -1
  73. data/doc/TaskJuggler/GanttMilestone.html +11 -1
  74. data/doc/TaskJuggler/GanttRouter.html +247 -596
  75. data/doc/TaskJuggler/GanttTaskBar.html +11 -1
  76. data/doc/TaskJuggler/HTMLDocument.html +11 -1
  77. data/doc/TaskJuggler/HTMLGraphics.html +11 -1
  78. data/doc/TaskJuggler/Interval.html +11 -1
  79. data/doc/TaskJuggler/IntervalListAttribute.html +33 -23
  80. data/doc/TaskJuggler/JobInfo.html +11 -1
  81. data/doc/TaskJuggler/Journal.html +11 -1
  82. data/doc/TaskJuggler/JournalEntry.html +11 -1
  83. data/doc/TaskJuggler/JournalEntryList.html +11 -1
  84. data/doc/TaskJuggler/KeywordArray.html +11 -1
  85. data/doc/TaskJuggler/KeywordDocumentation.html +16 -6
  86. data/doc/TaskJuggler/Limits.html +11 -1
  87. data/doc/TaskJuggler/Limits/Limit.html +11 -1
  88. data/doc/TaskJuggler/LimitsAttribute.html +24 -14
  89. data/doc/TaskJuggler/ListAttributeBase.html +11 -1
  90. data/doc/TaskJuggler/Log.html +11 -1
  91. data/doc/TaskJuggler/LogFile.html +11 -1
  92. data/doc/TaskJuggler/LogicalAttribute.html +11 -1
  93. data/doc/TaskJuggler/LogicalExpression.html +11 -1
  94. data/doc/TaskJuggler/LogicalExpressionAttribute.html +19 -9
  95. data/doc/TaskJuggler/LogicalFlag.html +11 -1
  96. data/doc/TaskJuggler/LogicalFunction.html +11 -1
  97. data/doc/TaskJuggler/LogicalOperation.html +11 -1
  98. data/doc/TaskJuggler/Macro.html +11 -1
  99. data/doc/TaskJuggler/MacroTable.html +11 -1
  100. data/doc/TaskJuggler/ManagerResponsibilities.html +11 -1
  101. data/doc/TaskJuggler/ManagerStatusRecord.html +11 -1
  102. data/doc/TaskJuggler/Message.html +11 -1
  103. data/doc/TaskJuggler/MessageHandler.html +11 -1
  104. data/doc/TaskJuggler/Navigator.html +12 -2
  105. data/doc/TaskJuggler/NavigatorElement.html +11 -1
  106. data/doc/TaskJuggler/NikuProject.html +11 -1
  107. data/doc/TaskJuggler/NikuReport.html +11 -1
  108. data/doc/TaskJuggler/NikuResource.html +11 -1
  109. data/doc/TaskJuggler/NodeListAttribute.html +17 -7
  110. data/doc/TaskJuggler/PlaceHolderCell.html +722 -0
  111. data/doc/TaskJuggler/ProcessIntercom.html +11 -1
  112. data/doc/TaskJuggler/ProcessIntercomIface.html +11 -1
  113. data/doc/TaskJuggler/Project.html +587 -500
  114. data/doc/TaskJuggler/ProjectBroker.html +11 -1
  115. data/doc/TaskJuggler/ProjectBrokerIface.html +11 -1
  116. data/doc/TaskJuggler/ProjectFileParser.html +205 -192
  117. data/doc/TaskJuggler/ProjectFileScanner.html +230 -207
  118. data/doc/TaskJuggler/ProjectRecord.html +11 -1
  119. data/doc/TaskJuggler/ProjectServer.html +11 -1
  120. data/doc/TaskJuggler/ProjectServerIface.html +11 -1
  121. data/doc/TaskJuggler/PropertyAttribute.html +19 -9
  122. data/doc/TaskJuggler/PropertyList.html +95 -83
  123. data/doc/TaskJuggler/PropertySet.html +11 -1
  124. data/doc/TaskJuggler/PropertyTreeNode.html +11 -1
  125. data/doc/TaskJuggler/Query.html +234 -232
  126. data/doc/TaskJuggler/RTFHandlers.html +11 -1
  127. data/doc/TaskJuggler/RTFNavigator.html +11 -1
  128. data/doc/TaskJuggler/RTFQuery.html +11 -1
  129. data/doc/TaskJuggler/RTFReport.html +11 -1
  130. data/doc/TaskJuggler/RTFReportLink.html +11 -1
  131. data/doc/TaskJuggler/RTFWithQuerySupport.html +11 -1
  132. data/doc/TaskJuggler/RealFormat.html +12 -2
  133. data/doc/TaskJuggler/RealFormatAttribute.html +15 -5
  134. data/doc/TaskJuggler/ReferenceAttribute.html +38 -28
  135. data/doc/TaskJuggler/Report.html +96 -113
  136. data/doc/TaskJuggler/ReportBase.html +161 -152
  137. data/doc/TaskJuggler/ReportContext.html +11 -1
  138. data/doc/TaskJuggler/ReportServer.html +59 -48
  139. data/doc/TaskJuggler/ReportServerIface.html +51 -41
  140. data/doc/TaskJuggler/ReportServerRecord.html +11 -1
  141. data/doc/TaskJuggler/ReportServlet.html +11 -1
  142. data/doc/TaskJuggler/ReportTable.html +46 -25
  143. data/doc/TaskJuggler/ReportTableCell.html +296 -275
  144. data/doc/TaskJuggler/ReportTableColumn.html +14 -4
  145. data/doc/TaskJuggler/ReportTableLegend.html +11 -1
  146. data/doc/TaskJuggler/ReportTableLine.html +19 -7
  147. data/doc/TaskJuggler/Resource.html +12 -2
  148. data/doc/TaskJuggler/ResourceListAttribute.html +40 -30
  149. data/doc/TaskJuggler/ResourceListRE.html +11 -1
  150. data/doc/TaskJuggler/ResourceScenario.html +708 -565
  151. data/doc/TaskJuggler/RichText.html +54 -36
  152. data/doc/TaskJuggler/RichTextAttribute.html +31 -21
  153. data/doc/TaskJuggler/RichTextDocument.html +11 -1
  154. data/doc/TaskJuggler/RichTextElement.html +11 -1
  155. data/doc/TaskJuggler/RichTextFunctionExample.html +11 -1
  156. data/doc/TaskJuggler/RichTextFunctionHandler.html +11 -1
  157. data/doc/TaskJuggler/RichTextImage.html +11 -1
  158. data/doc/TaskJuggler/RichTextIntermediate.html +81 -71
  159. data/doc/TaskJuggler/RichTextParser.html +88 -33
  160. data/doc/TaskJuggler/RichTextScanner.html +45 -35
  161. data/doc/TaskJuggler/RichTextSnip.html +11 -1
  162. data/doc/TaskJuggler/RichTextSyntaxRules.html +436 -389
  163. data/doc/TaskJuggler/Scenario.html +11 -1
  164. data/doc/TaskJuggler/ScenarioData.html +11 -1
  165. data/doc/TaskJuggler/ScenarioListAttribute.html +23 -13
  166. data/doc/TaskJuggler/Scoreboard.html +92 -73
  167. data/doc/TaskJuggler/SheetHandlerBase.html +11 -1
  168. data/doc/TaskJuggler/SheetReceiver.html +11 -1
  169. data/doc/TaskJuggler/SheetSender.html +11 -1
  170. data/doc/TaskJuggler/Shift.html +11 -1
  171. data/doc/TaskJuggler/ShiftAssignment.html +11 -1
  172. data/doc/TaskJuggler/ShiftAssignments.html +11 -1
  173. data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +24 -14
  174. data/doc/TaskJuggler/ShiftScenario.html +11 -1
  175. data/doc/TaskJuggler/SimpleQueryExpander.html +11 -1
  176. data/doc/TaskJuggler/SortListAttribute.html +21 -11
  177. data/doc/TaskJuggler/SourceFileInfo.html +11 -1
  178. data/doc/TaskJuggler/StatusSheetReceiver.html +11 -1
  179. data/doc/TaskJuggler/StatusSheetReport.html +11 -1
  180. data/doc/TaskJuggler/StatusSheetSender.html +112 -11
  181. data/doc/TaskJuggler/StringAttribute.html +23 -13
  182. data/doc/TaskJuggler/SymbolAttribute.html +19 -9
  183. data/doc/TaskJuggler/SyntaxReference.html +80 -71
  184. data/doc/TaskJuggler/TOCEntry.html +11 -1
  185. data/doc/TaskJuggler/TSResourceRecord.html +11 -1
  186. data/doc/TaskJuggler/TSTaskRecord.html +11 -1
  187. data/doc/TaskJuggler/TableColumnDefinition.html +11 -1
  188. data/doc/TaskJuggler/TableOfContents.html +11 -1
  189. data/doc/TaskJuggler/TableReport.html +422 -411
  190. data/doc/TaskJuggler/Task.html +11 -1
  191. data/doc/TaskJuggler/TaskDependency.html +11 -1
  192. data/doc/TaskJuggler/TaskListAttribute.html +33 -23
  193. data/doc/TaskJuggler/TaskListRE.html +11 -1
  194. data/doc/TaskJuggler/TaskScenario.html +2007 -1919
  195. data/doc/TaskJuggler/TextFormatter.html +11 -1
  196. data/doc/TaskJuggler/TextParser.html +421 -612
  197. data/doc/TaskJuggler/TextParser/Pattern.html +410 -211
  198. data/doc/TaskJuggler/TextParser/Rule.html +224 -152
  199. data/doc/TaskJuggler/TextParser/StackElement.html +190 -28
  200. data/doc/TaskJuggler/TextParser/State.html +989 -0
  201. data/doc/TaskJuggler/TextParser/StateTransition.html +782 -0
  202. data/doc/TaskJuggler/TextParser/TextParserResultArray.html +25 -14
  203. data/doc/TaskJuggler/TextParser/TokenDoc.html +11 -1
  204. data/doc/TaskJuggler/TextReport.html +11 -1
  205. data/doc/TaskJuggler/TextScanner.html +285 -273
  206. data/doc/TaskJuggler/TextScanner/BufferStreamHandle.html +17 -7
  207. data/doc/TaskJuggler/TextScanner/FileStreamHandle.html +24 -14
  208. data/doc/TaskJuggler/TextScanner/MacroStackEntry.html +11 -1
  209. data/doc/TaskJuggler/TextScanner/StreamHandle.html +64 -52
  210. data/doc/TaskJuggler/TimeSheet.html +11 -1
  211. data/doc/TaskJuggler/TimeSheetReceiver.html +11 -1
  212. data/doc/TaskJuggler/TimeSheetRecord.html +11 -1
  213. data/doc/TaskJuggler/TimeSheetReport.html +11 -1
  214. data/doc/TaskJuggler/TimeSheetSender.html +11 -1
  215. data/doc/TaskJuggler/TimeSheetSummary.html +11 -1
  216. data/doc/TaskJuggler/TimeSheets.html +11 -1
  217. data/doc/TaskJuggler/Tj3AppBase.html +11 -1
  218. data/doc/TaskJuggler/Tj3Client.html +11 -1
  219. data/doc/TaskJuggler/Tj3Daemon.html +11 -1
  220. data/doc/TaskJuggler/Tj3SheetAppBase.html +11 -1
  221. data/doc/TaskJuggler/Tj3SsReceiver.html +11 -1
  222. data/doc/TaskJuggler/Tj3SsSender.html +11 -1
  223. data/doc/TaskJuggler/Tj3TsReceiver.html +11 -1
  224. data/doc/TaskJuggler/Tj3TsSender.html +11 -1
  225. data/doc/TaskJuggler/Tj3TsSummary.html +11 -1
  226. data/doc/TaskJuggler/TjException.html +11 -1
  227. data/doc/TaskJuggler/TjTime.html +474 -324
  228. data/doc/TaskJuggler/TjpExample.html +11 -1
  229. data/doc/TaskJuggler/TjpExportRE.html +11 -1
  230. data/doc/TaskJuggler/TjpSyntaxRules.html +3731 -3662
  231. data/doc/TaskJuggler/URLParameter.html +11 -1
  232. data/doc/TaskJuggler/UserManual.html +11 -1
  233. data/doc/TaskJuggler/VimSyntax.html +11 -1
  234. data/doc/TaskJuggler/WebServer.html +11 -1
  235. data/doc/TaskJuggler/WorkingHours.html +295 -221
  236. data/doc/TaskJuggler/WorkingHoursAttribute.html +11 -1
  237. data/doc/TaskJuggler/XMLBlob.html +11 -1
  238. data/doc/TaskJuggler/XMLComment.html +11 -1
  239. data/doc/TaskJuggler/XMLDocument.html +11 -1
  240. data/doc/TaskJuggler/XMLElement.html +11 -1
  241. data/doc/TaskJuggler/XMLNamedText.html +11 -1
  242. data/doc/TaskJuggler/XMLText.html +11 -1
  243. data/doc/index.html +694 -624
  244. data/doc/lib/AppConfig_rb.html +1 -1
  245. data/doc/lib/Attributes_rb.html +1 -1
  246. data/doc/lib/Booking_rb.html +1 -1
  247. data/doc/lib/DataCache_rb.html +69 -0
  248. data/doc/lib/KeywordDocumentation_rb.html +1 -1
  249. data/doc/lib/ProjectFileParser_rb.html +1 -1
  250. data/doc/lib/ProjectFileScanner_rb.html +1 -1
  251. data/doc/lib/Project_rb.html +1 -1
  252. data/doc/lib/PropertyList_rb.html +1 -1
  253. data/doc/lib/Query_rb.html +1 -1
  254. data/doc/lib/RealFormat_rb.html +1 -1
  255. data/doc/lib/ResourceScenario_rb.html +1 -1
  256. data/doc/lib/Resource_rb.html +1 -1
  257. data/doc/lib/RichTextParser_rb.html +1 -1
  258. data/doc/lib/RichTextScanner_rb.html +1 -1
  259. data/doc/lib/RichTextSyntaxRules_rb.html +1 -1
  260. data/doc/lib/RichText_rb.html +1 -1
  261. data/doc/lib/Scoreboard_rb.html +1 -1
  262. data/doc/lib/StatusSheetSender_rb.html +1 -1
  263. data/doc/lib/SyntaxReference_rb.html +1 -1
  264. data/doc/lib/TaskJuggler_rb.html +1 -1
  265. data/doc/lib/TaskScenario_rb.html +3 -1
  266. data/doc/lib/TextParser/Pattern_rb.html +3 -1
  267. data/doc/lib/TextParser/Rule_rb.html +3 -1
  268. data/doc/lib/TextParser/StackElement_rb.html +3 -1
  269. data/doc/lib/TextParser/State_rb.html +65 -0
  270. data/doc/lib/TextParser_rb.html +1 -1
  271. data/doc/lib/TextScanner_rb.html +1 -1
  272. data/doc/lib/Tj3Config_rb.html +1 -1
  273. data/doc/lib/TjTime_rb.html +1 -1
  274. data/doc/lib/TjpSyntaxRules_rb.html +1 -1
  275. data/doc/lib/WorkingHours_rb.html +3 -1
  276. data/doc/lib/daemon/ReportServer_rb.html +1 -1
  277. data/doc/lib/reports/CSVFile_rb.html +1 -1
  278. data/doc/lib/reports/CollisionDetector_rb.html +67 -0
  279. data/doc/lib/reports/GanttChart_rb.html +1 -1
  280. data/doc/lib/reports/GanttRouter_rb.html +3 -1
  281. data/doc/lib/reports/Navigator_rb.html +1 -1
  282. data/doc/lib/reports/ReportBase_rb.html +1 -1
  283. data/doc/lib/reports/ReportTableCell_rb.html +1 -1
  284. data/doc/lib/reports/ReportTableColumn_rb.html +1 -1
  285. data/doc/lib/reports/ReportTableLine_rb.html +1 -1
  286. data/doc/lib/reports/ReportTable_rb.html +1 -1
  287. data/doc/lib/reports/Report_rb.html +1 -1
  288. data/doc/lib/reports/TableReport_rb.html +1 -1
  289. data/doc/lib/taskjuggler3_rb.html +1 -1
  290. data/examples/tutorial.tjp +1 -2
  291. data/lib/AppConfig.rb +10 -4
  292. data/lib/Attributes.rb +4 -4
  293. data/lib/DataCache.rb +124 -0
  294. data/lib/KeywordDocumentation.rb +5 -5
  295. data/lib/Project.rb +54 -10
  296. data/lib/ProjectFileParser.rb +10 -9
  297. data/lib/ProjectFileScanner.rb +38 -25
  298. data/lib/PropertyList.rb +6 -4
  299. data/lib/Query.rb +0 -8
  300. data/lib/RealFormat.rb +1 -1
  301. data/lib/Resource.rb +1 -1
  302. data/lib/ResourceScenario.rb +96 -31
  303. data/lib/RichText.rb +17 -5
  304. data/lib/RichTextParser.rb +22 -9
  305. data/lib/RichTextScanner.rb +34 -34
  306. data/lib/RichTextSyntaxRules.rb +41 -36
  307. data/lib/Scoreboard.rb +16 -7
  308. data/lib/StatusSheetSender.rb +63 -0
  309. data/lib/SyntaxReference.rb +9 -10
  310. data/lib/TaskJuggler.rb +28 -4
  311. data/lib/TaskScenario.rb +66 -19
  312. data/lib/TextParser.rb +219 -384
  313. data/lib/TextParser/Pattern.rb +168 -49
  314. data/lib/TextParser/Rule.rb +33 -17
  315. data/lib/TextParser/StackElement.rb +42 -2
  316. data/lib/TextParser/State.rb +175 -0
  317. data/lib/TextScanner.rb +19 -15
  318. data/lib/Tj3Config.rb +1 -1
  319. data/lib/TjTime.rb +111 -3
  320. data/lib/TjpSyntaxRules.rb +122 -66
  321. data/lib/WorkingHours.rb +91 -186
  322. data/lib/daemon/ReportServer.rb +3 -2
  323. data/lib/reports/CSVFile.rb +1 -1
  324. data/lib/reports/CollisionDetector.rb +177 -0
  325. data/lib/reports/GanttChart.rb +25 -41
  326. data/lib/reports/GanttRouter.rb +104 -233
  327. data/lib/reports/Navigator.rb +1 -1
  328. data/lib/reports/Report.rb +9 -33
  329. data/lib/reports/ReportBase.rb +0 -1
  330. data/lib/reports/ReportTable.rb +19 -8
  331. data/lib/reports/ReportTableCell.rb +61 -25
  332. data/lib/reports/ReportTableColumn.rb +2 -2
  333. data/lib/reports/ReportTableLine.rb +4 -2
  334. data/lib/reports/TableReport.rb +1 -0
  335. data/lib/taskjuggler3.rb +0 -1
  336. data/manual/Installation +7 -3
  337. data/manual/Intro +12 -10
  338. data/manual/The_TaskJuggler_Syntax +4 -4
  339. data/test/TestSuite/CSV-Reports/celltext-Reference.csv +14 -14
  340. data/test/TestSuite/CSV-Reports/genrefs +1 -1
  341. data/test/TestSuite/CSV-Reports/resourcereport-Reference.csv +4 -4
  342. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks-Reference.csv +22 -22
  343. data/test/TestSuite/CSV-Reports/sortByTree-Reference.csv +14 -14
  344. data/test/TestSuite/CSV-Reports/sortBy_duration.down-Reference.csv +14 -14
  345. data/test/TestSuite/CSV-Reports/sortBy_effort.up-Reference.csv +14 -14
  346. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down-Reference.csv +14 -14
  347. data/test/TestSuite/CSV-Reports/taskreport-Reference.csv +14 -14
  348. data/test/TestSuite/CSV-Reports/taskreport_with_resources-Reference.csv +32 -24
  349. data/test/TestSuite/CSV-Reports/weekly-Reference.csv +13 -0
  350. data/test/TestSuite/CSV-Reports/weekly.tjp +9 -0
  351. data/test/TestSuite/HTML-Reports/css/tjreport.css +7 -2
  352. data/test/TestSuite/HTML-Reports/depArrows.html +839 -830
  353. data/test/TestSuite/HTML-Reports/depArrows.tjp +12 -12
  354. data/test/TestSuite/HTML-Reports/profile.html +37581 -0
  355. data/test/TestSuite/ReportGenerator/Errors/no_report_defined.tjp +7 -0
  356. data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.tjp +1 -1
  357. data/test/TestSuite/StatusSheets/TimeSheets/2002-03-01/missing-reports +2 -0
  358. data/test/TestSuite/StatusSheets/run +2 -0
  359. data/test/TestSuite/Syntax/Correct/Booking.tjp +13 -5
  360. data/test/TestSuite/Syntax/Correct/ResourceRoot.tjp +21 -0
  361. data/test/TestSuite/Syntax/Correct/RollupResource.tjp +21 -0
  362. data/test/TestSuite/Syntax/Correct/TaskRoot.tjp +1 -1
  363. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
  364. data/test/TestSuite/Syntax/Errors/include_before_project.tjp +2 -0
  365. data/test/TestSuite/Syntax/Errors/no_reduce.tjp +6 -0
  366. data/test/TestSuite/Syntax/Errors/unsupported_token.tjp +1 -1
  367. data/test/TestSuite/TimeSheets/run +1 -1
  368. data/test/test_CSV-Reports.rb +2 -4
  369. data/test/test_CollisionDetector.rb +85 -0
  370. data/test/test_Project.rb +2 -2
  371. data/test/test_ProjectFileScanner.rb +73 -31
  372. data/test/test_Query.rb +2 -2
  373. data/test/test_ReportGenerator.rb +1 -1
  374. data/test/test_RichText.rb +4 -4
  375. data/test/test_WorkingHours.rb +150 -11
  376. metadata +75 -67
  377. data/test/TestSuite/ReportGenerator/Errors/css/tjreport.css +0 -407
  378. data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.html +0 -26
  379. data/test/TestSuite/Scheduler/Correct/Allocate.html +0 -3210
  380. data/test/TestSuite/Scheduler/Correct/Container.html +0 -349
  381. data/test/TestSuite/Scheduler/Correct/Limits.html +0 -4964
  382. data/test/TestSuite/Scheduler/Correct/Shift.html +0 -1719
  383. data/test/TestSuite/Scheduler/Correct/Shift2.html +0 -476
  384. data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +0 -66
  385. data/test/TestSuite/Scheduler/Correct/icons/details.png +0 -0
  386. data/test/TestSuite/Scheduler/Correct/icons/flag-green.png +0 -0
  387. data/test/TestSuite/Scheduler/Correct/icons/flag-red.png +0 -0
  388. data/test/TestSuite/Scheduler/Correct/icons/flag-yellow.png +0 -0
  389. data/test/TestSuite/Scheduler/Correct/icons/resource.png +0 -0
  390. data/test/TestSuite/Scheduler/Correct/icons/resourcegroup.png +0 -0
  391. data/test/TestSuite/Scheduler/Correct/icons/task.png +0 -0
  392. data/test/TestSuite/Scheduler/Correct/icons/taskgroup.png +0 -0
  393. data/test/TestSuite/Scheduler/Correct/icons/trend-down.png +0 -0
  394. data/test/TestSuite/Scheduler/Correct/icons/trend-flat.png +0 -0
  395. data/test/TestSuite/Scheduler/Correct/icons/trend-up.png +0 -0
  396. data/test/TestSuite/Scheduler/Correct/scripts/wz_tooltip.js +0 -1301
  397. data/test/TestSuite/Scheduler/Errors/css/tjmanual.css +0 -66
  398. data/test/TestSuite/Scheduler/Errors/css/tjreport.css +0 -407
  399. data/test/TestSuite/Scheduler/Errors/icons/details.png +0 -0
  400. data/test/TestSuite/Scheduler/Errors/icons/flag-green.png +0 -0
  401. data/test/TestSuite/Scheduler/Errors/icons/flag-red.png +0 -0
  402. data/test/TestSuite/Scheduler/Errors/icons/flag-yellow.png +0 -0
  403. data/test/TestSuite/Scheduler/Errors/icons/resource.png +0 -0
  404. data/test/TestSuite/Scheduler/Errors/icons/resourcegroup.png +0 -0
  405. data/test/TestSuite/Scheduler/Errors/icons/task.png +0 -0
  406. data/test/TestSuite/Scheduler/Errors/icons/taskgroup.png +0 -0
  407. data/test/TestSuite/Scheduler/Errors/icons/trend-down.png +0 -0
  408. data/test/TestSuite/Scheduler/Errors/icons/trend-flat.png +0 -0
  409. data/test/TestSuite/Scheduler/Errors/icons/trend-up.png +0 -0
  410. data/test/TestSuite/Scheduler/Errors/scripts/wz_tooltip.js +0 -1301
  411. data/test/TestSuite/StatusSheets/resrep.tji +0 -7
  412. data/test/TestSuite/StatusSheets/tj3d.log +0 -312
  413. data/test/TestSuite/Syntax/Correct/Managers.html +0 -263
  414. data/test/TestSuite/TimeSheets/acceptable_intervals +0 -1
  415. data/test/TestSuite/TimeSheets/statussheets.log +0 -1
data/lib/WorkingHours.rb CHANGED
@@ -11,140 +11,31 @@
11
11
  #
12
12
 
13
13
  require 'Interval'
14
+ require 'Scoreboard'
14
15
 
15
16
  class TaskJuggler
16
17
 
17
- # This cache class is used to speedup accesses to the frequently used
18
- # WorkingHours::onShift? function. It saves the result the first time the
19
- # function is called for a particular date and working hour set and returns
20
- # it on subsequent calls again. Each partucular set of working hours needs
21
- # its separate cache. The OnShiftCache object is shared amongst all
22
- # WorkingHours objects so that WorkingHours objects with identical working
23
- # hours can share the cache.
24
- class OnShiftCache
25
-
26
- # Create the OnShiftCache object. There should be only one for the
27
- # application.
28
- def initialize
29
- @caches = []
30
- @workingHoursTable = []
31
- # The cache is an array with entries for each date. To minimize the
32
- # necessary storage space, we need to guess the smallest used date
33
- # (which gets index 0 then) and the smallest distance between dates.
34
- @minDate = nil
35
- # We assume a timing resolution of 1 hour (the TaskJuggler default)
36
- # first.
37
- @minDateDelta = 60 * 60
38
- end
39
-
40
- # Register the WorkingHours object with the caches. The function will
41
- # return the actual cache used for this particular set of working hours.
42
- # The WorkingHours object may not change its working hours after this
43
- # call. The returned cache reference is used as a handle for subsequent
44
- # OnShiftCache::set and OnShiftCache::get calls.
45
- def register(wh)
46
- # Search the list of already registered caches for an identical set of
47
- # WorkingHours. In case one is found, return the reference to this
48
- # cache.
49
- @workingHoursTable.length.times do |i|
50
- if @workingHoursTable[i] == wh
51
- return @caches[i]
52
- end
53
- end
54
- # If this is a new set of WorkingHours we create a new cache for it.
55
- @workingHoursTable << WorkingHours.new(wh)
56
- @caches << []
57
- @caches.last
58
- end
59
-
60
- # Set the +value+ for a given +cache+ and +date+.
61
- def set(cache, date, value)
62
- cache[dateToIndex(date)] = value
63
- end
64
-
65
- # Get the value for a given +cache+ and +date+.
66
- def get(cache, date)
67
- cache[dateToIndex(date)]
68
- end
69
-
70
- private
71
-
72
- # When the @minDate or @minDateDelta values need to be changed, we have to
73
- # clear all the caches again.
74
- def resetCaches
75
- @caches.each { |c| c.clear }
76
- end
77
-
78
- # Convert a TjTime +date+ to an index in the cache Array. To optimize the
79
- # size of the cache, we have to guess the smallest used date and the
80
- # regular distance between the date values. If we have to correct these
81
- # guessed values, we have to clear the caches.
82
- def dateToIndex(date)
83
- if @minDate.nil? || date < @minDate
84
- @minDate = date
85
- resetCaches
86
- end
87
- startDate = date - @minDate
88
- div, mod = startDate.divmod(@minDateDelta)
89
- if mod != 0
90
- resetCaches
91
- # We have to guess the timingresolution of the project here. Possible
92
- # values are 5, 10, 15, 20, 30 or 60 minutes.
93
- case @minDateDelta / 60
94
- when 60
95
- @minDateDelta = 30
96
- when 30
97
- @minDateDelta = 20
98
- when 20
99
- @minDateDelta = 15
100
- when 15
101
- @minDateDelta = 10
102
- when 10
103
- @minDateDelta = 5
104
- else
105
- raise "Illegal timing resolution!"
106
- end
107
- @minDateDelta *= 60
108
- div = startDate / @minDateDelta
109
- end
110
-
111
- div
112
- end
113
-
114
- end
115
-
116
18
  # Class to store the working hours for each day of the week. The working hours
117
19
  # are stored as Arrays of Fixnum intervals for each day of the week. A day off
118
20
  # is modelled as empty Array for that week day. The start end end times of
119
21
  # each working period are stored as seconds after midnight.
120
22
  class WorkingHours
121
23
 
122
- attr_reader :days
123
- attr_accessor :timezone
124
-
125
- # All WorkingHours objects share the same cache to speedup the onShift?
126
- # method.
127
- @@onShiftCache = OnShiftCache.new
24
+ attr_reader :days, :startDate, :endDate, :slotDuration, :timezone,
25
+ :scoreboard
128
26
 
129
27
  # Create a new WorkingHours object. The method accepts a reference to an
130
28
  # existing WorkingHours object in +wh+. When it's present, the new object
131
- # will be a deep copy of the given object.
132
- def initialize(wh = nil)
29
+ # will be a deep copy of the given object. The Scoreboard object is _not_
30
+ # deep copied. It will be copied on write.
31
+ def initialize(arg1 = nil, startDate = nil, endDate = nil)
133
32
  # One entry for every day of the week. Sunday === 0.
134
33
  @days = Array.new(7, [])
135
- @cache = nil
34
+ @scoreboard = nil
136
35
 
137
- if wh.nil?
138
- # Create a new object with default working hours.
139
- @timezone = nil
140
- # Set the default working hours. Monday to Friday 9am - 12pm, 1pm - 6pm.
141
- # Saturday and Sunday are days off.
142
- 1.upto(5) do |day|
143
- @days[day] = [ [ 9 * 60 * 60, 12 * 60 * 60 ],
144
- [ 13 * 60 * 60, 18 * 60 * 60 ] ]
145
- end
146
- else
147
- # Copy the values from the given object.
36
+ if arg1.is_a?(WorkingHours)
37
+ # Create a copy of the passed WorkingHours object.
38
+ wh = arg1
148
39
  @timezone = wh.timezone
149
40
  7.times do |day|
150
41
  hours = []
@@ -153,13 +44,37 @@ class TaskJuggler
153
44
  end
154
45
  setWorkingHours(day, hours)
155
46
  end
47
+ @startDate = wh.startDate
48
+ @endDate = wh.endDate
49
+ @slotDuration = wh.slotDuration
50
+ @scoreboard = wh.scoreboard
51
+ else
52
+ slotDuration = arg1
53
+ if arg1.nil? || startDate.nil? || endDate.nil?
54
+ raise "You must supply values for slotDuration, start and end dates"
55
+ end
56
+ @startDate = startDate
57
+ @endDate = endDate
58
+ @slotDuration = slotDuration
59
+
60
+ # Create a new object with default working hours.
61
+ @timezone = nil
62
+ # Set the default working hours. Monday to Friday 9am - 12pm, 1pm - 6pm.
63
+ # Saturday and Sunday are days off.
64
+ 1.upto(5) do |day|
65
+ @days[day] = [ [ 9 * 60 * 60, 12 * 60 * 60 ],
66
+ [ 13 * 60 * 60, 18 * 60 * 60 ] ]
67
+ end
156
68
  end
157
69
  end
158
70
 
159
71
  # Return true of the given WorkingHours object +wh+ is identical to this
160
72
  # object.
161
73
  def ==(wh)
162
- return false if wh.nil? || @timezone != wh.timezone
74
+ return false if wh.nil? || @timezone != wh.timezone ||
75
+ @startDate != wh.startDate ||
76
+ @endDate != wh.endDate ||
77
+ @slotDuration != wh.slotDuration
163
78
 
164
79
  7.times do |d|
165
80
  return false if @days[d].length != wh.days[d].length
@@ -178,10 +93,8 @@ class TaskJuggler
178
93
  # specifies the time of day as minutes after midnight. The first value is
179
94
  # the start time of the interval, the second the end time.
180
95
  def setWorkingHours(dayOfWeek, intervals)
181
- if @cache
182
- raise 'You cannot change the working hours after onShift? has been ' +
183
- 'called.'
184
- end
96
+ # Changing the working hours requires the score board to be regenerated.
97
+ @scoreboard = nil
185
98
 
186
99
  # Legal values range from 0 Sunday to 6 Saturday.
187
100
  if dayOfWeek < 0 || dayOfWeek > 6
@@ -199,6 +112,13 @@ class TaskJuggler
199
112
  @days[dayOfWeek] = intervals
200
113
  end
201
114
 
115
+ # Set the time zone _zone_ for the working hours. This will reset the
116
+ # @scoreboard.
117
+ def timezone=(zone)
118
+ @scoreboard = nil
119
+ @timezone = zone
120
+ end
121
+
202
122
  # Return the working hour intervals for a given day of the week.
203
123
  # +dayOfWeek+ must 0 for Sunday, 1 for Monday and so on. The result is an
204
124
  # Array that contains Arrays of 2 Fixnums.
@@ -208,64 +128,24 @@ class TaskJuggler
208
128
 
209
129
  # Return true if _date_ is within the defined working hours.
210
130
  def onShift?(date)
211
- @cache = @@onShiftCache.register(self) unless @cache
212
-
213
- # If we have the result cached already, return it.
214
- unless (os = @@onShiftCache.get(@cache, date)).nil?
215
- return os
216
- end
217
-
218
- # The date is in UTC. The weekday needs to be calculated according to the
219
- # timezone of the project.
220
- projectDate = toLocaltime(date)
221
- dow = projectDate.wday
222
-
223
- # The working hours need to be put into the proper time zone.
224
- localDate = toLocaltime(date, @timezone)
225
- secondsOfDay = localDate.secondsOfDay
226
-
227
- @days[dow].each do |iv|
228
- # Check the working hours of that day if they overlap with +date+.
229
- if iv[0] <= secondsOfDay && secondsOfDay < iv[1]
230
- # Store the result in the cache.
231
- @@onShiftCache.set(@cache, date, true)
232
- return true
233
- end
234
- end
131
+ initScoreboard unless @scoreboard
235
132
 
236
- # Store the result in the cache.
237
- @@onShiftCache.set(@cache, date, false)
238
- false
133
+ @scoreboard.get(date)
239
134
  end
240
135
 
241
- # This function does not belong here! It should be handled via the
242
- # ShiftAssignment.
136
+ # Return true only if all slots in the _interval_ are offhour slots.
243
137
  def timeOff?(interval)
244
- t = interval.start.midnight
245
- while t < interval.end
246
- dow = t.wday
247
- unless @days[dow].empty?
248
- dayStart = t < interval.start ? interval.start.secondsOfDay :
249
- t.secondsOfDay
250
- dayEnd = t.sameTimeNextDay > interval.end ? interval.end.secondsOfDay :
251
- 60 * 60 * 24;
252
- @days[dow].each do |iv|
253
- return false if (dayStart <= iv[0] && iv[0] < dayEnd) ||
254
- (iv[0] <= dayStart && dayStart < iv[1])
255
- end
256
- end
257
- t = t.sameTimeNextDay
138
+ initScoreboard unless @scoreboard
139
+
140
+ startIdx = @scoreboard.dateToIdx(interval.start, true)
141
+ endIdx = @scoreboard.dateToIdx(interval.end, true)
142
+
143
+ startIdx.upto(endIdx - 1) do |i|
144
+ return false if @scoreboard[i]
258
145
  end
259
146
  true
260
147
  end
261
148
 
262
- # Probably should be put into ShiftAssignment as well.
263
- def dayOff?(date)
264
- projectDate = toLocaltime(date)
265
- dow = projectDate.wday
266
- @days[dow].empty?
267
- end
268
-
269
149
  # Returns the time interval settings for each day in a human readable form.
270
150
  def to_s
271
151
  dayNames = %w( Sun Mon Tue Wed Thu Fri Sat )
@@ -295,26 +175,51 @@ class TaskJuggler
295
175
 
296
176
  private
297
177
 
298
- # Convert a UTC date into the corresponding date in the local time zone.
299
- # This is either the current system setting or the time zone specified by
300
- # _tz_.
301
- def toLocaltime(date, tz = nil)
178
+ def initScoreboard
179
+ # The scoreboard is an Array of True/False values. It spans a certain
180
+ # time period with one entry per time slot.
181
+ @scoreboard = Scoreboard.new(@startDate, @endDate, @slotDuration, false)
182
+
302
183
  oldTimezone = nil
303
184
  # Set environment variable TZ to appropriate time zone
304
185
  if @timezone
305
- oldTimezone = ENV['tz']
306
- ENV['tz'] = @timezone
186
+ oldTimezone = ENV['TZ']
187
+ ENV['TZ'] = @timezone
307
188
  end
308
189
 
309
- localDate = date.dup
310
- localDate.localtime
190
+ date = @startDate
191
+ @scoreboard.collect! do |slot|
192
+ localDate = date.dup
193
+ localDate.localtime
194
+
195
+ # The date is in UTC. The weekday needs to be calculated according to
196
+ # the local timezone.
197
+ weekday = localDate.wday
198
+ secondsOfDay = localDate.secondsOfDay
199
+
200
+ result = false
201
+ @days[weekday].each do |iv|
202
+ # Check the working hours of that day if they overlap with +date+.
203
+ if iv[0] <= secondsOfDay && secondsOfDay < iv[1]
204
+ # The time slot is a working slot.
205
+ result = true
206
+ break
207
+ end
208
+ end
209
+ # Calculate date of next scoreboard slot
210
+ date += @slotDuration
311
211
 
312
- # Restore environment
313
- if oldTimezone
314
- ENV['tz'] = oldTimezone
212
+ result
315
213
  end
316
214
 
317
- localDate
215
+ # Restore environment
216
+ if @timezone
217
+ if oldTimezone
218
+ ENV['TZ'] = oldTimezone
219
+ else
220
+ ENV.delete('TZ')
221
+ end
222
+ end
318
223
  end
319
224
 
320
225
  end
@@ -98,7 +98,7 @@ class TaskJuggler
98
98
 
99
99
  def addFile(file)
100
100
  begin
101
- @tj.parseFile(file, 'properties')
101
+ @tj.parseFile(file, :properties)
102
102
  rescue TjException
103
103
  return false
104
104
  end
@@ -108,8 +108,9 @@ class TaskJuggler
108
108
 
109
109
  def generateReport(id, regExpMode, dynamicAttributes)
110
110
  @log.info("Generating report #{id}")
111
+ startTime = Time.now
111
112
  if (ok = @tj.generateReport(id, regExpMode, dynamicAttributes))
112
- @log.debug("Report #{id} generated")
113
+ @log.info("Report #{id} generated in #{Time.now - startTime} seconds")
113
114
  else
114
115
  @log.error("Report generation of #{id} failed")
115
116
  end
@@ -55,7 +55,7 @@ class TaskJuggler
55
55
  file = File.open(fileName, 'r')
56
56
  end
57
57
 
58
- @data = parse(file.read)
58
+ parse(file.read)
59
59
 
60
60
  file.close unless fileName == '.'
61
61
  @data
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = CollisionDetector.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ require 'reports/HTMLGraphics'
14
+
15
+ class TaskJuggler
16
+
17
+ class CollisionDetector
18
+
19
+ include HTMLGraphics
20
+
21
+ def initialize(width, height)
22
+ @width = width
23
+ @height = height
24
+
25
+ # The zones are stored as Arrays of line segments. Horizontal blocks are
26
+ # stored separately from vertical blocks. Blocked segments for a
27
+ # particular x coordinate are stored in @vLines, for y coordinates in
28
+ # @hLines. Each entry is an Array of [ start, end ] values that describe
29
+ # the blocked segments of that particular line. Start and end point are
30
+ # part of the segment. A listed segment will not be overwritten during
31
+ # routing.
32
+ @hLines = Array.new(@height) { |i| i = [] }
33
+ @vLines = Array.new(@width) { |i| i = [] }
34
+ end
35
+
36
+ # This function registers an area as don't-cross-zone. The rectangular zone
37
+ # is described by _x_, _y_, _w_ and _h_. If _horiz_ is true, the zone will
38
+ # be blocked for horizontal lines, if _vert_ is true the zone will be
39
+ # blocked for vertical lines.
40
+ def addBlockedZone(x, y, w, h, horiz, vert)
41
+ # Clip the input rectangle to fit within the handled area of this router.
42
+ x = clip(x.to_i, @width - 1)
43
+ y = clip(y.to_i, @height - 1)
44
+ w = clip(w.to_i, @width - x)
45
+ h = clip(h.to_i, @height - y)
46
+
47
+ # We can ignore empty zones.
48
+ return if w == 0 || h == 0
49
+
50
+ # Break the rectangle into line segments and add them to the appropriate
51
+ # line Arrays.
52
+ if horiz
53
+ y.upto(y + h - 1) do |i|
54
+ addSegment(@hLines[i], [ x, x + w - 1 ])
55
+ end
56
+ end
57
+ if vert
58
+ x.upto(x + w - 1) do |i|
59
+ addSegment(@vLines[i], [ y, y + h - 1 ])
60
+ end
61
+ end
62
+ end
63
+
64
+ # Find out if there is a block at line _pos_ for the start/end coordinates
65
+ # given by _segment_. If _horizontal_ is true, we are looking for a
66
+ # horizontal block, otherwise a vertical.
67
+ def collision?(pos, segment, horizontal)
68
+ line = (horizontal ? @hLines : @vLines)[pos]
69
+
70
+ # For complex charts, the segment lists can be rather long. We use a
71
+ # binary search to be fairly efficient.
72
+ l = 0
73
+ u = line.length - 1
74
+ while l <= u
75
+ # Look at the element in the middle between l and u.
76
+ p = l + ((u - l) / 2).to_i
77
+ return true if overlaps?(line[p], segment)
78
+
79
+ if segment[0] > line[p][1]
80
+ # The potential target is above p. Adjust lower bound.
81
+ l = p + 1
82
+ else
83
+ # The potential target is below p. Adjust upper bound.
84
+ u = p - 1
85
+ end
86
+ end
87
+ false
88
+ end
89
+
90
+ def to_html
91
+ html = []
92
+ # Change this to determine what zones you want to see.
93
+ if true
94
+ # Show vertical blocks
95
+ x = 0
96
+ @vLines.each do |line|
97
+ line.each do |segment|
98
+ html << lineToHTML(x, segment[0], x, segment[1], 'white')
99
+ end
100
+ x += 1
101
+ end
102
+ else
103
+ # Show horizontal blocks
104
+ y = 0
105
+ @hLines.each do |line|
106
+ line.each do |segment|
107
+ html << lineToHTML(segment[0], y, segment[1], y, 'white')
108
+ end
109
+ y += 1
110
+ end
111
+ end
112
+ html
113
+ end
114
+
115
+ private
116
+
117
+ # Simple utility function to limit _v_ between 0 and _max_.
118
+ def clip(v, max)
119
+ v = 0 if v < 0
120
+ v = max if v > max
121
+ v
122
+ end
123
+
124
+ # This function adds a new segment to the line. In case the new segment
125
+ # overlaps with or directly attaches to existing segments, these segments
126
+ # are merged into a single segment.
127
+ def addSegment(line, newSegment)
128
+ # Search for overlaping or directly attaching segments in the list.
129
+ i = 0
130
+ while (i < line.length)
131
+ segment = line[i]
132
+ if mergeable?(newSegment, segment)
133
+ # Merge exiting segment into new one
134
+ merge(newSegment, segment)
135
+ # Remove the old one from the list and restart with the newly created
136
+ # one at the same position.
137
+ line.delete_at(i)
138
+ next
139
+ elsif segment[0] > newSegment[1]
140
+ # Segments are stored in ascending order. If the next segment starts
141
+ # with a larger value, we insert the new segment before the larger
142
+ # one.
143
+ line.insert(i, newSegment)
144
+ return
145
+ end
146
+ i += 1
147
+ end
148
+ # Append new segment
149
+ line << newSegment
150
+ end
151
+
152
+ # Return true if the two segments described by _s1_ and _s2_ overlap each
153
+ # other. A segment is a [ start, end ] Array. The two points are part of the
154
+ # segment.
155
+ def overlaps?(s1, s2)
156
+ (s1[0] <= s2[0] && s2[0] <= s1[1]) ||
157
+ (s2[0] <= s1[0] && s1[0] <= s2[1])
158
+ end
159
+
160
+ # Return true if the two segments described by _s1_ and _s2_ overlap each
161
+ # other or are directly attached to each other.
162
+ def mergeable?(s1, s2)
163
+ overlaps?(s1, s2) ||
164
+ (s1[1] + 1 == s2[0]) ||
165
+ (s2[1] + 1 == s1[0])
166
+ end
167
+
168
+ # Merge the two segments described by _dst_ and _src_ into _dst_.
169
+ def merge(dst, seg)
170
+ dst[0] = seg[0] if seg[0] < dst[0]
171
+ dst[1] = seg[1] if seg[1] > dst[1]
172
+ end
173
+
174
+ end
175
+
176
+ end
177
+