/*
* Zettelkasten - nach Luhmann
* Copyright (C) 2001-2015 by Daniel Lüdecke (http://www.danielluedecke.de)
*
* Homepage: http://zettelkasten.danielluedecke.de
*
*
* 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, see <http://www.gnu.org/licenses/>.
*
*
* Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU
* General Public License, wie von der Free Software Foundation veröffentlicht, weitergeben
* und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (wenn Sie möchten)
* jeder späteren Version.
*
* Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein
* wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder
* der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der
* GNU General Public License.
*
* Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm
* erhalten haben. Falls nicht, siehe <http://www.gnu.org/licenses/>.
*/
package de.danielluedecke.zettelkasten.database;
import de.danielluedecke.zettelkasten.util.Constants;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.IllegalAddException;
import org.jdom2.IllegalDataException;
/**
*
* @author danielludecke
*/
public class StenoData {
/**
* XML document that holds the data for auto-correction. Each element "entry"
* has an attribute named "id" that contains the wrong, mispelled word. the
* entry's text is the correct writing of the word.
*/
private Document steno;
/**
* XML document that is used as backup
*/
private Document backupdoc = null;
/**
* This class stores the information about the automatic correction (spelling) when
* the user makes input for new entries.
*/
public StenoData() {
clear();
}
/**
* Clears the XML document and creates a dummy-backup of the document, in case the original
* XML-document contains data.
*/
public final void clear() {
// check whether backup document exists, whether autokorrektur-document exists and whether
// the autokorrektur-document has any data. only in this case we create a backup
if (steno!=null && steno.getRootElement().getContentSize()>0) {
// create new backup doc
backupdoc = new Document(new Element("backup_steno"));
// copy content
backupdoc.getRootElement().addContent(steno.getRootElement().cloneContent());
}
steno = new Document(new Element("steno"));
}
/**
* This method checks whether the XML document is ok or corrupted. in case there have been
* jdom-errors when adding new elements, the XML document {@link #steno} might
* be empty, while the backup-document {@link #backupdoc} has data. In this case,
* {@code false} is returned. If the XML-document is ok, {@code true} is returned.
* @return {@code true} if the main XML-document is ok, {@code false}if it might be corrupted.
* <br><br>
* You can use {@link #restoreDocument() restoreDocument()} to restore a corrupted document.
*/
public boolean isDocumentOK() {
// check whether we have any XML-document at all. proceed only, if we have no document
// of if the XML-document does not contain data
if ((null==steno) || (steno.getRootElement().getContentSize()<1)) {
// now check whether we have a backup of the XML document, which has content
if ((backupdoc!=null) && (backupdoc.getRootElement().getContentSize()>0)) {
// if so, the backup contains data that the main document does not has
// so, we assume the document is *not* ok
return false;
}
}
// else everything is fine
return true;
}
/**
* In case we have a corrupted XML document with a backup document that has data
* (see {@link #isDocumentOK() isDocumentOK()}), we can restore the backupped data
* with this method.<br><br>
* So, this method copies back the content of the {@link #backupdoc} to the
* original XML document {@link #steno}.
*/
public void restoreDocument() {
// check whether we have a backup document that also contains data
if ((backupdoc!=null) && (backupdoc.getRootElement().getContentSize()>0)) {
// if we have it, create new main XML document
steno = new Document(new Element("steno"));
// and copy the content of the backup document to it
steno.getRootElement().addContent(backupdoc.getRootElement().cloneContent());
}
}
/**
* Sets the document, e.g. after loading the settings
* @param d the document with the steno-data
*/
public void setDocument(Document d) {
steno = d;
}
/**
* Gets the xml-document that contains the steno-data
* @return the xml-document with the steno-data
*/
public Document getDocument() {
return steno;
}
/**
* Returns the amount of elements
* @return Returns the amount of elements as integer value
*/
public int getCount() {
return steno.getRootElement().getContentSize();
}
/**
* Gets a String-pair of steno data, i.e. a string array with 2 fields. first
* field contains the short steno word, the second field holds the complete
* version of the word
* @param nr the position of the element we want to retrieve
* @return a string array containing the steno and the complete word
*/
public String[] getElement(int nr) {
// get all elements
List<Element> all = steno.getRootElement().getChildren();
// get the requested element
Element el = all.get(nr);
// new string array
String[] retval = null;
// if we found an element, return its content
if (el!=null) {
retval = new String[2];
retval[0] = el.getAttributeValue("id");
retval[1] = el.getText();
}
return retval;
}
/**
* Adds a new pair of steno/long words to the document
*
* @param abbr the short, steno-abbreviation of the word
* @param longword the long, original version of the word
* @return {@code true} if element was successfully addes, false if {@code stenoword} already existed
*/
public boolean addElement(String abbr, String longword) {
// check for existence
if (exists(abbr)) {
return false;
}
// if it doesn't already exist, create new element
Element e = new Element(Daten.ELEMENT_ENTRY);
try {
// set id-attribute
e.setAttribute("id", abbr);
// set content
e.setText(longword);
// and add it to the document
steno.getRootElement().addContent(e);
}
catch (IllegalAddException | IllegalDataException ex) {
Constants.zknlogger.log(Level.SEVERE,ex.getLocalizedMessage());
return false;
}
// return success
return true;
}
/**
* This method checks whether text string {@code text} ends with one of the abbreviations
* (steno words) in the steno data base. if any abbreviation was found at the end of
* {@code text}, this abbreviation is returned, else {@code null} is returned.
*
* @param text a text fragment, which end may contain an abbreviation. If {@code text} ends with
* an abbreviation, this abbreviation is returned.
* @return a string with an abbreviation, if {@code text} ends with this abbreviation. {@code null}
* if {@code text} does not contain (end with) any abbreviation.
*/
public String findAbbreviationFromText(String text) {
// go through all existing steno abbreviations
for (int cnt=0; cnt<getCount(); cnt++) {
// retrieve abbreviation
String abbr = getAbbreviation(cnt);
// check whether the text segment ends with the
// current abbreviation, if so, we found a valid steno
if (text.endsWith(abbr)) {
try {
// now check whether the case is correct (matchcase)
if (text.substring(text.length()-abbr.length()).equals(abbr)) {
return abbr;
}
}
catch (IndexOutOfBoundsException ex) {
}
}
}
return null;
}
/**
* This method returns the length of the longest abbreviation on the steno list.
* This is needed to check how many chars before the current caret position in the edit window
* have to be checked for the steno abbreviation
*
* @return the length of the longest abbreviation
*/
public int retrieveLongestAbbrLength() {
int longest = 0;
for (int cnt=0; cnt<getCount(); cnt++) {
String abbr = getAbbreviation(cnt);
if (abbr.length()>longest) {
longest = abbr.length();
}
}
return longest;
}
/**
* This method returns the abbreviation of the steno element with the index number {@code nr}.
*
* @param nr the index-number of the abbreviation that should be returned.
* @return the abbreviation in the XML document with the index {@code nr}
*/
public String getAbbreviation(int nr) {
String[] retval = getElement(nr);
if (retval!=null) {
return retval[0];
}
return null;
}
/**
*
* @param abbr
* @return
*/
public String getStenoWord(String abbr) {
// get all elements
List<Element> all = steno.getRootElement().getChildren();
// create an iterator
Iterator<Element> i = all.iterator();
// go through list
while (i.hasNext()) {
// get element
Element el = i.next();
// get spell-check-word
String correct = el.getAttributeValue("id");
// check for existing value
if (null==correct) {
return null;
}
// if the element's id equals the requestes string "e", return true
// i.e. the string e already exists as element
if (correct.equals(abbr)) {
return el.getText();
}
}
return null;
}
/**
* Checks whether the value passed by the parameter "e" already exists in the
* data. Therefore, each element's id-attribute is compared to the parameter "e".
* @param abbr the string we want to look for if it exists
* @return {@code true} if we found it, false if it doesn't exist
*/
public boolean exists(String abbr) {
// get all elements
List<Element> all = steno.getRootElement().getChildren();
// create an iterator
Iterator<Element> i = all.iterator();
// go through list
while (i.hasNext()) {
// get element
Element el = i.next();
// get attribute
String att = el.getAttributeValue("id");
// if the element's id equals the requestes string "e", return true
// i.e. the string e already exists as element
if (att!=null && att.equals(abbr)) {
return true;
}
}
// nothing found...
return false;
}
}