org.jsurveylib
Class Survey

java.lang.Object
  extended by org.jsurveylib.Survey
All Implemented Interfaces:
ClientSurvey, AnswerListener, LinkListener, Visitable

public final class Survey
extends java.lang.Object
implements ClientSurvey, LinkListener, AnswerListener, Visitable

The Survey object stores the data and the state of the survey.


 try {
     ClientSurvey survey = new Survey("surveyGettingStarted.xml");
     SurveyPanel surveyPanel = new SurveyPanel(survey);
     survey.addSurveyListener(this);
     frame.setLayout(new BorderLayout());
     frame.add(surveyPanel, BorderLayout.CENTER);
     frame.setJMenuBar(new SurveyMenu(survey, this));
 } catch (Exception e) {
     e.printStackTrace();
 }
 
The Survey, ClientSurvey, SurveyPanel and the SurveyAdapter are the ONLY objects that the client should interact with directly. Even then, there may be public methods in this class that are marked "for internal use only". Methods marked "for internal use only" may be renamed, removed or replaced in future versions. Because of this uncertain future, it is highly recommended you don't use these methods: Your application may not compile when you upgrade. Most other classes are marked "for internal use only" but even if they aren't, these are the only classes that you should be interacting with.


Constructor Summary
Survey(java.io.Reader xmlConfigReader)
           
Survey(java.lang.String xmlConfigFile)
           
Survey(SurveyReader reader)
           
 
Method Summary
 void accept(Visitor visitor)
          FOR INTERNAL USE ONLY.
 void addInsertQuestionListener(InsertQuestionListener listener)
          FOR INTERNAL USE ONLY. Add a listener that gets informed when a new question is inserted into the survey.
 void addPageListener(PageListener listener)
          FOR INTERNAL USE ONLY. Add a listener that gets informed when a page changes.
 void addSurveyListener(SurveyListener listener)
          Add a listener which will be informed when the survey is finished
 void addSurveyResetListener(SurveyResetListener listener)
          FOR INTERNAL USE ONLY. Add a listener that gets informed when the survey gets reset.
 void answerChanged(Question question, boolean evaluateScript)
          FOR INTERNAL USE ONLY.
 void finish()
          FOR INTERNAL USE ONLY. This informs every SurveyListener that the survey has been finished and makes isFinished() return true and informs all survey listeners.
 java.lang.String getAnswer(java.lang.String id)
          Get the current answer of a question by its question id.
 java.util.Map<java.lang.String,java.lang.String> getAnswerMap()
          Returns an answer map of the survey.
 Page getCurrentPage()
          FOR INTERNAL USE ONLY. This will return the current Page that the survey is on.
 int getCurrentPageNumber()
          FOR INTERNAL USE ONLY. This will return the current page number the survey is on.
 int getCurrentPageNumberExcludingSkipped()
          FOR INTERNAL USE ONLY. This will return the current page number the survey is on but it will not count skipped pages.
 java.util.Map<java.lang.String,Question> getIdMap()
          FOR INTERNAL USE ONLY. This returns an unmodifiable map that has question id's as keys and questions as values.
 ScriptInterpreter getInterpreter()
          FOR INTERNAL USE ONLY. This returns the survey's script interpreter.
 Menu getMenu()
          FOR INTERNAL USE ONLY.
 java.util.List<Page> getPages()
          FOR INTERNAL USE ONLY. Returns an unmodifiable List of the pages in this Survey.
 Question getQuestionByID(java.lang.String id)
          FOR INTERNAL USE ONLY. Get a Question object using it's id.
 Strings getStrings()
          FOR INTERNAL USE ONLY.
 java.util.Map<java.lang.String,Template> getTemplateMap()
          FOR INTERNAL USE ONLY. This returns a map where the keys are template names and the values are template questions.
 java.lang.String getTitle()
          Gets the title of this survey.
 int getTotalPagesExcludingSkipped()
          FOR INTERNAL USE ONLY. This will return the total page number the survey has but it will not count skipped pages.
 java.lang.String getWorkingFilePath()
          This will return the "working file" path of the survey.
 void goToFirstPage()
          FOR INTERNAL USE ONLY. This will go to the first page, considering that some pages may be skipped.
 void goToLastPage()
          FOR INTERNAL USE ONLY. This will go to the last page or the page that has blank required/invalid questions, considering that some pages may be skipped.
 void goToNextPage()
          FOR INTERNAL USE ONLY. This will increment the current page then fire a page changed event.
 void goToPage(int pageNum)
          FOR INTERNAL USE ONLY. This method changes the page to the pageNum passed in.
 void goToPreviousPage()
          FOR INTERNAL USE ONLY. This will decrement the current page and fire a page changed event.
 void insertQuestion(Question question, int pageNum, int row)
          FOR INTERNAL USE ONLY. This is called to insert a question on a survey that is already running.
 void insertQuestion(Question question, Page page, int row)
          FOR INTERNAL USE ONLY. This is called to insert a question on a survey that is already running.
 boolean isDirty()
          FOR INTERNAL USE ONLY.
 boolean isLastPageAndComplete()
          FOR INTERNAL USE ONLY. This will return true if the current page is the last page and all other non-skipped pages have their requirements met.
 boolean isNextPageAvailable()
          FOR INTERNAL USE ONLY. Returns true if the next page is available.
 boolean isPreviousPageAvailable()
          FOR INTERNAL USE ONLY. Returns true if the previous page is available.
 void loadXMLAnswers(java.io.Reader answerXMLReader)
          This will set the survey's questions to all the answers in answerReader.
 void loadXMLAnswers(java.lang.String answerXMLFile)
          This is the same as loadXMLAnswers(Reader answerXMLReader) except it takes a String instead of a reader for convenience.
 void onClick(java.lang.String url)
          FOR INTERNAL USE ONLY.
 Page pageOf(java.lang.String questionId)
          FOR INTERNAL USE ONLY. This will return the page that a question resides in or null if the question does not exist on any page.
 void removeInsertQuestionListener(InsertQuestionListener listener)
          FOR INTERNAL USE ONLY. Remove a insert question listener.
 void removePageListener(PageListener listener)
          FOR INTERNAL USE ONLY. Remove a page listener.
 void removeSurveyListener(SurveyListener listener)
          Remove a survey listener
 void removeSurveyResetListener(SurveyResetListener listener)
          FOR INTERNAL USE ONLY. Remove a insert question listener.
 void reset()
          FOR INTERNAL USE ONLY. Reset the survey so it looks like it did when it was first started.
 boolean saveToFileOnFinish()
          FOR INTERNAL USE ONLY.
 void saveXMLAnswers(java.lang.String outputXMLFile)
          Save the answers of the survey to an XML file.
 void saveXMLAnswers(java.io.Writer writer)
          This method does the same thing as saveXMLAnswers(String) but it takes a Writer instead of a path to a file.
 void setAnswer(java.lang.String id, java.lang.String answer)
          FOR INTERNAL USE ONLY. Sets the answer of a question.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

Survey

public Survey(java.lang.String xmlConfigFile)
       throws java.lang.Exception
Throws:
java.lang.Exception

Survey

public Survey(java.io.Reader xmlConfigReader)
       throws java.lang.Exception
Throws:
java.lang.Exception

Survey

public Survey(SurveyReader reader)
Method Detail

reset

public void reset()
FOR INTERNAL USE ONLY. Reset the survey so it looks like it did when it was first started. The only reason this is public is so that tests can use it. Otherwise, I'd make it private.


goToFirstPage

public void goToFirstPage()
FOR INTERNAL USE ONLY. This will go to the first page, considering that some pages may be skipped. This is internal because the method may be replaced in the future and I see no reason for the client to listen to page events at this time.


goToLastPage

public void goToLastPage()
FOR INTERNAL USE ONLY. This will go to the last page or the page that has blank required/invalid questions, considering that some pages may be skipped. This is internal because the method may be replaced in the future and I see no reason for the client to listen to page events at this time.


addSurveyListener

public void addSurveyListener(SurveyListener listener)
Add a listener which will be informed when the survey is finished

Specified by:
addSurveyListener in interface ClientSurvey
Parameters:
listener - The object that will be informed of the survey finishing.

removeSurveyListener

public void removeSurveyListener(SurveyListener listener)
Remove a survey listener

Specified by:
removeSurveyListener in interface ClientSurvey
Parameters:
listener - The survey listener to be removed.

addPageListener

public void addPageListener(PageListener listener)
FOR INTERNAL USE ONLY. Add a listener that gets informed when a page changes. This is for internal use because the PageListener interface may change in the future. This method may be moved to a different class too.

Parameters:
listener - A listener that will be notified when the current page changes to another page

removePageListener

public void removePageListener(PageListener listener)
FOR INTERNAL USE ONLY. Remove a page listener. This is for internal use because the PageListener interface may change in the future. This method may be moved to a different class too.

Parameters:
listener - A listener that will be notified when the current page changes to another page

addInsertQuestionListener

public void addInsertQuestionListener(InsertQuestionListener listener)
FOR INTERNAL USE ONLY. Add a listener that gets informed when a new question is inserted into the survey. This is for internal use because the api of the Question object may change in the future.

Parameters:
listener - A listener that will be notified when the current page changes to another page

removeInsertQuestionListener

public void removeInsertQuestionListener(InsertQuestionListener listener)
FOR INTERNAL USE ONLY. Remove a insert question listener. This is for internal use because the api of the Question object may change in the future.

Parameters:
listener - A listener that will be notified when a question is added to a page

addSurveyResetListener

public void addSurveyResetListener(SurveyResetListener listener)
FOR INTERNAL USE ONLY. Add a listener that gets informed when the survey gets reset. This is for internal use because we may handle this situation in a different way later.

Parameters:
listener - A listener that will be notified when the survey resets

removeSurveyResetListener

public void removeSurveyResetListener(SurveyResetListener listener)
FOR INTERNAL USE ONLY. Remove a insert question listener. This is for internal use because we may handle this situation in a different way later.

Parameters:
listener - A listener that will be notified when the survey resets

loadXMLAnswers

public void loadXMLAnswers(java.io.Reader answerXMLReader)
                    throws java.io.IOException,
                           org.xml.sax.SAXException
This will set the survey's questions to all the answers in answerReader. answerReader is expected to be an XML reader that has content in it that can validate against the result.xsd of this version.

The result of saveXMLAnswers can always be passed directly into this method. The labels are ignored. Calling this method will overwrite the default values of questions.

Specified by:
loadXMLAnswers in interface ClientSurvey
Parameters:
answerXMLReader - A Reader that reads from an XML file that is valid against this XSD: http://jsurveylib.sourceforge.net/result-7.10.4.4.xsd
Throws:
java.io.IOException - If there is a problem reading from the file.
org.xml.sax.SAXException - If there is an error parsing the file.
See Also:
saveXMLAnswers(String), saveXMLAnswers(java.io.Writer)

loadXMLAnswers

public void loadXMLAnswers(java.lang.String answerXMLFile)
                    throws java.io.IOException,
                           org.xml.sax.SAXException
This is the same as loadXMLAnswers(Reader answerXMLReader) except it takes a String instead of a reader for convenience. This method will update the value of the getWorkingFilePath() to the absolute path of answerXMLFile. isDirty() will return false after this method is called.

Specified by:
loadXMLAnswers in interface ClientSurvey
Parameters:
answerXMLFile - A path to an XML file that is valid against this XSD: http://jsurveylib.sourceforge.net/result-7.10.4.4.xsd
Throws:
java.io.IOException - If there is a problem reading from the file.
org.xml.sax.SAXException - If there is an error parsing the file.
See Also:
loadXMLAnswers(java.io.Reader)

setAnswer

public void setAnswer(java.lang.String id,
                      java.lang.String answer)
FOR INTERNAL USE ONLY. Sets the answer of a question. To unset a question, pass in null or "". The client should not be setting answers programmatically. At this point it is a complicated issue that often requires looking at source code.

For example, on some questions passing in an invalid question sets it to some default, in other situations it throws a RuntimeException. I'd like to make things more consistent before I let others use this.

Parameters:
id - The id of the question you are answering
answer - The text/id/path/etc. that answers the question.
Throws:
java.lang.RuntimeException - A RuntimeException may be thrown if an invalid answer is set for the question.

isNextPageAvailable

public boolean isNextPageAvailable()
FOR INTERNAL USE ONLY. Returns true if the next page is available. The next page is available when all requirements are met on the current page and there is a visitable (non-skipped) next page to go to. This is for internal use only because the definition of what makes the next page available may change in the future.

Returns:
true if the next page is available, otherwise false.

isPreviousPageAvailable

public boolean isPreviousPageAvailable()
FOR INTERNAL USE ONLY. Returns true if the previous page is available. The previous page is available when you are not at the first page and there is a visitable (non-skipped) previous page to go to. This is for internal use only because the definition of what makes the previous page available may change in the future.

Returns:
true if the previous page is available.

isLastPageAndComplete

public boolean isLastPageAndComplete()
FOR INTERNAL USE ONLY. This will return true if the current page is the last page and all other non-skipped pages have their requirements met. The current page is considered the last page if there are no visitable (non-skipped) next pages. This is for internal use only because the name and logic of this method may change in the future.

Returns:
true if all pages have requirements met and you are on the last page, otherwise false.

goToNextPage

public void goToNextPage()
FOR INTERNAL USE ONLY. This will increment the current page then fire a page changed event. If the next page is skipped, it will visit the first page that is not skipped. This is internal because the method may be replaced in the future and I see no reason for the client to listen to page events at this time.


goToPreviousPage

public void goToPreviousPage()
FOR INTERNAL USE ONLY. This will decrement the current page and fire a page changed event. If the previous page is skipped, it will visit the first page that is not skipped. This is internal because the method may be replaced in the future and I see no reason for the client to listen to page events at this time.


goToPage

public void goToPage(int pageNum)
FOR INTERNAL USE ONLY. This method changes the page to the pageNum passed in. If the pageNum is different from the current page, a currentPageChanged event is fired. This is for internal use only because the client should not change the page manually.

Parameters:
pageNum - The to make the new current page.
Throws:
java.lang.IllegalStateException - If the pageNum is an index to a skipped page

saveXMLAnswers

public void saveXMLAnswers(java.lang.String outputXMLFile)
                    throws java.io.IOException
Save the answers of the survey to an XML file. The file path is specified by the parameter. The answers will be written to outputXMLFile and will validate against the lastest result.xsd. The getWorkingFilePath() method will return the absolute path of outputXMLFile after you call this method. isDirty() will return false after this method is called.

Specified by:
saveXMLAnswers in interface ClientSurvey
Parameters:
outputXMLFile - The path to the file that will have the answers written to it.
Throws:
java.io.IOException - If an error occurs writing the file.

saveXMLAnswers

public void saveXMLAnswers(java.io.Writer writer)
                    throws java.io.IOException
This method does the same thing as saveXMLAnswers(String) but it takes a Writer instead of a path to a file. The writer will be left open after you call this method.

Specified by:
saveXMLAnswers in interface ClientSurvey
Parameters:
writer - A writer that the xml will be written to.
Throws:
java.io.IOException - If an error occurs writing to the writer.
See Also:
saveXMLAnswers(String)

getAnswerMap

public java.util.Map<java.lang.String,java.lang.String> getAnswerMap()
Returns an answer map of the survey. This map uses a question's ID as the key and its answer as the value.

Specified by:
getAnswerMap in interface ClientSurvey
Returns:
A map that uses each question's ID as a key and its answer as the value.

getAnswer

public java.lang.String getAnswer(java.lang.String id)
Get the current answer of a question by its question id. This will return null if the question does not exist and "" if the question exists, but has not been answered.

Specified by:
getAnswer in interface ClientSurvey
Parameters:
id - The id of the question you want to get the answer of.
Returns:
The answer string or null if the question does not exist.

getTitle

public java.lang.String getTitle()
Gets the title of this survey.

Specified by:
getTitle in interface ClientSurvey
Returns:
The title of the survey.

getWorkingFilePath

public java.lang.String getWorkingFilePath()
This will return the "working file" path of the survey. The "working file" is the file that got saved or opened last. If you save or open to readers or never saved or opened, this will return null.

Specified by:
getWorkingFilePath in interface ClientSurvey
Returns:
The working file path

getCurrentPageNumber

public int getCurrentPageNumber()
FOR INTERNAL USE ONLY. This will return the current page number the survey is on. This is not publicly usable because its name may change in the future.

Returns:
The current page number. The first page is page number 0.
See Also:
getCurrentPageNumberExcludingSkipped()

getCurrentPageNumberExcludingSkipped

public int getCurrentPageNumberExcludingSkipped()
FOR INTERNAL USE ONLY. This will return the current page number the survey is on but it will not count skipped pages. This is useful for display purposes. If you're on page 1 and page 0 is a skipped page, this method will return 0 while getCurrentPageNumber() will still return 1. This is not publicly usable because its name may change in the future.

Returns:
The current page number excluding skipped pages. The first page is page number 0.
See Also:
getCurrentPageNumber()

getTotalPagesExcludingSkipped

public int getTotalPagesExcludingSkipped()
FOR INTERNAL USE ONLY. This will return the total page number the survey has but it will not count skipped pages. This is useful for display purposes. If you have 2 pages and one is skipped, this will return 1.

If the current page is a skipped page, the methods result will be incremented by one.

This is not publicly usable because its name may change in the future.

Returns:
The total pages excluding skipped pages. If the current page is a skipped page, the value will be incremented by one.

getCurrentPage

public Page getCurrentPage()
FOR INTERNAL USE ONLY. This will return the current Page that the survey is on. This is for internal use because the interface to the Page object can not be guaranteed in the future.

Returns:
The current Page the survey is on.

finish

public void finish()
FOR INTERNAL USE ONLY. This informs every SurveyListener that the survey has been finished and makes isFinished() return true and informs all survey listeners.

This is internal because I'm not sure that a client should be telling the survey when it's finished. This method may be changed/renamed/have a different meaning in the future.


getPages

public java.util.List<Page> getPages()
FOR INTERNAL USE ONLY. Returns an unmodifiable List of the pages in this Survey. It is for internal use because the Page object is not guaranteed to have the same interface in the future.

Returns:
The list of pages on this Survey object.

getQuestionByID

public Question getQuestionByID(java.lang.String id)
FOR INTERNAL USE ONLY. Get a Question object using it's id. This is for internal use because the interface for a Question object can not be guaranteed in the future. Use getAnswer instead if possible. If you really need to programmatically set an answer, calling set answer is safer than doing it through this, but as you'll read, that method is for internal use only, too.

Parameters:
id - The ID of the question to get.
Returns:
The Question object which corresponds to this ID or null if no question exists with that ID.
See Also:
getAnswer(String), setAnswer(String,String)

getIdMap

public java.util.Map<java.lang.String,Question> getIdMap()
FOR INTERNAL USE ONLY. This returns an unmodifiable map that has question id's as keys and questions as values. This is for internal use only because the api of the Question class can not be guaranteed in the future.

Returns:
An unmodifiable map that has question id's as keys and questions as values.

insertQuestion

public void insertQuestion(Question question,
                           int pageNum,
                           int row)
FOR INTERNAL USE ONLY. This is called to insert a question on a survey that is already running. It will fire a questionInserted event. This is for internal use because the api of the Question object may change in the future.

Parameters:
question - The question to insert
pageNum - The page number to insert the question on. The first page is page 0
row - The row to insert the question on. All SurveyElements on or after this row will be incremented by one row.
Throws:
java.lang.IllegalArgumentException - If a question with this id exists or the page number is out of bounds.

insertQuestion

public void insertQuestion(Question question,
                           Page page,
                           int row)
FOR INTERNAL USE ONLY. This is called to insert a question on a survey that is already running. It will fire a questionInserted event. This is for internal use because the api of the Question object may change in the future.

Parameters:
question - The question to insert
page - The page to insert the question on
row - The row to insert the question on. All SurveyElements on or after this row will be incremented by one row.
Throws:
java.lang.IllegalArgumentException - If a question with this id or the page number is out of bounds.

getInterpreter

public ScriptInterpreter getInterpreter()
FOR INTERNAL USE ONLY. This returns the survey's script interpreter. The script interpreter evaluates all question's scripts. This is for internal use only because the api of the ScriptInterpeter may change in the future. The Survey may have multiple script interpreters in the future.

Returns:
The script interpreter of this survey.

getTemplateMap

public java.util.Map<java.lang.String,Template> getTemplateMap()
FOR INTERNAL USE ONLY. This returns a map where the keys are template names and the values are template questions. To populate the template you should use Question.populateTemplate(String newId, String newLabel, Boolean mandatory).

This is for internal use because the api of the Question class may change in the future.

Returns:
A Template. A Template is a question with a meaningless id, label and mandatory setting that does not show up on the survey. You can populate a survey by calling Question.populateTemplate(String newId, String newLabel, Boolean mandatory) on it.
See Also:
Question.populateTemplate(String,String,boolean,String)

pageOf

public Page pageOf(java.lang.String questionId)
FOR INTERNAL USE ONLY. This will return the page that a question resides in or null if the question does not exist on any page.

Parameters:
questionId - The question ID of a question that exists on a page
Returns:
The page that contains this question ID

accept

public void accept(Visitor visitor)
FOR INTERNAL USE ONLY.

Specified by:
accept in interface Visitable

onClick

public void onClick(java.lang.String url)
FOR INTERNAL USE ONLY.

Specified by:
onClick in interface LinkListener

getStrings

public Strings getStrings()
FOR INTERNAL USE ONLY.

Returns:
A container of static strings

getMenu

public Menu getMenu()
FOR INTERNAL USE ONLY.

Returns:
The menu configuration for this survey

answerChanged

public void answerChanged(Question question,
                          boolean evaluateScript)
FOR INTERNAL USE ONLY.

Specified by:
answerChanged in interface AnswerListener
Parameters:
question - The question whose answer changed
evaluateScript - If true, the survey's script will be evaluated. If false, the script will not be evaluated.

isDirty

public boolean isDirty()
FOR INTERNAL USE ONLY.

Returns:
true if an answer has changed since the last opening/saving, otherwise, false. The result of this method is only reliable when you load/save to a file. The methods that load/save a Reader do not update this variable.

saveToFileOnFinish

public boolean saveToFileOnFinish()
FOR INTERNAL USE ONLY.

Returns:
true if this survey requires the user to save to a file on finish.