/*
* 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.tasks;
import de.danielluedecke.zettelkasten.database.Daten;
import de.danielluedecke.zettelkasten.database.Settings;
import de.danielluedecke.zettelkasten.database.Synonyms;
import de.danielluedecke.zettelkasten.database.TasksData;
import de.danielluedecke.zettelkasten.util.classes.Comparer;
import de.danielluedecke.zettelkasten.util.Tools;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import org.apache.commons.lang3.StringUtils;
/**
*
* @author Luedeke
*/
public class KeywordSuggestionsTask extends org.jdesktop.application.Task<Object, Void> {
/**
* Daten object, which contains the XML data of the Zettelkasten
*/
private final Daten dataObj;
/**
*
*/
private final TasksData taskinfo;
/**
*
*/
private final Synonyms synonymsObj;
/**
*
*/
private final Settings settingsObj;
/**
* Indicates whether we have an extended quick input setting. when this setting is activated,
* keyword-values consisting of more than one word are splitted, and the occurence of each
* keyword-part is searched in the main entries content. if found, the related keyword also
* counts as match.
*/
private final int extendedQuickInput;
/**
* Indictaes which of the four steps for the quick input is currently processed.
*/
private final int quickstep;
/**
* The entry-text that contains the content of the entry, where we want to find related keywords
* for.
*/
private final String entrytext;
/**
* The keywords the user selected in the first step of the quick input. needed to retrieve the
* keywords for the seconde step, since in this 2. step we want to have all related keywords of
* those keywords that have been selected in the first step.
*/
private final LinkedList<String> selectedKeywords;
/**
* A List containing the remaining keywords that haven't been retrieved during the past quick
* input steps. having this list, we don't need to look through the whole keyword list on the
* one hand, on the other hand we prevent finding double keywords.
*/
private LinkedList<String> remainingKeywords;
/**
* The final results of the quick input. Contains the keywords that have to be set to the
* keyword list in the new entry-frame, when this task is finished.
*/
private LinkedList<String> newKeywords;
/**
* Similar to {@link #selectedKeywords selectedKeywords}. We need the keywords of the first step
* for the third step. See task-comments below.
*/
private final LinkedList<String> fromFirstStep;
private final javax.swing.JDialog parentDialog;
private final javax.swing.JLabel msgLabel;
private long nt;
/**
* get the strings for file descriptions from the resource map
*/
private final org.jdesktop.application.ResourceMap resourceMap
= org.jdesktop.application.Application.getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).
getContext().getResourceMap(KeywordSuggestionsTask.class);
/**
*
* @param app
* @param parent
* @param label
* @param td
* @param d
* @param syn
* @param st
* @param eqi
* @param step
* @param sel
* @param rest
* @param ffs
* @param t
*/
KeywordSuggestionsTask(org.jdesktop.application.Application app, javax.swing.JDialog parent, javax.swing.JLabel label,
TasksData td, Daten d, Synonyms syn, Settings st,
int eqi, int step, LinkedList<String> sel, LinkedList<String> rest, LinkedList<String> ffs, String t) {
// Runs on the EDT. Copy GUI state that
// doInBackground() depends on from parameters
// to ImportFileTask fields, here.
super(app);
extendedQuickInput = eqi;
dataObj = d;
taskinfo = td;
synonymsObj = syn;
settingsObj = st;
quickstep = step;
selectedKeywords = sel;
remainingKeywords = rest;
fromFirstStep = ffs;
entrytext = t.toLowerCase();
parentDialog = parent;
msgLabel = label;
// init status text
msgLabel.setText(resourceMap.getString("msg1"));
}
@Override
protected Object doInBackground() {
// Your Task's code here. This method runs
// on a background thread, so don't reference
// the Swing GUI from here.
// save search time
nt = System.nanoTime();
// definition of variables
Iterator<String> i;
// create list for the new keywords
newKeywords = new LinkedList<>();
switch (quickstep) {
/*
* Here starts the first step of the quickinput.
*
* This step takes all keywords of the data-file and looks for their occurence
* in the text and title that have been edited/entered by the user. if the
* text contains a keyword, it is added to the list (newKeywords) that will be
* displayed in the jList-component.
*
* Furthermore, the entered text will be split at each new word, and then this
* step checks whether any word longer than 3 chars is part of a keyword. if we
* found such a keyword, it is also added to the list.
*
* Finally, when we have the extended search activated, all keywords are also split
* (some "keyword-values" may consist of several words, thus looking for the keyword
* as a whole string differs from looking for single keyword-parts). If any keyword-part
* occurs in the text, the keyword will be added to the final list.
*/
case 1:
// create the list with remaining keywords
remainingKeywords = new LinkedList<>();
// copy all keywords to the remaining list
for (int cnt = 1; cnt <= dataObj.getCount(Daten.KWCOUNT); cnt++) {
String kw = dataObj.getKeyword(cnt);
// leave out empty keyword-elements
if (!kw.isEmpty()) {
remainingKeywords.add(kw);
}
}
// first check whether we have any keyword-occurences in the entry text
// therefore, we need an iterator for the list
i = remainingKeywords.iterator();
// go through list
while (i.hasNext()) {
// get keyword
String kw = i.next();
// create array with keywords, and - if necessary - related synonyms
String[] synline = null;
// retrieve synonyms if option is set
if (settingsObj.getSearchAlwaysSynonyms()) {
synline = synonymsObj.getSynonymLine(kw, false);
}
// if we don't have any synonyms, put only keyword in the array
if (null == synline) {
synline = new String[]{kw};
}
// iterate all keywords and related synonyms
for (String s : synline) {
// if we find this keyword in the text, add it to the
// list of new keywords
if (StringUtils.indexOf(entrytext, s.toLowerCase()) != -1) {
newKeywords.add(kw);
// and remove the item from the remaining keywords
i.remove();
// leave loop
break;
}
}
}
// when we have set the extended quickinput-option, we have to split
// the keywords into its single words and check whether we have more keyword
// occurences, i.e. even parts of a complete keyword-value are found in the entry text
if (Settings.QUICK_INPUT_MORE == extendedQuickInput) {
// create new iterator again
i = remainingKeywords.iterator();
// go through list with remaining keywords
while (i.hasNext()) {
// get keyword
String kw = i.next();
// init found indicator
boolean found = false;
// get the parts of the keyword and its associated synonyms
String[] synline = Tools.getKeywordsAndSynonymsParts(settingsObj, synonymsObj, kw, false);
// iterate all keywords and related synonyms
for (String s : synline) {
// only keyword-parts of more than 3 chars are recognized
if ((s.length() > 3) && (StringUtils.indexOf(entrytext, s.toLowerCase()) != -1)) {
found = true;
// leave loop
break;
}
}
// if we find this keyword-part in the text, add it to the
// list of new keywords
if (found) {
newKeywords.add(kw);
// and remove the item from the remaining keywords
i.remove();
}
}
}
// check whether the extended-quickinput should deliver less results
if (extendedQuickInput != Settings.QUICK_INPUT_LESS) {
// now split entry text at end of each word and look
// whether any word of the entry text is part of any of the remaining keywords
String[] words = entrytext.split("\\b");
int wlength = words.length;
// go through all words
for (int cnt = 0; cnt < wlength; cnt++) {
// get word of the entry text
String e = words[cnt].toLowerCase();
// only check for occurences when the word of the entry's text is longer than 3 chars
if (e.length() > 3) {
// create iterator again
i = remainingKeywords.iterator();
// go through list of remaining keywords
while (i.hasNext()) {
// get keyword
String kw = i.next();
// create array with keywords, and - if necessary - related synonyms
String[] synline = null;
// retrieve synonyms if option is set
if (settingsObj.getSearchAlwaysSynonyms()) {
synline = synonymsObj.getSynonymLine(kw, false);
}
// if we don't have any synonyms, put only keyword in the array
if (null == synline) {
synline = new String[]{kw};
}
// iterate all keywords and related synonyms
for (String s : synline) {
// when the word is inside the keyword, add keyword to the list
if (s.contains(e)) {
newKeywords.add(kw);
// and remove the item from the remaining keywords
i.remove();
// leave loop
break;
}
}
}
}
// update progressbar
setProgress(cnt, 0, wlength);
}
}
// sort the keywordlist
if (newKeywords != null && !newKeywords.isEmpty()) {
Collections.sort(newKeywords, new Comparer());
}
// we're done with the first step
break;
/*
* Here starts the second step of the quickinput.
*
* In this step, we get the selected keywords from the first step, i.e. the user
* selections that have been chosen for the keywordlist. now we search in each entry
* whether one of the selected keywords exists in that entry. if yes, we retrieve all
* other keywords of that entry and add them to the final list (newKeywords).
*
* Thus, we now have all "related" keywords of the previous selected keywords.
*/
case 2:
// only proceed if we have any selected keywords at all
if ((selectedKeywords != null) && (selectedKeywords.size() > 0)) {
// get count of entries
int slength = dataObj.getCount(Daten.ZKNCOUNT);
// go through all entries and check for the existence of the selected keyword
for (int cnt = 1; cnt <= slength; cnt++) {
// create iterator
i = selectedKeywords.iterator();
// go through all selected keywords
while (i.hasNext()) {
// get each selected keyword
String sel = i.next();
// if the selected keyword exists in that entry, copy related
// keywords to the new list
if (dataObj.existsInKeywords(sel, cnt, false)) {
// get the entries keywords
String[] kws = dataObj.getKeywords(cnt);
// when we have any keywords, go on
if (kws != null) {
// go through all related keywords
for (String kw : kws) {
// if the requested keyword exists in the list of
// remaining keywords...
if (remainingKeywords.contains(kw)) {
// add it to the new keywords list
newKeywords.add(kw);
// and remove it from the remaining keywords
remainingKeywords.remove(kw);
}
}
}
break;
}
}
// update progressbar
setProgress(cnt, 0, slength);
}
// sort the keywordlist
if (newKeywords != null && !newKeywords.isEmpty()) {
Collections.sort(newKeywords, new Comparer());
}
}
// we're done with the first step
break;
/*
* Here starts the third step of the quickinput.
*
* This step combines step one and two: first, all keywords that appear in the text
* and all words from the content that appear in any keyword, those keywords are added
* to a list. we have done this in step one, so we simply pass the list from step one
* as parameter and use it here (fromFirstStep).
*
* Now, from these keywords, all related keywords are added to the final list. In step
* two, we retrieved the related keywords of the users selection, now we retrieve the
* related keywords of all found keywords of step 1.
*/
case 3:
// only proceed if we have any keywords from the first at all
if ((fromFirstStep != null) && (fromFirstStep.size() > 0)) {
// get count of entries
int slength = dataObj.getCount(Daten.ZKNCOUNT);
// go through all entries and check for the existence of the keywords
// that we found in the first step
for (int cnt = 1; cnt <= slength; cnt++) {
// create iterator
i = fromFirstStep.iterator();
// go through all selected keywords
while (i.hasNext()) {
// get each keyword
String ffs = i.next();
// if the keyword from the first step exists in that entry, copy related
// keywords to the new list
if (dataObj.existsInKeywords(ffs, cnt, false)) {
// get the entries keywords
String[] kws = dataObj.getKeywords(cnt);
// when we have any keywords, go on
if (kws != null) {
// go through all related keywords
for (String kw : kws) {
// if the requested keyword exists in the list of
// remaining keywords...
if (remainingKeywords.contains(kw)) {
// add it to the new keywords list
newKeywords.add(kw);
// and remove it from the remaining keywords
remainingKeywords.remove(kw);
}
}
}
break;
}
}
// update progressbar
setProgress(cnt, 0, slength);
}
// sort the keywordlists
if (newKeywords != null && !newKeywords.isEmpty()) {
Collections.sort(newKeywords, new Comparer());
}
if (remainingKeywords != null && !remainingKeywords.isEmpty()) {
Collections.sort(remainingKeywords, new Comparer());
}
}
// we're done with the first step
break;
}
return null; // return your result
}
@Override
protected void succeeded(Object result) {
// Runs on the EDT. Update the GUI based on
// the result computed by doInBackground().
// store results in data-class, so we have access to them even after this class is disposed
taskinfo.setKeywordSuggestionList(remainingKeywords, TasksData.REMAINING_KW);
taskinfo.setKeywordSuggestionList(newKeywords, TasksData.NEW_KW);
}
@Override
protected void finished() {
System.out.println((double)(System.nanoTime() - nt) / 1000000000.0);
super.finished();
// and close window
parentDialog.dispose();
parentDialog.setVisible(false);
}
}