Mercurial Hosting > junotu
changeset 8:9d3256f86803
Functional card creation and search
author | Fox |
---|---|
date | Fri, 08 Apr 2022 11:48:17 +0200 |
parents | 4ee26d904fe3 |
children | dd51276f95a2 |
files | src/junotu/CardWidget.java src/junotu/Database.java src/junotu/Main.java src/junotu/TabEdit.java src/junotu/TabSimpleSearch.java src/junotu/Window.java |
diffstat | 6 files changed, 352 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/src/junotu/CardWidget.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/CardWidget.java Fri Apr 08 11:48:17 2022 +0200 @@ -12,24 +12,19 @@ import javax.swing.JLabel; import javax.swing.JTextArea; +import junotu.Database.Card; + public class CardWidget extends JPanel { - public CardWidget() - { - this( "Title" ); - } + public long identifier; - public CardWidget( String titleStr ) - { - this( titleStr, "Content" ); - } - - public CardWidget( String titleStr, String contentStr ) + public CardWidget( Card card ) { this.setLayout( new GridBagLayout() ); - JLabel title = new JLabel( titleStr, JLabel.LEFT ); - JTextArea content = new JTextArea( contentStr ); + identifier = card.identifier; + JLabel title = new JLabel( card.title, JLabel.LEFT ); + JTextArea content = new JTextArea( card.content ); title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); content.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) );
--- a/src/junotu/Database.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/Database.java Fri Apr 08 11:48:17 2022 +0200 @@ -1,6 +1,8 @@ package junotu; +import java.lang.RuntimeException; import java.io.File; + import org.apache.lucene.index.IndexWriter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.store.Directory; @@ -26,7 +28,7 @@ public class Database { - public class Card { + public static class Card { public long identifier; public String title; public String content; @@ -36,8 +38,9 @@ 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_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; @@ -50,10 +53,10 @@ luceneWriter = new IndexWriter( indexDirectory, new StandardAnalyzer(LUCENE_VERSION), - true, + null, IndexWriter.MaxFieldLength.UNLIMITED ); - luceneSearcher = new IndexSearcher( indexDirectory ); + luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); /* Find highest unique identifier. */ TopDocs topDocuments = luceneSearcher.search( @@ -66,52 +69,140 @@ if( topDocuments.scoreDocs.length == 0 ) { highestIdentifier = 0; } else { - highestIdentifier = (Long)((NumericField)luceneSearcher.doc( topDocuments.scoreDocs[0].doc ).getFieldable( TAG_IDENTIFIER )).getNumericValue(); + /** TODO: Find a way to get NumericField from document. */ + highestIdentifier = Long.valueOf( luceneSearcher.doc( topDocuments.scoreDocs[0].doc ).get( TAG_IDENTIFIER ) ); } } - - public long cardAdd( String title, String content ) throws Exception + + public void databaseCommit() throws Exception { - Document document = new Document(); - - NumericField fieldIdentifier = new NumericField( TAG_IDENTIFIER, Field.Store.YES, true ); - Field fieldTitle = new Field( TAG_TITLE, title, Field.Store.YES, Field.Index.ANALYZED ); - Field fieldContent = new Field( TAG_CONTENT, content, Field.Store.YES, Field.Index.ANALYZED ); - - highestIdentifier++; - - fieldIdentifier.setLongValue( highestIdentifier ); - - document.add( fieldIdentifier ); - document.add( fieldTitle ); - document.add( fieldContent ); - - luceneWriter.addDocument( document ); - - return highestIdentifier; - + luceneWriter.commit(); } - public Card cardGetByIdentifier( long identifier ) throws Exception + private void searcherRefresh() throws Exception { + luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); + } + + private Document documentByIdentifier( long identifier ) throws Exception + { + TopDocs topDocuments = luceneSearcher.search( NumericRangeQuery.newLongRange( TAG_IDENTIFIER, identifier, identifier, true, true ), 1 ); if( topDocuments.scoreDocs.length == 0 ) { return null; } - Document document = luceneSearcher.doc( topDocuments.scoreDocs[0].doc ); + return luceneSearcher.doc( topDocuments.scoreDocs[0].doc ); + + } + + private Document cardToDocument( Card card ) throws Exception + { + + 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 ); + + return document; + + } + + private Card cardFromDocument( Document document ) throws Exception + { + Card card = new Card(); - card.identifier = (long)((NumericField)document.getFieldable( TAG_IDENTIFIER )).getNumericValue(); - card.title = document.get( TAG_TITLE ); - card.content = document.get( TAG_CONTENT ); + /** 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 ); return card; } + + public long cardAdd( Card card ) throws Exception + { + highestIdentifier++; + card.identifier = highestIdentifier; + + luceneWriter.addDocument( cardToDocument( card ) ); + System.out.print("Added card with identifier "+Long.toString(highestIdentifier)+": '"+card.title+"'\n"); + searcherRefresh(); + //luceneWriter.commit(); + + return highestIdentifier; + + } + + public void cardUpdate( Card card ) throws Exception + { + + Query query = NumericRangeQuery.newLongRange( TAG_IDENTIFIER, card.identifier, card.identifier, 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." ); + } + + int documentNumber = topDocuments.scoreDocs[0].doc; + + luceneWriter.deleteDocuments( query ); + luceneWriter.addDocument( cardToDocument( card ) ); + searcherRefresh(); + //luceneWriter.commit(); + + } + + public Card cardGetByIdentifier( long identifier ) throws Exception + { + + Document document = documentByIdentifier( identifier ); + + if( document == null ) { + return null; + } + + return cardFromDocument( document ); + + } + + /** Return up to 'amount' of recently modified cards. */ + public Card[] searchTopRecent( int amount ) throws Exception + { + + TopDocs topDocuments = luceneSearcher.search( + new MatchAllDocsQuery(), + null, + amount, + new Sort( new SortField( TAG_LAST_EDIT, SortField.LONG, true ) ) + ); + + Card[] cards = new Card[topDocuments.scoreDocs.length]; + + for( int i = 0; i < topDocuments.scoreDocs.length; i++ ) { + Document document = luceneSearcher.doc( topDocuments.scoreDocs[i].doc ); + cards[i] = cardFromDocument( document ); + } + + return cards; + + } + public Card[] searchSimple( String query ) throws Exception { @@ -136,10 +227,7 @@ for( int i = 0; i < hits.scoreDocs.length; i++ ) { Document document = luceneSearcher.doc( hits.scoreDocs[i].doc ); - cards[i] = new Card(); - cards[i].identifier = (long)((NumericField)document.getFieldable( TAG_IDENTIFIER )).getNumericValue(); - cards[i].title = document.get( TAG_TITLE ); - cards[i].content = document.get( TAG_CONTENT ); + cards[i] = cardFromDocument( document ); } return cards;
--- a/src/junotu/Main.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/Main.java Fri Apr 08 11:48:17 2022 +0200 @@ -1,8 +1,12 @@ package junotu; +import java.lang.RuntimeException; + import junotu.Database; +import junotu.Database.Card; import junotu.Window; import junotu.Window.Tab; +import junotu.TabEdit; public class Main { @@ -15,10 +19,10 @@ public static void main(String[] args) throws Exception { database = new Database(); - addWindow( Tab.SEARCH ); + windowAdd( Tab.SEARCH ); } - public static void addWindow( Tab tab ) + public static void windowAdd( Tab tab ) { for( int i = 0; i < windows.length; i++ ) { if( windows[i] == null ) { @@ -29,13 +33,52 @@ return; } - public static void activeWindowTabSwitch( Tab tab ) { + public static void windowClose( Window window ) + { + int openWindowCount = 0; + for( int i = 0; i < windows.length; i++ ) { + if( windows[i] == window ) { + window.dispose(); + windows[i] = null; + } + if( windows[i] != null ) { + openWindowCount++; + } + } + if( openWindowCount == 0 ) { + System.out.print( "No windows open, closing program..\n" ); + try { + database.databaseCommit(); + } catch( Exception e ) { + throw new RuntimeException(e); + } + System.exit(0); + } + } + + public static Window windowGetActive() + { for( int i = 0; i < windows.length; i++ ) { if( windows[i] != null && windows[i].isActive() ) { - windows[i].tabSwitch( tab ); - return; + return windows[i]; } } - return; + return null; + } + + public static void actionCardCreate() + { + Window active = windowGetActive(); + active.tabEdit.cardCreate(); + active.tabSwitch( Tab.EDIT ); } + + public static void actionCardEdit( long identifier ) throws Exception + { + Window active = windowGetActive(); + Card card = database.cardGetByIdentifier( identifier ); + active.tabEdit.cardEdit( card ); + active.tabSwitch( Tab.EDIT ); + } + }
--- a/src/junotu/TabEdit.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/TabEdit.java Fri Apr 08 11:48:17 2022 +0200 @@ -2,6 +2,8 @@ import java.awt.Dimension; import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.JPanel; @@ -13,15 +15,27 @@ import javax.swing.JTextArea; import javax.swing.JScrollPane; +import junotu.Main; +import junotu.Database; +import junotu.Database.Card; +import junotu.Window.Tab; + public class TabEdit extends JPanel { + + private boolean newCard = true; + private long identifier = -1; + + private JTextField title; + private JTextArea content; + public TabEdit() { this.setLayout( new BorderLayout() ); Box scrollContent = Box.createVerticalBox(); JScrollPane scroll = new JScrollPane( scrollContent ); - JTextField title = new JTextField( "Title" ); - JTextArea content = new JTextArea( "Here you go. Some text." ); + title = new JTextField(); + content = new JTextArea(); Box bottom = Box.createHorizontalBox(); JButton back = new JButton("Cancel"); @@ -45,6 +59,77 @@ bottom.add( save ); //scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + + back.addActionListener( + new ActionListener() { + @Override + public void actionPerformed( ActionEvent e ) + { + buttonClickedBack(); + } + } + ); + + save.addActionListener( + new ActionListener() { + @Override + public void actionPerformed( ActionEvent e ) + { + buttonClickedSave(); + } + } + ); } + + public void cardCreate() + { + newCard = true; + identifier = -1; + } + + public void cardEdit( Card card ) + { + newCard = false; + identifier = card.identifier; + title.setText( card.title ); + content.setText( card.content ); + } + + private void clearWidgets() + { + title.setText(""); + content.setText(""); + } + + private void buttonClickedBack() + { + Main.windowGetActive().tabSwitch( Tab.SEARCH ); + clearWidgets(); + } + + private void buttonClickedSave() + { + + Card card = new Card(); + + card.identifier = identifier; + card.title = title.getText(); + card.content = content.getText(); + + try { + if( newCard ) { + Main.database.cardAdd( card ); + } else { + Main.database.cardUpdate( card ); + } + } catch( Exception e ) { + + } + + Main.windowGetActive().tabSearch.search(); + Main.windowGetActive().tabSwitch( Tab.SEARCH ); + clearWidgets(); + } + }
--- a/src/junotu/TabSimpleSearch.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/TabSimpleSearch.java Fri Apr 08 11:48:17 2022 +0200 @@ -1,10 +1,15 @@ package junotu; +import java.lang.RuntimeException; + import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import javax.swing.event.DocumentListener; +import javax.swing.event.DocumentEvent; + import javax.swing.JPanel; import javax.swing.Box; @@ -15,18 +20,23 @@ import javax.swing.JScrollPane; import junotu.Main; +import junotu.Database.Card; import junotu.Window.Tab; import junotu.CardWidget; public class TabSimpleSearch extends JPanel { + + private JTextField field; + private Box results; + public TabSimpleSearch() { this.setLayout( new BorderLayout() ); JPanel top = new JPanel( new BorderLayout() ); - JTextField field = new JTextField(); + field = new JTextField(); JButton create = new JButton("+"); - Box results = Box.createVerticalBox(); + results = Box.createVerticalBox(); JScrollPane scroll = new JScrollPane( results ); field.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); @@ -41,15 +51,14 @@ top.add( create, BorderLayout.EAST ); this.add( scroll, BorderLayout.CENTER ); - for( int i = 0; i < 100; i++ ) { - CardWidget card = new CardWidget( "Placeholder #"+Integer.toString(i+1) ); - results.add( card ); - } scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + search(); + create.addActionListener( - new ActionListener() { + new ActionListener() + { @Override public void actionPerformed( ActionEvent e ) { @@ -57,12 +66,60 @@ } } ); + + field.getDocument().addDocumentListener( + new DocumentListener() + { + @Override + public void changedUpdate( DocumentEvent e ) + { + search(); + } + @Override + public void removeUpdate( DocumentEvent e ) + { + search(); + } + @Override + public void insertUpdate( DocumentEvent e ) + { + search(); + } + } + ); } + public void search() { + + Card[] cards; + + try { + String text = field.getText(); + if( text.length() > 0 ) { + cards = Main.database.searchSimple( field.getText() ); + } else { + cards = Main.database.searchTopRecent( 32 ); + } + } catch( Exception e ) { + throw new RuntimeException(e); + } + + System.out.print("Search: Found "+cards.length+" matches.\n"); + + /* TODO: Reuse widgets. */ + results.removeAll(); + for( Card card : cards ) { + CardWidget cardWidget = new CardWidget( card ); + results.add( cardWidget ); + } + results.validate(); + results.repaint(); + } + private void buttonClickedCreate() { - Main.activeWindowTabSwitch( Tab.EDIT ); + Main.actionCardCreate(); } }
--- a/src/junotu/Window.java Thu Apr 07 21:47:36 2022 +0200 +++ b/src/junotu/Window.java Fri Apr 08 11:48:17 2022 +0200 @@ -2,6 +2,7 @@ import java.awt.Dimension; import java.awt.Font; +import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JPanel; @@ -31,10 +32,11 @@ "Edit", }; + public TabSimpleSearch tabSearch; + public TabEdit tabEdit; + private JPanel tabs; private CardLayout tabsLayout; - private JPanel search; - private JPanel edit; private Tab activeTab; @@ -47,6 +49,17 @@ this.setSize(384, 384); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); + + } + + @Override + protected void processWindowEvent( WindowEvent e ) + { + switch( e.getID() ) { + case WindowEvent.WINDOW_CLOSING: { + Main.windowClose(this); + } + } } public void tabSwitch( Tab tab ) @@ -62,14 +75,14 @@ tabsLayout = new CardLayout(); tabs = new JPanel( tabsLayout ); - search = new TabSimpleSearch(); - edit = new TabEdit(); + tabSearch = new TabSimpleSearch(); + tabEdit = new TabEdit(); this.add(tabs); - tabs.add(search); - tabs.add(edit); - tabsLayout.addLayoutComponent( search, TAB_NAMES[Tab.SEARCH.ordinal()] ); - tabsLayout.addLayoutComponent( edit, TAB_NAMES[Tab.EDIT.ordinal()] ); + tabs.add(tabSearch); + tabs.add(tabEdit); + tabsLayout.addLayoutComponent( tabSearch, TAB_NAMES[Tab.SEARCH.ordinal()] ); + tabsLayout.addLayoutComponent( tabEdit, TAB_NAMES[Tab.EDIT.ordinal()] ); }