changeset 14:d90a9b1065d1

Rewrote 'Card' class with tag support
author Fox
date Sat, 09 Apr 2022 16:40:55 +0200
parents ecc0cb60b845
children 4bb371496315
files src/junotu/Card.java src/junotu/CardWidget.java src/junotu/Database.java src/junotu/Main.java src/junotu/TabEdit.java src/junotu/TabSimpleSearch.java
diffstat 6 files changed, 180 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/junotu/Card.java	Sat Apr 09 16:40:55 2022 +0200
@@ -0,0 +1,128 @@
+package junotu;
+
+import java.lang.RuntimeException;
+import java.lang.ClassCastException;
+
+import java.util.TreeMap;
+import java.util.SortedMap;
+import java.util.Set;
+import java.util.HashSet;
+
+public class Card {
+
+    public static final String TAG_CORE_PREFIX = "_junotu_";
+    public static final String TAG_IDENTIFIER = TAG_CORE_PREFIX+"identifier";
+    public static final String TAG_TITLE      = TAG_CORE_PREFIX+"title";
+    public static final String TAG_CONTENT    = TAG_CORE_PREFIX+"content";
+    public static final String TAG_LAST_EDIT  = TAG_CORE_PREFIX+"timestamp_last_edit";
+
+    public SortedMap< String, Set<Object> > tags = new TreeMap< String, Set<Object> >();
+
+    public Card( long identifier )
+    {
+	tagValueSetOnly( TAG_IDENTIFIER, new Long( identifier ) );
+    }
+    
+    public long identifierGet()
+    {
+	Long identifier = this.<Long>tagGetAs( TAG_IDENTIFIER );
+	
+	if( identifier == null ) {
+	    throw new RuntimeException( "Failed to get card identifier. Fatal." );
+	}
+	
+	return identifier.longValue();
+    }
+    
+    public String titleGet()
+    {
+	return tagGetAsOr( TAG_TITLE, "" );
+    }
+
+    public void titleSet( String title )
+    {
+	tagValueSetOnly( TAG_TITLE, title );
+    }
+
+    public String contentGet()
+    {
+	return tagGetAsOr( TAG_CONTENT, "" );
+    }
+
+    public void contentSet( String content )
+    {
+	tagValueSetOnly( TAG_CONTENT, content );
+    }
+
+    public Set<Object> tagValues( String tag )
+    {
+	return tags.get( tag );
+    }
+
+    public void tagValueSetOnly( String tag, Object value )
+    {
+	Set<Object> values = new HashSet<Object>();
+	values.add( value );
+	tags.put( tag, values );
+    }
+    
+    /** Adds a value to a tag, if it doesn't contain equal value yet. */
+    public void tagValueAdd( String tag, Object value )
+    {
+	Set<Object> values = new HashSet<Object>();
+	values.add( value );
+	
+        values = tags.putIfAbsent( tag, values );
+	
+	if( values == null ) {
+	    /* Means that key is new to the map, and was added just now. */
+	    return;
+	} else {
+	    values.add( value );
+	}
+    }
+
+    public void tagValueRemove( String tag, Object value )
+    {
+        Set<Object> values = tags.get( tag );
+	if( values != null ) {
+	    values.remove( value );
+	}
+    }
+    
+    public void tagValueReplace( String tag, Object previous, Object value )
+    {
+	Set<Object> values = tags.get( tag );
+	
+	if( values == null ) {
+	    throw new RuntimeException("Can't replace value of a tag if the tag doesn't exist.");
+	}
+
+	values.remove( previous );
+	values.add( value );
+	
+    }
+
+    /** Returns first T value of a tag, or null. */
+    @SuppressWarnings("unchecked")
+    public <T> T tagGetAs( String tag )
+    {
+        final Set<Object> values = tagValues( tag );
+	Object current;
+	while( ( current = values.iterator().next() ) != null ) {
+	    try {
+		return (T)current;
+	    } catch( ClassCastException e ) {
+		continue;
+	    }
+	}
+	return null;
+    }
+
+    public <T> T tagGetAsOr( String tag, T or )
+    {
+	T value = tagGetAs( tag );
+	return value != null ? value : or;
+    }
+    
+}
--- a/src/junotu/CardWidget.java	Sat Apr 09 14:11:43 2022 +0200
+++ b/src/junotu/CardWidget.java	Sat Apr 09 16:40:55 2022 +0200
@@ -15,7 +15,7 @@
 import javax.swing.JTextArea;
 
 import junotu.Main;
-import junotu.Database.Card;
+import junotu.Card;
 import junotu.Window;
 
 public class CardWidget extends JPanel {
@@ -26,9 +26,9 @@
     {
 	this.setLayout( new GridBagLayout() );
 
-	identifier = card.identifier;
-	JLabel title = new JLabel( card.title, JLabel.LEFT );
-	JTextArea content = new JTextArea( card.content );
+	identifier = card.identifierGet();
+	JLabel title = new JLabel( card.titleGet(), JLabel.LEFT );
+	JTextArea content = new JTextArea( card.contentGet() );
 
 	title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) );
 	content.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) );
--- a/src/junotu/Database.java	Sat Apr 09 14:11:43 2022 +0200
+++ b/src/junotu/Database.java	Sat Apr 09 16:40:55 2022 +0200
@@ -2,6 +2,7 @@
 
 import java.lang.RuntimeException;
 import java.io.File;
+import java.util.Set;
 
 import org.apache.lucene.queryParser.ParseException;
 
@@ -28,21 +29,12 @@
 
 import org.apache.lucene.search.BooleanClause;
 
-public class Database {
+import junotu.Card;
 
-    public static class Card {
-	public long identifier;
-	public String title;
-	public String content;
-    }
+public class Database {
     
     public static final String DATABASE_DIRECTORY = "./Database";
     public static final Version LUCENE_VERSION = Version.LUCENE_30;
-
-    public static final String TAG_IDENTIFIER = "_junotu_identifier";
-    public static final String TAG_TITLE      = "_junotu_title";
-    public static final String TAG_CONTENT    = "_junotu_content";
-    public static final String TAG_LAST_EDIT  = "_junotu_timestamp_last_edit";
     
     private IndexWriter luceneWriter;
     private IndexSearcher luceneSearcher;
@@ -65,14 +57,14 @@
 						     new MatchAllDocsQuery(),
 						     null,
 						     1,
-						     new Sort( new SortField( TAG_IDENTIFIER, SortField.LONG, true ) )
+						     new Sort( new SortField( Card.TAG_IDENTIFIER, SortField.LONG, true ) )
 						     );
 
 	if( topDocuments.scoreDocs.length == 0 ) {
 	    highestIdentifier = 0;
 	} else {
 	    /** TODO: Find a way to get NumericField from document. */
-	    highestIdentifier = Long.valueOf( luceneSearcher.doc( topDocuments.scoreDocs[0].doc ).get( TAG_IDENTIFIER ) );
+	    highestIdentifier = Long.valueOf( luceneSearcher.doc( topDocuments.scoreDocs[0].doc ).get( Card.TAG_IDENTIFIER ) );
 	}
 	
     }
@@ -90,7 +82,7 @@
     private Document documentByIdentifier( long identifier ) throws Exception
     {
 	
-	TopDocs topDocuments = luceneSearcher.search( NumericRangeQuery.newLongRange( TAG_IDENTIFIER, identifier, identifier, true, true ), 1 );
+	TopDocs topDocuments = luceneSearcher.search( NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true ), 1 );
 
 	if( topDocuments.scoreDocs.length == 0 ) {
 	    return null;
@@ -104,19 +96,25 @@
     {
 	
 	Document document = new Document();
-
-	NumericField fieldIdentifier = new NumericField( TAG_IDENTIFIER, Field.Store.YES, true );
-	Field        fieldTitle      = new Field( TAG_TITLE, card.title, Field.Store.YES, Field.Index.ANALYZED );
-	Field        fieldContent    = new Field( TAG_CONTENT, card.content, Field.Store.YES, Field.Index.ANALYZED );
-	NumericField fieldLastEdit   = new NumericField( TAG_LAST_EDIT, Field.Store.YES, true );
 	
-	fieldIdentifier.setLongValue( card.identifier );
-	fieldLastEdit.setLongValue( System.currentTimeMillis() );
-	    
-	document.add( fieldIdentifier );
-	document.add( fieldTitle );
-	document.add( fieldContent );
-	document.add( fieldLastEdit );
+	for( String tag : card.tags.keySet() ) {
+	    Set<Object> values = card.tags.get( tag );
+	    for( Object value : values ) {
+		if( false ) {
+		    
+	        } else if( value instanceof String ) {
+		    document.add( new Field( tag, (String)value, Field.Store.YES, Field.Index.ANALYZED ) );
+		} else if( value instanceof Number ) {
+		    NumericField field = new NumericField( tag, Field.Store.YES, true );
+		    if( value instanceof Long ) {
+			field.setLongValue( ((Long)value).longValue() );
+		    } else {
+			throw new RuntimeException( "Unknown tag number type." );
+		    }
+		    document.add( field );
+		}
+	    }
+	}
 
 	return document;
 	
@@ -124,13 +122,12 @@
 
     private Card cardFromDocument( Document document ) throws Exception
     {
-	
-	Card card = new Card();
 
 	/** TODO: Find how to get NumericField from document. */
-	card.identifier = Long.valueOf( document.get( TAG_IDENTIFIER ) );
-	card.title      = document.get( TAG_TITLE );
-	card.content    = document.get( TAG_CONTENT );
+	Card card = new Card( Long.valueOf( document.get( Card.TAG_IDENTIFIER ) ) );
+
+	card.titleSet( document.get( Card.TAG_TITLE ) );
+	card.contentSet( document.get( Card.TAG_CONTENT ) );
 
 	return card;
 	
@@ -140,10 +137,11 @@
     {
 
 	highestIdentifier++;
-	card.identifier = highestIdentifier;
+	card.tagValueSetOnly( Card.TAG_IDENTIFIER, new Long( highestIdentifier ) );
+	card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) );
 	
 	luceneWriter.addDocument( cardToDocument( card ) );
-	System.out.print("Added card with identifier "+Long.toString(highestIdentifier)+": '"+card.title+"'\n");
+	System.out.print("Added card with identifier "+Long.toString(highestIdentifier)+": '"+card.titleGet()+"'\n");
 	searcherRefresh();
 	//luceneWriter.commit();
 
@@ -154,18 +152,20 @@
     public void cardUpdate( Card card ) throws Exception
     {
 
-	Query query = NumericRangeQuery.newLongRange( TAG_IDENTIFIER, card.identifier, card.identifier, true, true );
+	Query query = NumericRangeQuery.newLongRange( card.TAG_IDENTIFIER, card.identifierGet(), card.identifierGet(), true, true );
 	TopDocs topDocuments = luceneSearcher.search( query, 1 );
 
 	if( topDocuments.scoreDocs.length == 0 ) {
-	    throw new RuntimeException( "Failed to update card with identifier "+Long.toString( card.identifier )+", not found." );
+	    throw new RuntimeException( "Failed to update card with identifier "+Long.toString( card.identifierGet() )+", not found." );
 	}
+
+	card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) );
 	
         int documentNumber = topDocuments.scoreDocs[0].doc;
 
 	luceneWriter.deleteDocuments( query );
 	luceneWriter.addDocument( cardToDocument( card ) );
-	System.out.print("Updated card with identifier "+Long.toString(card.identifier)+": '"+card.title+"'\n");
+	System.out.print("Updated card with identifier "+Long.toString(card.identifierGet())+": '"+card.titleGet()+"'\n");
 	searcherRefresh();
 	//luceneWriter.commit();
 	
@@ -173,7 +173,7 @@
 
     public void cardDelete( long identifier ) throws Exception
     {
-	Query query = NumericRangeQuery.newLongRange( TAG_IDENTIFIER, identifier, identifier, true, true );
+	Query query = NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true );
 	TopDocs topDocuments = luceneSearcher.search( query, 1 );
 
 	if( topDocuments.scoreDocs.length == 0 ) {
@@ -209,7 +209,7 @@
 						     new MatchAllDocsQuery(),
 						     null,
 						     amount,
-						     new Sort( new SortField( TAG_LAST_EDIT, SortField.LONG, true ) )
+						     new Sort( new SortField( Card.TAG_LAST_EDIT, SortField.LONG, true ) )
 						     );
 
 	Card[] cards = new Card[topDocuments.scoreDocs.length];
@@ -235,11 +235,11 @@
 	    /* TODO: FIXME: Don't use advanced QueryParser for simple search. */
 	    queryTitle = new QueryParser(
 					 LUCENE_VERSION,
-					 TAG_TITLE,
+					 Card.TAG_TITLE,
 					 new StandardAnalyzer(LUCENE_VERSION)).parse(query);
 	    queryContent = new QueryParser(
 					   LUCENE_VERSION,
-					   TAG_CONTENT,
+					   Card.TAG_CONTENT,
 					   new StandardAnalyzer(LUCENE_VERSION)).parse(query);
 	} catch( ParseException e ) {
 	    System.out.print( "Search query parsing exception, returning zero results.\n" );
--- a/src/junotu/Main.java	Sat Apr 09 14:11:43 2022 +0200
+++ b/src/junotu/Main.java	Sat Apr 09 16:40:55 2022 +0200
@@ -3,10 +3,8 @@
 import java.lang.RuntimeException;
 
 import junotu.Database;
-import junotu.Database.Card;
 import junotu.Window;
 import junotu.Window.Tab;
-import junotu.TabEdit;
 
 public class Main {
 
--- a/src/junotu/TabEdit.java	Sat Apr 09 14:11:43 2022 +0200
+++ b/src/junotu/TabEdit.java	Sat Apr 09 16:40:55 2022 +0200
@@ -22,8 +22,8 @@
 
 import junotu.Main;
 import junotu.Database;
-import junotu.Database.Card;
 import junotu.Window.Tab;
+import junotu.Card;
 
 public class TabEdit extends JPanel {
 
@@ -148,9 +148,9 @@
     public void cardEdit( Card card )
     {
 	newCard = false;
-	identifier = card.identifier;
-	title.setText( card.title );
-	content.setText( card.content );
+	identifier = card.identifierGet();
+	title.setText( card.titleGet() );
+	content.setText( card.contentGet() );
 	updateTitle();
 	delete.setVisible(true);
 	SwingUtilities.invokeLater(
@@ -215,11 +215,10 @@
     private void buttonClickedSave()
     {
 
-	Card card = new Card();
+	Card card = new Card( identifier );
 
-	card.identifier = identifier;
-	card.title = title.getText();
-	card.content = content.getText();
+	card.titleSet( title.getText() );
+	card.contentSet( content.getText() );
 
 	try {
 	    if( newCard ) {
--- a/src/junotu/TabSimpleSearch.java	Sat Apr 09 14:11:43 2022 +0200
+++ b/src/junotu/TabSimpleSearch.java	Sat Apr 09 16:40:55 2022 +0200
@@ -20,8 +20,8 @@
 import javax.swing.JScrollPane;
 
 import junotu.Main;
-import junotu.Database.Card;
 import junotu.Window.Tab;
+import junotu.Card;
 import junotu.CardWidget;
 
 public class TabSimpleSearch extends JPanel {