diff --git a/biz.ganttproject.core/src/biz/ganttproject/core/model/task/TaskDefaultColumn.java b/biz.ganttproject.core/src/biz/ganttproject/core/model/task/TaskDefaultColumn.java
index 62380d6fb2..b3f5c2260a 100644
--- a/biz.ganttproject.core/src/biz/ganttproject/core/model/task/TaskDefaultColumn.java
+++ b/biz.ganttproject.core/src/biz/ganttproject/core/model/task/TaskDefaultColumn.java
@@ -50,7 +50,8 @@ public enum TaskDefaultColumn {
ID(new ColumnList.ColumnStub("tpd10", null, false, -1, 20), Integer.class, "tableColID", Functions.NOT_EDITABLE),
OUTLINE_NUMBER(new ColumnList.ColumnStub("tpd11", null, false, 4, 20), String.class, "tableColOutline", Functions.NOT_EDITABLE),
COST(new ColumnList.ColumnStub("tpd12", null, false, -1, 20), Double.class, "tableColCost"),
- RESOURCES(new ColumnList.ColumnStub("tpd13", null, false, -1, 20), String.class, "resources", Functions.NOT_EDITABLE);
+ RESOURCES(new ColumnList.ColumnStub("tpd13", null, false, -1, 20), String.class, "resources", Functions.NOT_EDITABLE),
+ LOAD(new ColumnList.ColumnStub("tpd14", null, false, -1, 20), Double.class, "tableColLoad", Functions.NOT_EDITABLE);
public interface LocaleApi {
String i18n(String key);
diff --git a/ganttproject-tester/test/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmTest.java b/ganttproject-tester/test/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmTest.java
new file mode 100644
index 0000000000..02126347fd
--- /dev/null
+++ b/ganttproject-tester/test/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmTest.java
@@ -0,0 +1,86 @@
+/*
+Copyright 2017 Christoph Schneider, BarD Software s.r.o
+
+This file is part of GanttProject, an opensource project management tool.
+
+GanttProject is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GanttProject is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GanttProject. If not, see .
+*/
+package net.sourceforge.ganttproject.task.algorithm;
+
+import net.sourceforge.ganttproject.TestSetupHelper;
+import net.sourceforge.ganttproject.TestSetupHelper.TaskManagerBuilder;
+import net.sourceforge.ganttproject.resource.HumanResource;
+import net.sourceforge.ganttproject.task.Task;
+import net.sourceforge.ganttproject.task.TaskContainmentHierarchyFacade;
+import net.sourceforge.ganttproject.test.task.TaskTestCase;
+
+/**
+ * Tests for cost calculations
+ *
+ * @author schch (Christoph Schneider)
+ */
+public class LoadAlgorithmTest extends TaskTestCase {
+ public void testSupertaskLoad() {
+ Task supertask = createTask();
+ Task subtask1 = createTask();
+ Task subtask2 = createTask();
+ TaskContainmentHierarchyFacade hierarchy = getTaskManager().getTaskHierarchy();
+ hierarchy.move(subtask1, supertask);
+ hierarchy.move(subtask2, supertask);
+
+ TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder();
+ setTaskManager(builder.build());
+ HumanResource joe = new HumanResource("Joe", 1, builder.getResourceManager());
+
+ HumanResource jane = new HumanResource("Jane", 1, builder.getResourceManager());
+
+ builder.getResourceManager().add(joe);
+ builder.getResourceManager().add(jane);
+
+ subtask1.setDuration(subtask1.getManager().createLength(5));
+ subtask2.setDuration(subtask1.getManager().createLength(10));
+ assertEquals(0.0, supertask.getLoad().getValue());
+
+ subtask1.getAssignmentCollection().addAssignment(joe).setLoad(100f);
+ subtask1.getAssignmentCollection().addAssignment(jane).setLoad(50f);
+ assertEquals(7.5, supertask.getLoad().getValue());
+ assertEquals(7.5, subtask1.getLoad().getValue());
+ assertEquals(0.0, subtask2.getLoad().getValue());
+
+ subtask2.getAssignmentCollection().addAssignment(jane).setLoad(50f);
+ assertEquals(12.5, supertask.getLoad().getValue());
+ assertEquals(7.5, subtask1.getLoad().getValue());
+ assertEquals(5.0, subtask2.getLoad().getValue());
+ }
+
+ public void testTaskLoad() {
+ TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder();
+ setTaskManager(builder.build());
+ HumanResource joe = new HumanResource("Joe", 1, builder.getResourceManager());
+
+ HumanResource jane = new HumanResource("Jane", 1, builder.getResourceManager());
+
+ builder.getResourceManager().add(joe);
+ builder.getResourceManager().add(jane);
+
+ Task t = createTask();
+ t.setDuration(t.getManager().createLength(2));
+ assertEquals(0.0, t.getLoad().getValue());
+
+ t.getAssignmentCollection().addAssignment(joe).setLoad(100f);
+ t.getAssignmentCollection().addAssignment(jane).setLoad(50f);
+ assertEquals(3.0, t.getLoad().getValue());
+ }
+
+}
diff --git a/ganttproject/data/resources/language/i18n.properties b/ganttproject/data/resources/language/i18n.properties
index c85d3c6f6e..f9ee64a242 100644
--- a/ganttproject/data/resources/language/i18n.properties
+++ b/ganttproject/data/resources/language/i18n.properties
@@ -212,6 +212,7 @@ library = Libraries
license = License
list.separator = ', '
list.separator.last = ' and '
+load = Load
lockDAV = Lock WebDAV resources (maximal locking time in minutes)
longLanguage = English
looknfeel = Appearance
@@ -323,6 +324,7 @@ option.taskProperties.cost.calculated.label.yes = Calculated\:
option.taskProperties.cost.calculated.label.no = Set explicitly\:
option.taskProperties.customColumn.name.label = Column name
option.taskProperties.customColumn.type.label = Column type
+option.taskProperties.load.value.label = Sum of all loads\:
option.taskProperties.main.earliestBegin.copyBeginDate = Copy begin date
option.taskProperties.main.scheduling.automated.label = in scheduling algorithms \u25BE
option.taskProperties.main.scheduling.automated.value.duration = Duration is immutable
@@ -364,6 +366,7 @@ optionGroup.importer.msproject.mpx.label = MPX options
optionGroup.resourceChartColors.label = Resource colors
optionGroup.resourceRate.label = Resource payment rate
optionGroup.task.cost.label = Task cost
+optionGroup.task.load.label = Task load
optionGroup.timelineLabels.label = Timeline labels
optionGroup.rss.label = GanttProject news and updates
optionGroup.webdav.lock.label = Locking parameters
@@ -598,6 +601,7 @@ tableColDuration = Duration
tableColEndDate = End date
tableColID = ID
tableColInfo = Alerts
+tableColLoad = Load
tableColName = Name
tableColOutline = Outline number
tableColPredecessors = Predecessors
diff --git a/ganttproject/data/resources/language/i18n_de.properties b/ganttproject/data/resources/language/i18n_de.properties
index dd74bacdfe..906165e0a0 100644
--- a/ganttproject/data/resources/language/i18n_de.properties
+++ b/ganttproject/data/resources/language/i18n_de.properties
@@ -207,6 +207,7 @@ length = Dauer
library = Bibliothek
license = Lizenz
list.separator.last = ' und '
+load = Aufwand
lockDAV = WebDAV-Ressourcen sperren (maximale Sperrdauer in Minuten)
longLanguage = Deutsch
looknfeel = Aussehen
@@ -312,6 +313,7 @@ option.taskProperties.cost.calculated.label.yes = Berechnet\:
option.taskProperties.cost.calculated.label.no = Explizit festgelegt\:
option.taskProperties.customColumn.name.label = Spaltenname
option.taskProperties.customColumn.type.label = Spaltentyp
+option.taskProperties.load.value.label = Summe der Aufw\u00E4nde\:
option.taskProperties.main.earliestBegin.copyBeginDate = Kopiere Anfangsdatum
option.taskProperties.main.scheduling.automated.value.hint = diese Optionen k\u00F6nnen noch nicht konfiguriert werden
option.taskProperties.main.scheduling.label = Planungsoptionen
@@ -349,6 +351,7 @@ optionGroup.importer.msproject.mpx.label = MPX-Optionen
optionGroup.resourceChartColors.label = Farben f\u00FCr Ressourcen
optionGroup.resourceRate.label = Bezahlungsrate der Ressource
optionGroup.task.cost.label = Aufgabenkosten
+optionGroup.task.load.label = Gesamtaufwand
optionGroup.timelineLabels.label = Beschriftungen auf Zeitachse
optionGroup.rss.label = GanttProject News und Updates
optionGroup.webdav.lock.label = Datei-Sperre Einstellungen
@@ -545,6 +548,7 @@ tableColDuration = Dauer
tableColEndDate = Ende
tableColID = ID
tableColInfo = Warnungen
+tableColLoad = Aufwand
tableColName = Vorgang
tableColOutline = GliederungsNr.
tableColPredecessors = Vorg\u00E4nger
diff --git a/ganttproject/src/biz/ganttproject/impex/csv/GanttCSVExport.java b/ganttproject/src/biz/ganttproject/impex/csv/GanttCSVExport.java
index 44164dcb16..3d2bf9e4a7 100644
--- a/ganttproject/src/biz/ganttproject/impex/csv/GanttCSVExport.java
+++ b/ganttproject/src/biz/ganttproject/impex/csv/GanttCSVExport.java
@@ -205,6 +205,9 @@ private void writeTasks(SpreadsheetWriter writer) throws IOException {
case COST:
writer.print(task.getCost().getValue().toPlainString());
break;
+ case LOAD:
+ writer.print(task.getLoad().getValue().toString());
+ break;
case INFO:
case PRIORITY:
case TYPE:
diff --git a/ganttproject/src/net/sourceforge/ganttproject/GanttTreeTableModel.java b/ganttproject/src/net/sourceforge/ganttproject/GanttTreeTableModel.java
index 9db99f3281..0c0a746e13 100644
--- a/ganttproject/src/net/sourceforge/ganttproject/GanttTreeTableModel.java
+++ b/ganttproject/src/net/sourceforge/ganttproject/GanttTreeTableModel.java
@@ -314,6 +314,9 @@ else if (t.isMilestone()) {
case COST:
res = t.getCost().getValue();
break;
+ case LOAD:
+ res = t.getLoad().getValue();
+ break;
case RESOURCES:
List resources = Lists.transform(Arrays.asList(t.getAssignments()), new Function() {
@Override
diff --git a/ganttproject/src/net/sourceforge/ganttproject/gui/taskproperties/TaskAllocationsPanel.java b/ganttproject/src/net/sourceforge/ganttproject/gui/taskproperties/TaskAllocationsPanel.java
index 974b87210d..a35608574a 100644
--- a/ganttproject/src/net/sourceforge/ganttproject/gui/taskproperties/TaskAllocationsPanel.java
+++ b/ganttproject/src/net/sourceforge/ganttproject/gui/taskproperties/TaskAllocationsPanel.java
@@ -58,6 +58,8 @@ public void setValue(Double value) {
};
private final GPOptionGroup myCostGroup = new GPOptionGroup("task.cost", myCostIsCalculated, myCostValue);
+ private final GPOptionGroup myLoadGroup = new GPOptionGroup("task.load");
+
private JTable myTable;
public TaskAllocationsPanel(Task task, HumanResourceManager hrManager, RoleManager roleMgr) {
@@ -78,7 +80,7 @@ public JPanel getComponent() {
CommonPanel.setupComboBoxEditor(getTable().getColumnModel().getColumn(4), myRoleManager.getEnabledRoles());
JPanel tablePanel = CommonPanel.createTableAndActions(myTable, myModel);
- String layoutDef = "(ROW weight=1.0 (LEAF name=resources weight=0.5) (LEAF name=cost weight=0.5))";
+ String layoutDef = "(ROW weight=1.0 (LEAF name=resources weight=0.5) (COLUMN weight=0.5 (LEAF name=cost weight=0.5) (LEAF name=load weight=0.5)))";
JXMultiSplitPane result = new JXMultiSplitPane();
result.setDividerSize(0);
@@ -87,6 +89,7 @@ public JPanel getComponent() {
result.getMultiSplitLayout().setModel(modelRoot);
result.add(tablePanel, "resources");
result.add(UIUtil.border(createCostPanel(), 10, UIUtil.LEFT), "cost");
+ result.add(UIUtil.border(createLoadPanel(), 10, UIUtil.LEFT), "load");
return result;
}
@@ -122,6 +125,21 @@ public void changeValue(ChangeValueEvent event) {
return result;
}
+ private JComponent createLoadPanel() {
+ OptionsPageBuilder builder = new OptionsPageBuilder();
+
+ JPanel optionsPanel = new JPanel();
+ optionsPanel.add(new JLabel(GanttLanguage.getInstance().getText("option.taskProperties.load.value.label")));
+ optionsPanel.add(new JLabel(myTask.getLoad().getValue().toString()));
+ OptionsPageBuilder.TWO_COLUMN_LAYOUT.layout(optionsPanel, 1);
+
+ UIUtil.createTitle(optionsPanel, builder.getI18N().getOptionGroupLabel(myLoadGroup));
+
+ JPanel result = new JPanel(new BorderLayout());
+ result.add(optionsPanel, BorderLayout.NORTH);
+ return result;
+ }
+
public void commit() {
if (myTable.isEditing()) {
myTable.getCellEditor().stopCellEditing();
diff --git a/ganttproject/src/net/sourceforge/ganttproject/task/Task.java b/ganttproject/src/net/sourceforge/ganttproject/task/Task.java
index ebf3dfecf1..9b00cf0737 100644
--- a/ganttproject/src/net/sourceforge/ganttproject/task/Task.java
+++ b/ganttproject/src/net/sourceforge/ganttproject/task/Task.java
@@ -186,4 +186,10 @@ public static interface Cost {
boolean isSupertask();
List getAttachments();
+
+ public static interface Load {
+ Double getValue();
+ }
+
+ Load getLoad();
}
diff --git a/ganttproject/src/net/sourceforge/ganttproject/task/TaskImpl.java b/ganttproject/src/net/sourceforge/ganttproject/task/TaskImpl.java
index 4a396c4c59..362df23b1d 100644
--- a/ganttproject/src/net/sourceforge/ganttproject/task/TaskImpl.java
+++ b/ganttproject/src/net/sourceforge/ganttproject/task/TaskImpl.java
@@ -37,6 +37,7 @@ of the License, or (at your option) any later version.
import net.sourceforge.ganttproject.task.algorithm.AlgorithmCollection;
import net.sourceforge.ganttproject.task.algorithm.AlgorithmException;
import net.sourceforge.ganttproject.task.algorithm.CostAlgorithmImpl;
+import net.sourceforge.ganttproject.task.algorithm.LoadAlgorithmImpl;
import net.sourceforge.ganttproject.task.algorithm.ShiftTaskTreeAlgorithm;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyException;
import net.sourceforge.ganttproject.task.dependency.TaskDependencySlice;
@@ -130,6 +131,8 @@ public class TaskImpl implements Task {
private final CostImpl myCost = new CostImpl();
+ private final LoadImpl myLoad = new LoadImpl();
+
private boolean isUnplugged = false;
public final static int NONE = 0;
@@ -1277,4 +1280,19 @@ public void setCalculated(boolean calculated) {
public Cost getCost() {
return myCost;
}
+
+ private class LoadImpl implements Load {
+
+ @Override
+ public Double getValue() {
+ return new LoadAlgorithmImpl().getCalculatedLoad(TaskImpl.this);
+ }
+
+ }
+
+ @Override
+ public Load getLoad() {
+ return myLoad;
+ }
+
}
diff --git a/ganttproject/src/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmImpl.java b/ganttproject/src/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmImpl.java
new file mode 100644
index 0000000000..8078cefd70
--- /dev/null
+++ b/ganttproject/src/net/sourceforge/ganttproject/task/algorithm/LoadAlgorithmImpl.java
@@ -0,0 +1,44 @@
+/*
+Copyright 2017 Christoph Schneider, BarD Software s.r.o
+
+This file is part of GanttProject, an opensource project management tool.
+
+GanttProject is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GanttProject is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GanttProject. If not, see .
+*/
+package net.sourceforge.ganttproject.task.algorithm;
+
+import net.sourceforge.ganttproject.task.ResourceAssignment;
+import net.sourceforge.ganttproject.task.Task;
+import net.sourceforge.ganttproject.task.TaskContainmentHierarchyFacade;
+
+/**
+ * Algorithm for calculating task load
+ *
+ * @author schch (Christoph Schneider)
+ */
+public class LoadAlgorithmImpl {
+ public Double getCalculatedLoad(Task t) {
+ Double total = new Double(0.0);
+ TaskContainmentHierarchyFacade taskHierarchy = t.getManager().getTaskHierarchy();
+ if (taskHierarchy.hasNestedTasks(t)) {
+ for (Task child : taskHierarchy.getNestedTasks(t)) {
+ total = total + child.getLoad().getValue();
+ }
+ }
+ for (ResourceAssignment assignment : t.getAssignments()) {
+ total = total + assignment.getLoad() * t.getDuration().getLength() / 100.0;
+ }
+ return total;
+ }
+}
diff --git a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/PropertyFetcher.java b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/PropertyFetcher.java
index 380912bab5..ce04a210dc 100755
--- a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/PropertyFetcher.java
+++ b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/PropertyFetcher.java
@@ -64,6 +64,7 @@ public void getTaskAttributes(Task t, Map id2value) {
id2value.put(TaskDefaultColumn.OUTLINE_NUMBER.getStub().getID(), Joiner.on('.').join(outlinePath));
id2value.put(TaskDefaultColumn.ID.getStub().getID(), String.valueOf(t.getTaskID()));
id2value.put(TaskDefaultColumn.COST.getStub().getID(), t.getCost().getValue().toPlainString());
+ id2value.put(TaskDefaultColumn.LOAD.getStub().getID(), t.getLoad().getValue().toString());
CustomColumnsValues customValues = t.getCustomValues();
for (CustomPropertyDefinition def : myProject.getTaskCustomColumnManager().getDefinitions()) {
diff --git a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/XmlSerializer.java b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/XmlSerializer.java
index 34e73af439..af00776ae4 100644
--- a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/XmlSerializer.java
+++ b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/XmlSerializer.java
@@ -143,6 +143,7 @@ protected void writeTasks(final TaskManager taskManager, final TransformerHandle
addAttribute("assigned-to", i18n("human"), attrs);
addAttribute("notes", i18n("notes"), attrs);
addAttribute("duration", i18n("duration"), attrs);
+ addAttribute("load", i18n("load"), attrs);
startPrefixedElement("tasks", attrs, handler);
TaskVisitor visitor = new TaskVisitor() {
AttributesImpl myAttrs = new AttributesImpl();
@@ -172,6 +173,9 @@ protected String serializeTask(Task t, int depth) throws Exception {
addAttribute("id", "tpd6", myAttrs);
textElement("duration", myAttrs, String.valueOf(t.getDuration().getLength()), handler);
+ addAttribute("id", "tpd14", myAttrs);
+ textElement("load", myAttrs, String.valueOf(t.getLoad().getValue()), handler);
+
final List attachments = t.getAttachments();
for (int i = 0; i < attachments.size(); i++) {
Document nextAttachment = attachments.get(i);
diff --git a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/itext/ThemeImpl.java b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/itext/ThemeImpl.java
index 53361230f2..28e71fa5d8 100644
--- a/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/itext/ThemeImpl.java
+++ b/org.ganttproject.impex.htmlpdf/src/org/ganttproject/impex/htmlpdf/itext/ThemeImpl.java
@@ -424,6 +424,7 @@ private void writeProperties(ArrayList orderedColumns, Map