/*
GanttProject is an opensource project management tool. License: GPL3
Copyright (C) 2002-2011 Thomas Alexandre, GanttProject Team
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.sourceforge.ganttproject.io;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import net.sourceforge.ganttproject.GPLogger;
import net.sourceforge.ganttproject.PrjInfos;
import net.sourceforge.ganttproject.gui.UIConfiguration;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.parser.AbstractTagHandler;
import net.sourceforge.ganttproject.parser.GPParser;
import net.sourceforge.ganttproject.parser.ParsingContext;
import net.sourceforge.ganttproject.parser.ParsingListener;
import net.sourceforge.ganttproject.parser.TagHandler;
import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskManager;
import org.xml.sax.Attributes;
import biz.ganttproject.core.time.GanttCalendar;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
/**
* Allows to load a gantt file from xml format, using SAX parser
*/
public class GanttXMLOpen implements GPParser {
/** 0-->description of project, 1->note for task */
int typeChar = -1;
private final ArrayList<TagHandler> myTagHandlers = new ArrayList<TagHandler>();
private final ArrayList<ParsingListener> myListeners = new ArrayList<ParsingListener>();
private final ParsingContext myContext;
private final TaskManager myTaskManager;
private int viewIndex;
private int ganttDividerLocation;
private int resourceDividerLocation;
private PrjInfos myProjectInfo = null;
private UIFacade myUIFacade = null;
private UIConfiguration myUIConfig;
private TagHandler myTimelineTagHandler = new TimelineTagHandler();
public GanttXMLOpen(PrjInfos info, UIConfiguration uiConfig, TaskManager taskManager, UIFacade uiFacade) {
this(taskManager);
myProjectInfo = info;
myUIConfig = uiConfig;
this.viewIndex = 0;
this.ganttDividerLocation = 300; // TODO is this arbitrary value right ?
this.resourceDividerLocation = 300;
myUIFacade = uiFacade;
}
public GanttXMLOpen(TaskManager taskManager) {
myContext = new ParsingContext();
myTaskManager = taskManager;
}
@Override
public boolean load(InputStream inStream) throws IOException {
return doLoad(inStream);
}
public boolean doLoad(InputStream inStream) throws IOException {
// Use an instance of ourselves as the SAX event handler
XmlParser parser = new XmlParser(myTagHandlers, myListeners);
parser.parse(inStream);
myUIFacade.setViewIndex(viewIndex);
myUIFacade.setGanttDividerLocation(ganttDividerLocation);
if (resourceDividerLocation != 0) {
myUIFacade.setResourceDividerLocation(resourceDividerLocation);
}
return true;
}
public boolean load(File file) {
XmlParser parser = new XmlParser(myTagHandlers, myListeners);
try {
parser.parse(new BufferedInputStream(new FileInputStream(file)));
} catch (Exception e) {
myUIFacade.showErrorDialog(e);
return false;
}
return true;
}
@Override
public void addTagHandler(TagHandler handler) {
myTagHandlers.add(handler);
}
@Override
public void addParsingListener(ParsingListener listener) {
myListeners.add(listener);
}
@Override
public ParsingContext getContext() {
return myContext;
}
@Override
public TagHandler getDefaultTagHandler() {
return new DefaultTagHandler();
}
private class DefaultTagHandler extends AbstractTagHandler {
private final Set<String> myTags = ImmutableSet.of("project", "tasks", "description", "notes");
public DefaultTagHandler() {
super(null, true);
}
@Override
public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) {
clearCdata();
String eName = sName; // element name
if ("".equals(eName)) {
eName = qName; // not namespace aware
}
setTagStarted(myTags.contains(eName));
if (eName.equals("tasks")) {
myTaskManager.setZeroMilestones(null);
}
if (attrs != null) {
for (int i = 0; i < attrs.getLength(); i++) {
String aName = attrs.getLocalName(i); // Attr name
if ("".equals(aName)) {
aName = attrs.getQName(i);
// The project part
}
if (eName.equals("project")) {
if (aName.equals("name")) {
myProjectInfo.setName(attrs.getValue(i));
} else if (aName.equals("company")) {
myProjectInfo.setOrganization(attrs.getValue(i));
} else if (aName.equals("webLink")) {
myProjectInfo.setWebLink(attrs.getValue(i));
}
// TODO: 1.12 repair scrolling to the saved date
else if (aName.equals("view-date")) {
myUIFacade.getScrollingManager().scrollTo(GanttCalendar.parseXMLDate(attrs.getValue(i)).getTime());
} else if (aName.equals("view-index")) {
viewIndex = new Integer(attrs.getValue(i)).hashCode();
} else if (aName.equals("gantt-divider-location")) {
ganttDividerLocation = new Integer(attrs.getValue(i)).intValue();
} else if (aName.equals("resource-divider-location")) {
resourceDividerLocation = new Integer(attrs.getValue(i)).intValue();
}
} else if (eName.equals("tasks")) {
if ("empty-milestones".equals(aName)) {
myTaskManager.setZeroMilestones(Boolean.parseBoolean(attrs.getValue(i)));
}
}
}
}
}
@Override
public void endElement(String namespaceURI, String sName, String qName) {
if (!myTags.contains(qName)) {
return;
}
if ("description".equals(qName)) {
myProjectInfo.setDescription(getCdata());
} else if ("notes".equals(qName)) {
Task currentTask = getContext().peekTask();
currentTask.setNotes(getCdata());
}
setTagStarted(false);
}
}
@Override
public TagHandler getTimelineTagHandler() {
return myTimelineTagHandler;
}
class TimelineTagHandler extends AbstractTagHandler implements ParsingListener {
private final List<Integer> myIds = Lists.newArrayList();
public TimelineTagHandler() {
super("timeline", true);
}
@Override
public void parsingStarted() {
}
@Override
public void parsingFinished() {
myUIFacade.getCurrentTaskView().getTimelineTasks().clear();
for (Integer id : myIds) {
Task t = myTaskManager.getTask(id);
if (t != null) {
myUIFacade.getCurrentTaskView().getTimelineTasks().add(t);
}
}
}
@Override
protected boolean onStartElement(Attributes attrs) {
clearCdata();
return super.onStartElement(attrs);
}
@Override
protected void onEndElement() {
String[] ids = getCdata().split(",");
for (String id : ids) {
try {
myIds.add(Integer.valueOf(id.trim()));
} catch (NumberFormatException e) {
GPLogger.logToLogger(e);
}
}
clearCdata();
}
}
}