Mercurial Hosting > junotu
changeset 103:7a3fd865654a
Spacing/Formatting/Indentation: Now using tabs exclusively, instead of a mix of tabs and spaces
author | Fox |
---|---|
date | Thu, 06 Apr 2023 01:44:10 +0200 |
parents | a313eaea437a |
children | 144cb44cd75e |
files | src/junotu/Card.java src/junotu/CardWidget.java src/junotu/ColumnCardWidget.java src/junotu/Database.java src/junotu/GUIToolbox.java src/junotu/Main.java src/junotu/TabBoard.java src/junotu/TabCalendarBoard.java src/junotu/TabEdit.java src/junotu/TabSimpleSearch.java src/junotu/TagUtility.java src/junotu/Window.java |
diffstat | 12 files changed, 2987 insertions(+), 2976 deletions(-) [+] |
line wrap: on
line diff
--- a/src/junotu/Card.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/Card.java Thu Apr 06 01:44:10 2023 +0200 @@ -10,179 +10,179 @@ 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_SEARCH = TAG_CORE_PREFIX+"search"; - public static final String TAG_SAVED = TAG_CORE_PREFIX+"timestamp_saved"; - public static final String TAG_LAST_EDIT = TAG_CORE_PREFIX+"timestamp_last_edit"; - - public static final String TAG_BOARD = TAG_CORE_PREFIX+"board"; - public static final String TAG_BOARD_COLUMNS = TAG_CORE_PREFIX+"board_columns"; - public static final String TAG_BOARD_COLUMN = TAG_CORE_PREFIX+"board_column"; - public static final String TAG_BOARD_COLUMN_CARDS = TAG_CORE_PREFIX+"board_column_cards"; - public static final String TAG_BOARD_COLUMN_CARD = TAG_CORE_PREFIX+"board_column_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_SEARCH = TAG_CORE_PREFIX+"search"; + public static final String TAG_SAVED = TAG_CORE_PREFIX+"timestamp_saved"; + public static final String TAG_LAST_EDIT = TAG_CORE_PREFIX+"timestamp_last_edit"; - public static final String TAG_CALENDAR_BOARD = TAG_CORE_PREFIX+"calendar_board"; - public static final String TAG_CALENDAR_BOARD_COLUMN = TAG_CORE_PREFIX+"calendar_board_column"; - public static final String TAG_CALENDAR_BOARD_COLUMN_DATE = TAG_CORE_PREFIX+"calendar_board_column_date"; - public static final String TAG_CALENDAR_BOARD_COLUMN_CARDS = TAG_CORE_PREFIX+"calendar_board_column_cards"; - public static final String TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED = TAG_CORE_PREFIX+"calendar_board_hide_empty_days"; - - public static final String VALUE_BOARD_COLUMN_CARD_ONLY = "only"; - - public static final String HIDE_TAGS[] = { - TAG_BOARD_COLUMN, - TAG_CALENDAR_BOARD, - TAG_CALENDAR_BOARD_COLUMN, - }; - - public static final String HIDE_TAG_VALUES[] = { - TAG_BOARD_COLUMN_CARD, VALUE_BOARD_COLUMN_CARD_ONLY, - }; + public static final String TAG_BOARD = TAG_CORE_PREFIX+"board"; + public static final String TAG_BOARD_COLUMNS = TAG_CORE_PREFIX+"board_columns"; + public static final String TAG_BOARD_COLUMN = TAG_CORE_PREFIX+"board_column"; + public static final String TAG_BOARD_COLUMN_CARDS = TAG_CORE_PREFIX+"board_column_cards"; + public static final String TAG_BOARD_COLUMN_CARD = TAG_CORE_PREFIX+"board_column_card"; - public SortedMap< String, Set<Object> > tags = new TreeMap< String, Set<Object> >(); + public static final String TAG_CALENDAR_BOARD = TAG_CORE_PREFIX+"calendar_board"; + public static final String TAG_CALENDAR_BOARD_COLUMN = TAG_CORE_PREFIX+"calendar_board_column"; + public static final String TAG_CALENDAR_BOARD_COLUMN_DATE = TAG_CORE_PREFIX+"calendar_board_column_date"; + public static final String TAG_CALENDAR_BOARD_COLUMN_CARDS = TAG_CORE_PREFIX+"calendar_board_column_cards"; + public static final String TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED = TAG_CORE_PREFIX+"calendar_board_hide_empty_days"; + + public static final String VALUE_BOARD_COLUMN_CARD_ONLY = "only"; - public Card() - { - tagValueSetOnly( TAG_IDENTIFIER, new Long( -1 ) ); - } - - public long identifierGet() - { - Long identifier = this.<Long>tagGetAs( TAG_IDENTIFIER ); - - if( identifier == null ) { - throw new RuntimeException( "Failed to get card identifier. Fatal." ); + public static final String HIDE_TAGS[] = { + TAG_BOARD_COLUMN, + TAG_CALENDAR_BOARD, + TAG_CALENDAR_BOARD_COLUMN, + }; + + public static final String HIDE_TAG_VALUES[] = { + TAG_BOARD_COLUMN_CARD, VALUE_BOARD_COLUMN_CARD_ONLY, + }; + + public SortedMap< String, Set<Object> > tags = new TreeMap< String, Set<Object> >(); + + public Card() + { + tagValueSetOnly( TAG_IDENTIFIER, new Long( -1 ) ); } - - 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 long identifierGet() + { + Long identifier = this.<Long>tagGetAs( TAG_IDENTIFIER ); + + if( identifier == null ) { + throw new RuntimeException( "Failed to get card identifier. Fatal." ); + } - /** Return all set tags. */ - public Set<String> tagNames() - { - return tags.keySet(); - } - - public Set<Object> tagValues( String tag ) - { - return tags.get( tag ); - } + return identifier.longValue(); + } + + public String titleGet() + { + return tagGetAsOr( TAG_TITLE, "" ); + } + + public void titleSet( String title ) + { + tagValueSetOnly( TAG_TITLE, title ); + } - public void tagRemove( String tag ) - { - tags.remove( 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. Returns true if the value is new. */ - public boolean 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 true; - } else { - return values.add( value ); + public String contentGet() + { + return tagGetAsOr( TAG_CONTENT, "" ); + } + + public void contentSet( String content ) + { + tagValueSetOnly( TAG_CONTENT, content ); } - } - public void tagValueRemove( String tag, Object value ) - { - Set<Object> values = tags.get( tag ); - - if( values == null ) { - return; + /** Return all set tags. */ + public Set<String> tagNames() + { + return tags.keySet(); } - - values.remove( value ); - - if( values.size() == 0 ) { - tagRemove( tag ); + + public Set<Object> tagValues( String tag ) + { + return tags.get( tag ); } - - } - - 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."); + + public void tagRemove( String tag ) + { + tags.remove( tag ); } - values.remove( previous ); - values.add( value ); - - } + 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. Returns true if the value is new. */ + public boolean tagValueAdd( String tag, Object value ) + { + Set<Object> values = new HashSet<Object>(); + values.add( value ); + + values = tags.putIfAbsent( tag, values ); - /** Returns first T value of a tag, or null. */ - @SuppressWarnings("unchecked") - public <T> T tagGetAs( String tag ) - { - final Set<Object> values = tagValues( tag ); + if( values == null ) { + /* Means that key is new to the map, and was added just now. */ + return true; + } else { + return values.add( value ); + } + } - if( values == null ) { - return null; + public void tagValueRemove( String tag, Object value ) + { + Set<Object> values = tags.get( tag ); + + if( values == null ) { + return; + } + + values.remove( value ); + + if( values.size() == 0 ) { + tagRemove( tag ); + } + } - - Object current; - while( ( current = values.iterator().next() ) != null ) { - try { - return (T)current; - } catch( ClassCastException e ) { - continue; - } + + 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 ); + } - return null; - } + + /** Returns first T value of a tag, or null. */ + @SuppressWarnings("unchecked") + public <T> T tagGetAs( String tag ) + { + final Set<Object> values = tagValues( tag ); + + if( values == null ) { + return null; + } - public <T> T tagGetAsOr( String tag, T or ) - { - T value = tagGetAs( tag ); - return value != null ? value : or; - } + Object current; + while( ( current = values.iterator().next() ) != null ) { + try { + return (T)current; + } catch( ClassCastException e ) { + continue; + } + } + return null; + } - public boolean tagHas( String tag ) - { - return tags.containsKey(tag); - } + public <T> T tagGetAsOr( String tag, T or ) + { + T value = tagGetAs( tag ); + return value != null ? value : or; + } - public boolean isBoard() - { - return tags.containsKey(TAG_BOARD); - } - + public boolean tagHas( String tag ) + { + return tags.containsKey(tag); + } + + public boolean isBoard() + { + return tags.containsKey(TAG_BOARD); + } + }
--- a/src/junotu/CardWidget.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/CardWidget.java Thu Apr 06 01:44:10 2023 +0200 @@ -22,65 +22,64 @@ public class CardWidget extends JPanel { - public long identifier; - - public CardWidget( Card card ) - { - this.setLayout( new GridBagLayout() ); + public long identifier; + + public CardWidget( Card card ) + { + this.setLayout( new GridBagLayout() ); + + 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 ) ); - identifier = card.identifierGet(); - JLabel title = new JLabel( card.titleGet(), JLabel.LEFT ); - JTextArea content = new JTextArea( card.contentGet() ); + this.setMinimumSize( new Dimension( 96, 32 ) ); + this.setPreferredSize( new Dimension( 128, 128 ) ); + this.setMaximumSize( new Dimension( 1000000000, 128 ) ); + + title.setMinimumSize( new Dimension( 32, 32 ) ); - title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); - content.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) ); - - this.setMinimumSize( new Dimension( 96, 32 ) ); - this.setPreferredSize( new Dimension( 128, 128 ) ); - this.setMaximumSize( new Dimension( 1000000000, 128 ) ); + this.setBorder( BorderFactory.createRaisedBevelBorder() ); + content.setEditable( false ); + content.setLineWrap( true ); + content.setWrapStyleWord( true ); + content.setOpaque( false ); - title.setMinimumSize( new Dimension( 32, 32 ) ); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = 1.0; - this.setBorder( BorderFactory.createRaisedBevelBorder() ); - content.setEditable( false ); - content.setLineWrap( true ); - content.setWrapStyleWord( true ); - content.setOpaque( false ); - - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - - this.add( title, constraints ); - constraints.anchor = GridBagConstraints.NORTHWEST; - constraints.gridx++; - constraints.fill = GridBagConstraints.BOTH; - constraints.weighty = 0.5; - this.add( content, constraints ); + this.add( title, constraints ); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.gridx++; + constraints.fill = GridBagConstraints.BOTH; + constraints.weighty = 0.5; + this.add( content, constraints ); - MouseAdapter mouseListener = new MouseAdapter() - { - @Override - public void mouseClicked( MouseEvent e ) + MouseAdapter mouseListener = new MouseAdapter() { - switch( e.getButton() ) + @Override + public void mouseClicked( MouseEvent e ) { - case MouseEvent.BUTTON1: { - boolean newWindow = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; - if( newWindow ) { - Main.actionCardEdit( Main.windowAdd( Tab.EDIT ), identifier ); - } else { - Main.actionCardEdit( (Window)getTopLevelAncestor(), identifier ); - } - } + switch( e.getButton() ) + { + case MouseEvent.BUTTON1: { + boolean newWindow = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; + if( newWindow ) { + Main.actionCardEdit( Main.windowAdd( Tab.EDIT ), identifier ); + } else { + Main.actionCardEdit( (Window)getTopLevelAncestor(), identifier ); + } + } + } } - - } - }; - - this.addMouseListener( mouseListener ); - content.addMouseListener( mouseListener ); - - } + }; + + this.addMouseListener( mouseListener ); + content.addMouseListener( mouseListener ); + + } }
--- a/src/junotu/ColumnCardWidget.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/ColumnCardWidget.java Thu Apr 06 01:44:10 2023 +0200 @@ -23,96 +23,96 @@ class ColumnCardWidget extends JPanel { - public boolean newCard; - public long identifier; - public JTextArea title; - - public ColumnCardWidget( Card card ) - { - this.setLayout( new BorderLayout() ); + public boolean newCard; + public long identifier; + public JTextArea title; - title = new JTextArea(""); - - title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); - - this.setMinimumSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 64 ) ); - this.setPreferredSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 64 ) ); - this.setMaximumSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 128 ) ); - - //title.setMinimumSize( new Dimension( 32, 32 ) ); + public ColumnCardWidget( Card card ) + { + this.setLayout( new BorderLayout() ); - this.setBorder( BorderFactory.createRaisedBevelBorder() ); - title.setEditable( true ); - title.setLineWrap( true ); - title.setWrapStyleWord( true ); - title.setOpaque( false ); + title = new JTextArea(""); - this.add( title, BorderLayout.CENTER ); + title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); - MouseAdapter mouseListener = new MouseAdapter() - { - @Override - public void mouseClicked( MouseEvent e ) - { - e.setSource(ColumnCardWidget.this); - processMouseEvent(e); - } - }; + this.setMinimumSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 64 ) ); + this.setPreferredSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 64 ) ); + this.setMaximumSize( new Dimension( TabBoard.COLUMN_CONTENT_WIDTH, 128 ) ); - title.addMouseListener( mouseListener ); + //title.setMinimumSize( new Dimension( 32, 32 ) ); - newCard = card == null; - if( !newCard ) { - identifier = card.identifierGet(); - title.setText(card.titleGet()); - } - - } + this.setBorder( BorderFactory.createRaisedBevelBorder() ); + title.setEditable( true ); + title.setLineWrap( true ); + title.setWrapStyleWord( true ); + title.setOpaque( false ); + + this.add( title, BorderLayout.CENTER ); - public void save() - { - try { - if( newCard ) { - Card card = new Card(); - card.titleSet( title.getText() ); - card.tagValueSetOnly( Card.TAG_BOARD_COLUMN_CARD, Card.VALUE_BOARD_COLUMN_CARD_ONLY ); - - identifier = Main.database.cardAdd(card); - newCard = false; - - } else { - Card card = Main.database.cardGetByIdentifier(identifier); - - if( card == null ) { - throw new RuntimeException("Null card on update try."); + MouseAdapter mouseListener = new MouseAdapter() + { + @Override + public void mouseClicked( MouseEvent e ) + { + e.setSource(ColumnCardWidget.this); + processMouseEvent(e); + } + }; + + title.addMouseListener( mouseListener ); + + newCard = card == null; + if( !newCard ) { + identifier = card.identifierGet(); + title.setText(card.titleGet()); } - - card.titleSet( title.getText() ); - Main.database.cardUpdate( card, true ); - - } - } catch( Exception e ) { - throw new RuntimeException(e); - } - } - public void delete() - { - if( newCard ) { - return; } - Main.database.cardDeleteByIdentifier(identifier, true); - } + public void save() + { + try { + if( newCard ) { + Card card = new Card(); + card.titleSet( title.getText() ); + card.tagValueSetOnly( Card.TAG_BOARD_COLUMN_CARD, Card.VALUE_BOARD_COLUMN_CARD_ONLY ); + + identifier = Main.database.cardAdd(card); + newCard = false; + + } else { + Card card = Main.database.cardGetByIdentifier(identifier); + + if( card == null ) { + throw new RuntimeException("Null card on update try."); + } + + card.titleSet( title.getText() ); + Main.database.cardUpdate( card, true ); - public boolean isSelected() - { - return title.isFocusOwner(); - } + } + } catch( Exception e ) { + throw new RuntimeException(e); + } + } + + public void delete() + { + if( newCard ) { + return; + } - public void select() - { - title.requestFocusInWindow(); - } - + Main.database.cardDeleteByIdentifier(identifier, true); + } + + public boolean isSelected() + { + return title.isFocusOwner(); + } + + public void select() + { + title.requestFocusInWindow(); + } + }
--- a/src/junotu/Database.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/Database.java Thu Apr 06 01:44:10 2023 +0200 @@ -38,450 +38,449 @@ import junotu.Card; public class Database { - - public static final String DATABASE_DIRECTORY = "./database"; - public static final Version LUCENE_VERSION = Version.LUCENE_30; - - private IndexWriter luceneWriter; - private IndexSearcher luceneSearcher; + + public static final String DATABASE_DIRECTORY = "./database"; + public static final Version LUCENE_VERSION = Version.LUCENE_30; + + private IndexWriter luceneWriter; + private IndexSearcher luceneSearcher; + + private long highestIdentifier; + + private Query[] hideQueries; + + public Database() + { + try { + Directory indexDirectory = FSDirectory.open( new File( DATABASE_DIRECTORY ) ); + luceneWriter = new IndexWriter( + indexDirectory, + new StandardAnalyzer(LUCENE_VERSION), + null, + IndexWriter.MaxFieldLength.UNLIMITED + ); + luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); - private long highestIdentifier; + /* Find highest unique identifier. */ + TopDocs topDocuments = luceneSearcher.search( + new MatchAllDocsQuery(), + null, + 1, + 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( Card.TAG_IDENTIFIER ) ); + } + } catch( IOException e ) { /* Also catches CorruptIndexException from Lucene */ + throw new RuntimeException(e); + } + + hideQueries = new Query[Card.HIDE_TAGS.length+Card.HIDE_TAG_VALUES.length/2]; + int pos = 0; + + for( int i = 0; i < Card.HIDE_TAGS.length; i++ ) { + hideQueries[pos] = new WildcardQuery( new Term(Card.HIDE_TAGS[i], "*") ); + pos += 1; + } - private Query[] hideQueries; - - public Database() - { - try { - Directory indexDirectory = FSDirectory.open( new File( DATABASE_DIRECTORY ) ); - luceneWriter = new IndexWriter( - indexDirectory, - new StandardAnalyzer(LUCENE_VERSION), - null, - IndexWriter.MaxFieldLength.UNLIMITED - ); - luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); - - /* Find highest unique identifier. */ - TopDocs topDocuments = luceneSearcher.search( - new MatchAllDocsQuery(), - null, - 1, - new Sort( new SortField( Card.TAG_IDENTIFIER, SortField.LONG, true ) ) - ); + for( int i = 0; i < Card.HIDE_TAG_VALUES.length/2; i++ ) { + hideQueries[pos] = new TermQuery( new Term(Card.HIDE_TAG_VALUES[i*2], Card.HIDE_TAG_VALUES[i*2+1]) ); + pos += 1; + } + + } + + public void databaseCommit() + { + System.out.print( "Saving database to disk..\n" ); + try { + luceneWriter.commit(); + } catch( IOException e ) { + throw new RuntimeException(e); + } + } - 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( Card.TAG_IDENTIFIER ) ); - } - } catch( IOException e ) { /* Also catches CorruptIndexException from Lucene */ - throw new RuntimeException(e); + public void databaseResaveAll() + { + System.out.print("Database: resaving all cards without modifying edit timestamp..\n"); + try { + TopDocs topDocuments = luceneSearcher.search( + new MatchAllDocsQuery(), + 1000000 + ); + + Card card; + for( int i = 0; i < topDocuments.scoreDocs.length; i++ ) { + Document document = luceneSearcher.doc( topDocuments.scoreDocs[i].doc ); + card = cardFromDocument( document ); + cardUpdate( card, false ); + } + + searcherRefresh(); + + } catch( IOException e ) { + throw new RuntimeException(e); + } + System.out.print("Database: finished resaving all cards.\n"); + } + + private void searcherRefresh() + { + try { + luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); + } catch( IOException e ) { + throw new RuntimeException(e); + } } - hideQueries = new Query[Card.HIDE_TAGS.length+Card.HIDE_TAG_VALUES.length/2]; - int pos = 0; - - for( int i = 0; i < Card.HIDE_TAGS.length; i++ ) { - hideQueries[pos] = new WildcardQuery( new Term(Card.HIDE_TAGS[i], "*") ); - pos += 1; - } - - for( int i = 0; i < Card.HIDE_TAG_VALUES.length/2; i++ ) { - hideQueries[pos] = new TermQuery( new Term(Card.HIDE_TAG_VALUES[i*2], Card.HIDE_TAG_VALUES[i*2+1]) ); - pos += 1; - } - - } + private Document documentByIdentifier( long identifier ) + { - public void databaseCommit() - { - System.out.print( "Saving database to disk..\n" ); - try { - luceneWriter.commit(); - } catch( IOException e ) { - throw new RuntimeException(e); - } - } - - public void databaseResaveAll() - { - System.out.print("Database: resaving all cards without modifying edit timestamp..\n"); - try { - TopDocs topDocuments = luceneSearcher.search( - new MatchAllDocsQuery(), - 1000000 - ); - - Card card; - for( int i = 0; i < topDocuments.scoreDocs.length; i++ ) { - Document document = luceneSearcher.doc( topDocuments.scoreDocs[i].doc ); - card = cardFromDocument( document ); - cardUpdate( card, false ); - } - - searcherRefresh(); - - } catch( IOException e ) { - throw new RuntimeException(e); - } - System.out.print("Database: finished resaving all cards.\n"); - } - - private void searcherRefresh() - { - try { - luceneSearcher = new IndexSearcher( luceneWriter.getReader() ); - } catch( IOException e ) { - throw new RuntimeException(e); - } - } - - private Document documentByIdentifier( long identifier ) - { + try { + TopDocs topDocuments = luceneSearcher.search( NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true ), 1 ); - try { - TopDocs topDocuments = luceneSearcher.search( NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true ), 1 ); - - if( topDocuments.scoreDocs.length == 0 ) { - return null; - } - - return luceneSearcher.doc( topDocuments.scoreDocs[0].doc ); - } catch( IOException e ) { - throw new RuntimeException(e); - } - - } - - private Document cardToDocument( Card card ) - { - - Document document = new Document(); - - String search = ""; - for( String tag : card.tags.keySet() ) { - Set<Object> values = card.tags.get( tag ); - for( Object value : values ) { + if( topDocuments.scoreDocs.length == 0 ) { + return null; + } - /* Building analyzed-only search tag. */ - if( - ( tag.equals(Card.TAG_TITLE) || tag.equals(Card.TAG_CONTENT) ) - && value != null - - ) { - search += value.toString()+" "; - - } else if( tag.length() == 0 || tag.charAt(0) != '_' ) { - if( value == null ) { - search += tag+" "; - } else { - search += tag+" "+value.toString()+" "; - } + return luceneSearcher.doc( topDocuments.scoreDocs[0].doc ); + } catch( IOException e ) { + throw new RuntimeException(e); } - - if( value == null || "".equals(value) ) { - if( !tag.equals("") ) { - /* It seems that if a field with empty string value is analyzed, it isn't searchable at all. */ - document.add( new Field( tag, "", Field.Store.YES, Field.Index.NOT_ANALYZED ) ); - } - } 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 ); - } - } - } - document.add( new Field( Card.TAG_SEARCH, search, Field.Store.NO, Field.Index.ANALYZED ) ); - return document; - - } - - private Card cardFromDocument( Document document ) - { - - Card card = new Card(); - - for( Fieldable field : document.getFields() ) { - /** TODO: Find how to get NumericField from document. */ - String value = field.stringValue(); - card.tagValueAdd( field.name(), value.equals("") ? null : value ); } - card.tagValueSetOnly( Card.TAG_IDENTIFIER, Long.valueOf( document.get( Card.TAG_IDENTIFIER ) ) ); + private Document cardToDocument( Card card ) + { + + Document document = new Document(); - return card; - - } - - public long cardAdd( Card card ) - { + String search = ""; + for( String tag : card.tags.keySet() ) { + Set<Object> values = card.tags.get( tag ); + for( Object value : values ) { - highestIdentifier++; - card.tagValueSetOnly( Card.TAG_IDENTIFIER, new Long( highestIdentifier ) ); - card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) ); + /* Building analyzed-only search tag. */ + if( + ( tag.equals(Card.TAG_TITLE) || tag.equals(Card.TAG_CONTENT) ) + && value != null + + ) { + search += value.toString()+" "; - try { - luceneWriter.addDocument( cardToDocument( card ) ); - } catch( IOException e ) { - throw new RuntimeException(e); - } - - System.out.print( "Added card with identifier "+Long.toString(highestIdentifier)+": '"+card.titleGet()+"'\n" ); - searcherRefresh(); - //luceneWriter.commit(); + } else if( tag.length() == 0 || tag.charAt(0) != '_' ) { + if( value == null ) { + search += tag+" "; + } else { + search += tag+" "+value.toString()+" "; + } + } - return highestIdentifier; - - } - - public void cardUpdate( Card card, boolean userEdit ) - { + if( value == null || "".equals(value) ) { + if( !tag.equals("") ) { + /* It seems that if a field with empty string value is analyzed, it isn't searchable at all. */ + document.add( new Field( tag, "", Field.Store.YES, Field.Index.NOT_ANALYZED ) ); + } + } 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 ); + } + } + } + document.add( new Field( Card.TAG_SEARCH, search, Field.Store.NO, Field.Index.ANALYZED ) ); - TopDocs topDocuments; - Query query = NumericRangeQuery.newLongRange( card.TAG_IDENTIFIER, card.identifierGet(), card.identifierGet(), true, true ); - try { - topDocuments = luceneSearcher.search( query, 1 ); - } catch( IOException e ) { - throw new RuntimeException(e); + return document; + } - if( topDocuments.scoreDocs.length == 0 ) { - throw new RuntimeException( "Failed to update card with identifier "+Long.toString( card.identifierGet() )+", not found." ); + private Card cardFromDocument( Document document ) + { + + Card card = new Card(); + + for( Fieldable field : document.getFields() ) { + /** TODO: Find how to get NumericField from document. */ + String value = field.stringValue(); + card.tagValueAdd( field.name(), value.equals("") ? null : value ); + } + + card.tagValueSetOnly( Card.TAG_IDENTIFIER, Long.valueOf( document.get( Card.TAG_IDENTIFIER ) ) ); + + return card; + + } + + public long cardAdd( Card card ) + { + + highestIdentifier++; + card.tagValueSetOnly( Card.TAG_IDENTIFIER, new Long( highestIdentifier ) ); + card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) ); + + try { + luceneWriter.addDocument( cardToDocument( card ) ); + } catch( IOException e ) { + throw new RuntimeException(e); + } + + System.out.print( "Added card with identifier "+Long.toString(highestIdentifier)+": '"+card.titleGet()+"'\n" ); + searcherRefresh(); + //luceneWriter.commit(); + + return highestIdentifier; + } - card.tagValueSetOnly( Card.TAG_SAVED, new Long( System.currentTimeMillis() ) ); - if( userEdit ) { - card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) ); - } - - int documentNumber = topDocuments.scoreDocs[0].doc; + public void cardUpdate( Card card, boolean userEdit ) + { - try { - luceneWriter.deleteDocuments( query ); - luceneWriter.addDocument( cardToDocument( card ) ); - } catch( IOException e ) { - throw new RuntimeException(e); - } - System.out.print( "Updated card with identifier "+Long.toString(card.identifierGet())+": '"+card.titleGet()+"'\n" ); - searcherRefresh(); - //luceneWriter.commit(); - - } + TopDocs topDocuments; + Query query = NumericRangeQuery.newLongRange( card.TAG_IDENTIFIER, card.identifierGet(), card.identifierGet(), true, true ); + try { + topDocuments = luceneSearcher.search( query, 1 ); + } catch( IOException e ) { + throw new RuntimeException(e); + } - public void cardDelete( Card card ) - { - cardDelete( card, false ); - } + if( topDocuments.scoreDocs.length == 0 ) { + throw new RuntimeException( "Failed to update card with identifier "+Long.toString( card.identifierGet() )+", not found." ); + } - public void cardDelete( Card card, boolean cautious ) - { - if( cautious ) { - String tag; - if( (tag = card.<String>tagGetAs(Card.TAG_BOARD_COLUMN_CARD)) != null && tag.equals(Card.VALUE_BOARD_COLUMN_CARD_ONLY) ) { - //pass - } else { - return; /* Don't delete. */ - } + card.tagValueSetOnly( Card.TAG_SAVED, new Long( System.currentTimeMillis() ) ); + if( userEdit ) { + card.tagValueSetOnly( Card.TAG_LAST_EDIT, new Long( System.currentTimeMillis() ) ); + } + + int documentNumber = topDocuments.scoreDocs[0].doc; + + try { + luceneWriter.deleteDocuments( query ); + luceneWriter.addDocument( cardToDocument( card ) ); + } catch( IOException e ) { + throw new RuntimeException(e); + } + System.out.print( "Updated card with identifier "+Long.toString(card.identifierGet())+": '"+card.titleGet()+"'\n" ); + searcherRefresh(); + } - String tag; - Card[] cards; - if( card.tagHas(Card.TAG_BOARD) ) { - tag = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMNS, ""); - cards = TagUtility.parseCardList(tag); - for( int i = 0; i < cards.length; i++ ) { - if( cards[i] == null ) { - continue; - } - cardDelete( cards[i], false ); - } - } - if( card.tagHas(Card.TAG_BOARD_COLUMN) ) { - tag = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMN_CARDS, ""); - cards = TagUtility.parseCardList(tag); - for( int i = 0; i < cards.length; i++ ) { - if( cards[i] == null ) { - continue; - } - cardDelete( cards[i], true ); - } + + public void cardDelete( Card card ) + { + cardDelete( card, false ); } - cardDeleteRaw(card.identifierGet()); - - } + public void cardDelete( Card card, boolean cautious ) + { + if( cautious ) { + String tag; + if( (tag = card.<String>tagGetAs(Card.TAG_BOARD_COLUMN_CARD)) != null && tag.equals(Card.VALUE_BOARD_COLUMN_CARD_ONLY) ) { + //pass + } else { + return; /* Don't delete. */ + } + } + String tag; + Card[] cards; + if( card.tagHas(Card.TAG_BOARD) ) { + tag = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMNS, ""); + cards = TagUtility.parseCardList(tag); + for( int i = 0; i < cards.length; i++ ) { + if( cards[i] == null ) { + continue; + } + cardDelete( cards[i], false ); + } + } + if( card.tagHas(Card.TAG_BOARD_COLUMN) ) { + tag = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMN_CARDS, ""); + cards = TagUtility.parseCardList(tag); + for( int i = 0; i < cards.length; i++ ) { + if( cards[i] == null ) { + continue; + } + cardDelete( cards[i], true ); + } + } + + cardDeleteRaw(card.identifierGet()); + + } - public void cardDeleteByIdentifier( long identifier ) - { - cardDeleteByIdentifier( identifier, false ); - } - - public void cardDeleteByIdentifier( long identifier, boolean cautious ) - { - Card card = cardGetByIdentifier(identifier); - if( card != null ) { - cardDelete(card); - } else { - throw new RuntimeException( "Failed to delete card by identifier "+Long.toString(identifier)+", not found." ); + public void cardDeleteByIdentifier( long identifier ) + { + cardDeleteByIdentifier( identifier, false ); + } + + public void cardDeleteByIdentifier( long identifier, boolean cautious ) + { + Card card = cardGetByIdentifier(identifier); + if( card != null ) { + cardDelete(card); + } else { + throw new RuntimeException( "Failed to delete card by identifier "+Long.toString(identifier)+", not found." ); + } } - } + + public void cardDeleteRaw( long identifier ) + { + TopDocs topDocuments; + Query query = NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true ); + try { + topDocuments = luceneSearcher.search( query, 1 ); + } catch( IOException e ) { + throw new RuntimeException(e); + } - public void cardDeleteRaw( long identifier ) - { - TopDocs topDocuments; - Query query = NumericRangeQuery.newLongRange( Card.TAG_IDENTIFIER, identifier, identifier, true, true ); - try { - topDocuments = luceneSearcher.search( query, 1 ); - } catch( IOException e ) { - throw new RuntimeException(e); + if( topDocuments.scoreDocs.length == 0 ) { + throw new RuntimeException( "Failed to delete card with identifier "+Long.toString( identifier )+", not found." ); + } + + int documentNumber = topDocuments.scoreDocs[0].doc; + + try { + luceneWriter.deleteDocuments( query ); + } catch( IOException e ) { + throw new RuntimeException(e); + } + System.out.print("Deleted card with identifier "+Long.toString(identifier)+"\n"); + searcherRefresh(); + } - if( topDocuments.scoreDocs.length == 0 ) { - throw new RuntimeException( "Failed to delete card with identifier "+Long.toString( identifier )+", not found." ); - } - - int documentNumber = topDocuments.scoreDocs[0].doc; + public Card cardGetByIdentifier( long identifier ) + { + + Document document = documentByIdentifier( identifier ); - try { - luceneWriter.deleteDocuments( query ); - } catch( IOException e ) { - throw new RuntimeException(e); + if( document == null ) { + return null; + } + + return cardFromDocument( document ); + } - System.out.print("Deleted card with identifier "+Long.toString(identifier)+"\n"); - searcherRefresh(); - - } + + /** Return up to 'amount' of recently modified cards. */ + public Card[] searchTopRecent( int amount ) + { + BooleanQuery finalQuery = new BooleanQuery(); - public Card cardGetByIdentifier( long identifier ) - { - - Document document = documentByIdentifier( identifier ); + finalQuery.add( new MatchAllDocsQuery(), BooleanClause.Occur.SHOULD ); + for( int i = 0; i < hideQueries.length; i++ ) { + finalQuery.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); + } - if( document == null ) { - return null; - } - - return cardFromDocument( document ); - - } + try { + TopDocs topDocuments = luceneSearcher.search( + finalQuery, + null, + amount, + new Sort( new SortField( Card.TAG_LAST_EDIT, SortField.LONG, true ) ) + ); - /** Return up to 'amount' of recently modified cards. */ - public Card[] searchTopRecent( int amount ) - { - BooleanQuery finalQuery = new BooleanQuery(); + Card[] cards = new Card[topDocuments.scoreDocs.length]; - finalQuery.add( new MatchAllDocsQuery(), BooleanClause.Occur.SHOULD ); - for( int i = 0; i < hideQueries.length; i++ ) { - finalQuery.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); + for( int i = 0; i < topDocuments.scoreDocs.length; i++ ) { + Document document = luceneSearcher.doc( topDocuments.scoreDocs[i].doc ); + cards[i] = cardFromDocument( document ); + } + + return cards; + + } catch( IOException e ) { + throw new RuntimeException(e); + } } - - try { - TopDocs topDocuments = luceneSearcher.search( - finalQuery, - null, - amount, - new Sort( new SortField( Card.TAG_LAST_EDIT, SortField.LONG, true ) ) - ); + + public Card[] searchSimple( String query ) + { + + Query parsedQuery; + BooleanQuery finalQuery; - 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 ); - } + try { + QueryParser queryParser = new QueryParser( + LUCENE_VERSION, + Card.TAG_SEARCH, + new StandardAnalyzer(LUCENE_VERSION) + ); - return cards; - - } catch( IOException e ) { - throw new RuntimeException(e); - } - } - - public Card[] searchSimple( String query ) - { + queryParser.setAllowLeadingWildcard( true ); + + parsedQuery = queryParser.parse( query ); - Query parsedQuery; - BooleanQuery finalQuery; - - try { - QueryParser queryParser = new QueryParser( - LUCENE_VERSION, - Card.TAG_SEARCH, - new StandardAnalyzer(LUCENE_VERSION) - ); + } catch( ParseException e ) { + System.out.print( "Search query parsing exception, returning zero results: "+e.getMessage()+"\n" ); + return new Card[0]; + } + + finalQuery = new BooleanQuery(); + + finalQuery.add( parsedQuery, BooleanClause.Occur.SHOULD ); + for( int i = 0; i < hideQueries.length; i++ ) { + finalQuery.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); + } + + try { - queryParser.setAllowLeadingWildcard( true ); - - parsedQuery = queryParser.parse( query ); - - } catch( ParseException e ) { - System.out.print( "Search query parsing exception, returning zero results: "+e.getMessage()+"\n" ); - return new Card[0]; - } - - finalQuery = new BooleanQuery(); + TopDocs hits = luceneSearcher.search( finalQuery, 32 ); + Card[] cards = new Card[hits.scoreDocs.length]; - finalQuery.add( parsedQuery, BooleanClause.Occur.SHOULD ); - for( int i = 0; i < hideQueries.length; i++ ) { - finalQuery.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); + for( int i = 0; i < hits.scoreDocs.length; i++ ) { + Document document = luceneSearcher.doc( hits.scoreDocs[i].doc ); + cards[i] = cardFromDocument( document ); + } + + return cards; + + } catch( IOException e ) { + throw new RuntimeException(e); + } + } - - try { - - TopDocs hits = luceneSearcher.search( finalQuery, 32 ); - Card[] cards = new Card[hits.scoreDocs.length]; - - for( int i = 0; i < hits.scoreDocs.length; i++ ) { - Document document = luceneSearcher.doc( hits.scoreDocs[i].doc ); - cards[i] = cardFromDocument( document ); - } - - return cards; - - } catch( IOException e ) { - throw new RuntimeException(e); - } - - } + + public Card[] searchCustom( Query query, int limit, boolean useIgnores ) + { + + if( useIgnores ) { + BooleanQuery withIgnores = new BooleanQuery(); - public Card[] searchCustom( Query query, int limit, boolean useIgnores ) - { + withIgnores.add( query, BooleanClause.Occur.SHOULD ); + for( int i = 0; i < hideQueries.length; i++ ) { + withIgnores.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); + } - if( useIgnores ) { - BooleanQuery withIgnores = new BooleanQuery(); + query = withIgnores; + + } - withIgnores.add( query, BooleanClause.Occur.SHOULD ); - for( int i = 0; i < hideQueries.length; i++ ) { - withIgnores.add( hideQueries[i], BooleanClause.Occur.MUST_NOT ); - } + try { + + TopDocs hits = luceneSearcher.search( query, limit ); + Card[] cards = new Card[hits.scoreDocs.length]; - query = withIgnores; - + for( int i = 0; i < hits.scoreDocs.length; i++ ) { + Document document = luceneSearcher.doc( hits.scoreDocs[i].doc ); + cards[i] = cardFromDocument( document ); + } + + return cards; + + } catch( IOException e ) { + throw new RuntimeException(e); + } + } - - try { - - TopDocs hits = luceneSearcher.search( query, limit ); - Card[] cards = new Card[hits.scoreDocs.length]; - - for( int i = 0; i < hits.scoreDocs.length; i++ ) { - Document document = luceneSearcher.doc( hits.scoreDocs[i].doc ); - cards[i] = cardFromDocument( document ); - } - - return cards; - - } catch( IOException e ) { - throw new RuntimeException(e); - } - - } }
--- a/src/junotu/GUIToolbox.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/GUIToolbox.java Thu Apr 06 01:44:10 2023 +0200 @@ -13,118 +13,123 @@ public class GUIToolbox { - /** Source: https://stackoverflow.com/a/2814718 */ - public static class JPanelScrollable extends JPanel implements Scrollable { + /** Source: https://stackoverflow.com/a/2814718 */ + public static class JPanelScrollable extends JPanel implements Scrollable { + + public boolean scrollVertical = false; + + public JPanelScrollable() + { + super(); + } + + public JPanelScrollable( LayoutManager layout ) + { + super( layout ); + } + + public Dimension getPreferredScrollableViewportSize() + { + return getPreferredSize(); + } - public boolean scrollVertical = false; + public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) + { + return 10; + } + + public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction ) + { + return ((orientation == SwingConstants.VERTICAL) ? visibleRect.height : visibleRect.width) - 10; + } - public JPanelScrollable() - { - super(); + public boolean getScrollableTracksViewportWidth() + { + return !scrollVertical; + } + + public boolean getScrollableTracksViewportHeight() + { + return scrollVertical; + } } - public JPanelScrollable( LayoutManager layout ) + public static final int componentGetIndex( Component component ) { - super( layout ); - } - - public Dimension getPreferredScrollableViewportSize() { - return getPreferredSize(); - } - - public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) { - return 10; - } - - public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction ) { - return ((orientation == SwingConstants.VERTICAL) ? visibleRect.height : visibleRect.width) - 10; - } - - public boolean getScrollableTracksViewportWidth() { - return !scrollVertical; - } - - public boolean getScrollableTracksViewportHeight() { - return scrollVertical; - } - } + if (component != null && component.getParent() != null) { + Container parent = component.getParent(); + for( int i = 0; i < parent.getComponentCount(); i++ ) { + if( parent.getComponent(i) == component ) + return i; + } + } - public static final int componentGetIndex( Component component ) - { - if (component != null && component.getParent() != null) { - Container parent = component.getParent(); - for( int i = 0; i < parent.getComponentCount(); i++ ) { - if( parent.getComponent(i) == component ) - return i; - } - } - - return -1; - } - - public static class CardEditLayout implements LayoutManager - { - public CardEditLayout() {} - - public Dimension minimumLayoutSize( Container parent ) - { - return new Dimension( 1, 1 ); + return -1; } - /* TODO: Does this need to be precise? */ - public Dimension preferredLayoutSize( Container parent ) - { - - Dimension preferred = new Dimension(); - - Container parentparent = parent.getParent(); - preferred.width = parentparent.getSize().width; - - Component[] components = parent.getComponents(); - assert( components.length == 3 ); - - //Component title = components[0]; - Component content = components[1]; - Component tags = components[2]; - - content.setMaximumSize( new Dimension( preferred.width, Integer.MAX_VALUE ) ); - tags.setMaximumSize( new Dimension( preferred.width, Integer.MAX_VALUE ) ); - - preferred.height = 32+8+4+Math.max(content.getPreferredSize().height, 32*12)+tags.getPreferredSize().height+512; - - return preferred; - } - - public void addLayoutComponent( String name, Component comp ) {} - public void removeLayoutComponent( Component comp ) {} - - public void layoutContainer( Container parent ) + public static class CardEditLayout implements LayoutManager { - Component[] components = parent.getComponents(); - assert( components.length == 3 ); - - Component title = components[0]; - Component content = components[1]; - Component tags = components[2]; - - int width = (preferredLayoutSize( parent )).width; + public CardEditLayout() {} + + public Dimension minimumLayoutSize( Container parent ) + { + return new Dimension( 1, 1 ); + } + + /* TODO: Does this need to be precise? */ + public Dimension preferredLayoutSize( Container parent ) + { + + Dimension preferred = new Dimension(); - content.setMaximumSize( new Dimension( width, Integer.MAX_VALUE ) ); - tags.setMaximumSize( new Dimension( width, Integer.MAX_VALUE ) ); + Container parentparent = parent.getParent(); + preferred.width = parentparent.getSize().width; + + Component[] components = parent.getComponents(); + assert( components.length == 3 ); + + //Component title = components[0]; + Component content = components[1]; + Component tags = components[2]; + + content.setMaximumSize( new Dimension( preferred.width, Integer.MAX_VALUE ) ); + tags.setMaximumSize( new Dimension( preferred.width, Integer.MAX_VALUE ) ); + + preferred.height = 32+8+4+Math.max(content.getPreferredSize().height, 32*12)+tags.getPreferredSize().height+512; + + return preferred; + } - int contentHeight = Math.max(content.getPreferredSize().height, 32*12); - int tagsHeight = (tags.getPreferredSize()).height+512; + public void addLayoutComponent( String name, Component comp ) {} + public void removeLayoutComponent( Component comp ) {} + + public void layoutContainer( Container parent ) + { + Component[] components = parent.getComponents(); + assert( components.length == 3 ); + + Component title = components[0]; + Component content = components[1]; + Component tags = components[2]; + + int width = (preferredLayoutSize( parent )).width; + + content.setMaximumSize( new Dimension( width, Integer.MAX_VALUE ) ); + tags.setMaximumSize( new Dimension( width, Integer.MAX_VALUE ) ); - int y = 0; - title.setBounds( 0, y, width, 32+8 ); /* Underscores don't fit if I set height to font height exactly. :/ */ - y += 32+8; - y += 4; - content.setBounds( 0, y, width, contentHeight ); - y += contentHeight; - tags.setBounds( 0, y, width, tagsHeight ); - y += tagsHeight; - + int contentHeight = Math.max(content.getPreferredSize().height, 32*12); + int tagsHeight = (tags.getPreferredSize()).height+512; + + int y = 0; + title.setBounds( 0, y, width, 32+8 ); /* Underscores don't fit if I set height to font height exactly. :/ */ + y += 32+8; + y += 4; + content.setBounds( 0, y, width, contentHeight ); + y += contentHeight; + tags.setBounds( 0, y, width, tagsHeight ); + y += tagsHeight; + + } } - } - + }
--- a/src/junotu/Main.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/Main.java Thu Apr 06 01:44:10 2023 +0200 @@ -17,168 +17,168 @@ public class Main { - public static final String PROGRAM_NAME = "Junotu"; - public static final int MAX_WINDOWS = 8; + public static final String PROGRAM_NAME = "Junotu"; + public static final int MAX_WINDOWS = 8; + + public static Database database; + public static Window[] windows = new Window[MAX_WINDOWS]; + public static Desktop desktop; - public static Database database; - public static Window[] windows = new Window[MAX_WINDOWS]; - public static Desktop desktop; - - public static void main(String[] args) throws Exception - { - database = new Database(); - desktop = Desktop.getDesktop(); + public static void main(String[] args) throws Exception + { + database = new Database(); + desktop = Desktop.getDesktop(); + + //database.databaseResaveAll(); - //database.databaseResaveAll(); - - SwingUtilities.invokeLater( - new Runnable() { - public void run() - { - windowAdd( Tab.SEARCH ); - } - } - ); - } + SwingUtilities.invokeLater( + new Runnable() { + public void run() + { + windowAdd( Tab.SEARCH ); + } + } + ); + } - public static Window windowAdd( Tab tab ) - { - for( int i = 0; i < windows.length; i++ ) { - if( windows[i] == null ) { - windows[i] = new Window( tab ); - return windows[i]; - } + public static Window windowAdd( Tab tab ) + { + for( int i = 0; i < windows.length; i++ ) { + if( windows[i] == null ) { + windows[i] = new Window( tab ); + return windows[i]; + } + } + System.out.print("Reached window limit! (Maximum "+Integer.toString(MAX_WINDOWS)+" windows.)\n"); + return null; } - System.out.print("Reached window limit! (Maximum "+Integer.toString(MAX_WINDOWS)+" windows.)\n"); - return null; - } - public static void windowClose( Window window ) - { - int openWindowCount = 0; - for( int i = 0; i < windows.length; i++ ) { - if( windows[i] == window ) { - System.out.print( "Closing window slot "+Integer.toString(i)+": '"+window.getTitle()+"'.\n" ); - window.dispose(); - windows[i] = null; - } - if( windows[i] != null ) { - openWindowCount++; - } + public static void windowClose( Window window ) + { + int openWindowCount = 0; + for( int i = 0; i < windows.length; i++ ) { + if( windows[i] == window ) { + System.out.print( "Closing window slot "+Integer.toString(i)+": '"+window.getTitle()+"'.\n" ); + window.dispose(); + windows[i] = null; + } + if( windows[i] != null ) { + openWindowCount++; + } + } + if( openWindowCount == 0 ) { + System.out.print( "No windows open, closing program..\n" ); + database.databaseCommit(); + System.exit(0); + } } - if( openWindowCount == 0 ) { - System.out.print( "No windows open, closing program..\n" ); - database.databaseCommit(); - System.exit(0); - } - } - public static Window windowGetActive() - { - for( int i = 0; i < windows.length; i++ ) { - if( windows[i] != null && windows[i].isActive() ) { - return windows[i]; - } + public static Window windowGetActive() + { + for( int i = 0; i < windows.length; i++ ) { + if( windows[i] != null && windows[i].isActive() ) { + return windows[i]; + } + } + return null; } - return null; - } - public static void refreshSearches() - { - for( int i = 0; i < windows.length; i++ ) { - if( windows[i] != null ) { - Window window = windows[i]; - window.tabSearch.dirty = true; - if( window.tabCurrent() == Tab.SEARCH ) { - window.tabSearch.refreshSearch(); + public static void refreshSearches() + { + for( int i = 0; i < windows.length; i++ ) { + if( windows[i] != null ) { + Window window = windows[i]; + window.tabSearch.dirty = true; + if( window.tabCurrent() == Tab.SEARCH ) { + window.tabSearch.refreshSearch(); + } + } } - } } - } - public static void actionCardCreate( Window window ) - { - //window = windowGetActive(); - window.tabSwitch( Tab.EDIT ); - window.tabEdit.cardCreate(); - System.out.print( "Opening edit tab for newly created card.\n" ); - } + public static void actionCardCreate( Window window ) + { + //window = windowGetActive(); + window.tabSwitch( Tab.EDIT ); + window.tabEdit.cardCreate(); + System.out.print( "Opening edit tab for newly created card.\n" ); + } - public static void actionCardEdit( Window window, long identifier ) - { - //window = windowGetActive(); - Card card = database.cardGetByIdentifier( identifier ); - window.tabSwitch( Tab.EDIT ); - window.tabEdit.cardEdit( card ); - System.out.print( "Opening edit tab to edit '"+card.titleGet()+"'.\n" ); - } - - public static void actionOpenURI( String uri ) - { - if( desktop == null ) { - System.err.print("Failed to open URI: No 'Desktop' instance.\n"); - return; + public static void actionCardEdit( Window window, long identifier ) + { + //window = windowGetActive(); + Card card = database.cardGetByIdentifier( identifier ); + window.tabSwitch( Tab.EDIT ); + window.tabEdit.cardEdit( card ); + System.out.print( "Opening edit tab to edit '"+card.titleGet()+"'.\n" ); } - try { - if( desktop.isSupported( Desktop.Action.BROWSE ) ) { - URI parsed = new URI(uri); - desktop.browse(parsed); - } else if( System.getProperty("os.name").equals("Linux") ) { - System.out.print("URI: 'Browse' action is not supported, trying Linux-specific workarounds..\n"); - /* Try some common commands. Loosely inspired by 'https://stackoverflow.com/a/18004334'. */ - final String openCommands[] = { - "xdg-open", - //"gnome-open", - //"kde-open", - }; - String command[] = new String[2]; - command[1] = uri; - for( int i = 0; i < openCommands.length; i++ ) { - System.out.print("\tRunning '"+openCommands[i]+" "+uri+"'..\n"); - command[0] = openCommands[i]; - Process process; - boolean success = false; - try { - process = Runtime.getRuntime().exec( command, null, null ); - if( process.exitValue() == 0 ) { - success = true; + + public static void actionOpenURI( String uri ) + { + if( desktop == null ) { + System.err.print("Failed to open URI: No 'Desktop' instance.\n"); + return; + } + try { + if( desktop.isSupported( Desktop.Action.BROWSE ) ) { + URI parsed = new URI(uri); + desktop.browse(parsed); + } else if( System.getProperty("os.name").equals("Linux") ) { + System.out.print("URI: 'Browse' action is not supported, trying Linux-specific workarounds..\n"); + /* Try some common commands. Loosely inspired by 'https://stackoverflow.com/a/18004334'. */ + final String openCommands[] = { + "xdg-open", + //"gnome-open", + //"kde-open", + }; + String command[] = new String[2]; + command[1] = uri; + for( int i = 0; i < openCommands.length; i++ ) { + System.out.print("\tRunning '"+openCommands[i]+" "+uri+"'..\n"); + command[0] = openCommands[i]; + Process process; + boolean success = false; + try { + process = Runtime.getRuntime().exec( command, null, null ); + if( process.exitValue() == 0 ) { + success = true; + } + } catch( IOException e ) { + /* I am assuming it means that the command is missing. */ + } catch( IllegalThreadStateException e ) { + /* Process is still running. Count as success. */ + success = true; + } + if( success ) { + System.out.print("URI: '"+openCommands[i]+"' seems to have worked.\n"); + return; + } + } + System.err.print("Failed to open URI: All Linux-specific workarounds seem to have failed.\n"); + } else { + System.err.print("Failed to open URI: 'Browse' action is not supported, and system-specific workarounds waren't triggered. (OS name: '"+System.getProperty("os.name")+"')\n"); } - } catch( IOException e ) { - /* I am assuming it means that the command is missing. */ - } catch( IllegalThreadStateException e ) { - /* Process is still running. Count as success. */ - success = true; - } - if( success ) { - System.out.print("URI: '"+openCommands[i]+"' seems to have worked.\n"); - return; - } + } catch( Exception e ) { + throw new RuntimeException(e); } - System.err.print("Failed to open URI: All Linux-specific workarounds seem to have failed.\n"); - } else { - System.err.print("Failed to open URI: 'Browse' action is not supported, and system-specific workarounds waren't triggered. (OS name: '"+System.getProperty("os.name")+"')\n"); - } - } catch( Exception e ) { - throw new RuntimeException(e); } - } - public static String clipboardGet() - { - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - try { - return (String)clipboard.getData( DataFlavor.stringFlavor ); - } catch( Exception e ) { - return ""; + public static String clipboardGet() + { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + try { + return (String)clipboard.getData( DataFlavor.stringFlavor ); + } catch( Exception e ) { + return ""; + } } - } - public static void clipboardSet( String string ) - { - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - StringSelection transferable = new StringSelection(string); - System.out.print("Set system clipboard to '"+string+"'.\n"); - clipboard.setContents( transferable, transferable ); - } - + public static void clipboardSet( String string ) + { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + StringSelection transferable = new StringSelection(string); + System.out.print("Set system clipboard to '"+string+"'.\n"); + clipboard.setContents( transferable, transferable ); + } + }
--- a/src/junotu/TabBoard.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/TabBoard.java Thu Apr 06 01:44:10 2023 +0200 @@ -50,624 +50,629 @@ public class TabBoard extends JPanel implements ActionListener, MouseListener { - final static int COLUMN_CONTENT_WIDTH = 256; - final static int COLUMN_WIDTH = COLUMN_CONTENT_WIDTH+16; + final static int COLUMN_CONTENT_WIDTH = 256; + final static int COLUMN_WIDTH = COLUMN_CONTENT_WIDTH+16; + + public final String KEY_ACTION_BACK = "back"; + public final String KEY_ACTION_COMMIT = "commit"; + public final String KEY_ACTION_CARD_UP = "card_up"; + public final String KEY_ACTION_CARD_DOWN = "card_down"; + public final String KEY_ACTION_CARD_FULL_UP = "card_full_up"; + public final String KEY_ACTION_CARD_FULL_DOWN = "card_full_down"; + public final String KEY_ACTION_CARD_LEFT = "card_left"; + public final String KEY_ACTION_CARD_RIGHT = "card_right"; + public final String KEY_ACTION_CARD_FULL_LEFT = "card_full_left"; + public final String KEY_ACTION_CARD_FULL_RIGHT = "card_full_right"; + + private class ColumnWidget extends JPanel implements ActionListener, MouseListener { + + long identifier; + boolean newCard; + + JTextField titleEdit; + TitledBorder titledBorder; + Box cards; + JButton addCard; + + public ColumnWidget( TabBoard parent, Card card ) + { + this.setLayout( new GridBagLayout() ); + + titleEdit = new JTextField(""); + cards = Box.createVerticalBox(); + addCard = new JButton("+"); + + titleEdit.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); + addCard.setFont( new Font( "Monospaced", Font.BOLD, 32 ) ); + + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = 1.0; + constraints.weighty = 0.0; + constraints.gridx = 0; + constraints.gridy = 0; + + this.add( titleEdit, constraints ); + constraints.gridy++; + this.add( cards, constraints ); + constraints.gridy++; + this.add( addCard, constraints ); + constraints.gridy++; + constraints.weighty = 1.0; + this.add( Box.createVerticalGlue(), constraints ); + + addCard.setPreferredSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); + addCard.setMaximumSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); + addCard.setAlignmentX( JButton.CENTER_ALIGNMENT ); + + //this.setPreferredSize( new Dimension( COLUMN_WIDTH, 384 ) ); + this.setMaximumSize( new Dimension( COLUMN_WIDTH, 1000000 ) ); + + titleEdit.setVisible(false); + + titledBorder = BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "", + TitledBorder.LEADING, + TitledBorder.TOP, + new Font( "Monospaced", Font.BOLD, 16 ) + ); + + this.setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 0, 8, 0, 8 ), + titledBorder + ) + ); + + addMouseListener(this); + registerKeyboardAction( + this, + KEY_ACTION_CARD_UP, + KeyStroke.getKeyStroke( KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_DOWN, + KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_FULL_UP, + KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_FULL_DOWN, + KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_LEFT, + KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_RIGHT, + KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_FULL_LEFT, + KeyStroke.getKeyStroke( KeyEvent.VK_HOME, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_FULL_RIGHT, + KeyStroke.getKeyStroke( KeyEvent.VK_END, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + + addCard.addActionListener(this); + titleEdit.addFocusListener( + new FocusListener() + { + @Override + public void focusGained(FocusEvent e) {} + + @Override + public void focusLost(FocusEvent e) + { + titleCommit(); + } + } + ); + + addCard.setToolTipText("Add card."); + + newCard = card == null; + + if( newCard ) { + return; + } + + identifier = card.identifierGet(); + titleSet(card.titleGet()); + + String cardsString = card.<String>tagGetAsOr( Card.TAG_BOARD_COLUMN_CARDS, "" ); + Card[] cardsSplit = TagUtility.parseCardList(cardsString); + + for( int i = 0; i < cardsSplit.length; i++ ) { + + if( cardsSplit[i] == null ) { + System.out.print("Column '"+card.titleGet()+"', identifier "+Long.toString(card.identifierGet())+": Failed to retrieve card identifier by index "+Integer.toString(i)+". Full cards tag: '"+cardsString+"'\n"); + insertCard( null, -1 ); + continue; + } + + insertCard( cardsSplit[i], -1 ); + + } + + } + + public void titleSet( String title ) + { + titledBorder.setTitle(title); + repaint(); + } + + public String titleGet() + { + return titledBorder.getTitle(); + } - public final String KEY_ACTION_BACK = "back"; - public final String KEY_ACTION_COMMIT = "commit"; - public final String KEY_ACTION_CARD_UP = "card_up"; - public final String KEY_ACTION_CARD_DOWN = "card_down"; - public final String KEY_ACTION_CARD_FULL_UP = "card_full_up"; - public final String KEY_ACTION_CARD_FULL_DOWN = "card_full_down"; - public final String KEY_ACTION_CARD_LEFT = "card_left"; - public final String KEY_ACTION_CARD_RIGHT = "card_right"; - public final String KEY_ACTION_CARD_FULL_LEFT = "card_full_left"; - public final String KEY_ACTION_CARD_FULL_RIGHT = "card_full_right"; - - private class ColumnWidget extends JPanel implements ActionListener, MouseListener { + public void titleEdit() + { + titleEdit.setText(titleGet()); + titleEdit.setVisible(true); + titleSet(" "); + revalidate(); + titleEdit.grabFocus(); + } + + public void titleCommit() + { + if( !titleEdit.isVisible() ) { + return; + } + titleSet(titleEdit.getText()); + titleEdit.setVisible(false); + revalidate(); + } + + public void insertCard( Card card, int at ) + { + ColumnCardWidget cardWidget = new ColumnCardWidget( card ); + insertCardRaw( cardWidget, at ); + } + + public void insertCardRaw( ColumnCardWidget cardWidget, int at ) + { + if( at == -1 ) { + at = cards.getComponentCount(); + } + cardWidget.addMouseListener(this); + /* TODO: Check if works properly. */ + cards.add( cardWidget, at ); + cards.revalidate(); + } + + public void moveCard( int at, int to ) + { + if( at < 0 ) { + return; + } + ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); + boolean focused = cardWidget.isSelected(); + cards.remove(at); + cards.add( cardWidget, to ); + cards.revalidate(); + if( focused ) { + cardWidget.select(); + } + } + + public ColumnCardWidget popCard( int at ) + { + if( at < 0 ) { + return null; + } + ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); + cards.remove(at); + cardWidget.removeMouseListener(this); + return cardWidget; + } + + public int selectedCard() + { + Component[] cardList = cards.getComponents(); + for( int i = 0; i < cardList.length; i++ ) { + if( ((ColumnCardWidget)cardList[i]).isSelected() ) { + return i; + } + } + System.out.print("Selected card not found."); + return -1; + } + + public int cardCount() + { + return cards.getComponentCount(); + } + + public void save() + { + Component[] cardList = cards.getComponents(); + String cardIdentifiers = ""; + for( int i = 0; i < cardList.length; i++ ) { + ColumnCardWidget cardWidget = (ColumnCardWidget)cardList[i]; + cardWidget.save(); + + if( cardIdentifiers.length() > 0 ) { + cardIdentifiers += " "; + } + cardIdentifiers += Long.toString(cardWidget.identifier); + } + + Card card; + + if( newCard ) { + card = new Card(); + } else { + try { + card = Main.database.cardGetByIdentifier(identifier); + } catch( Exception e ) { + throw new RuntimeException(e); + } + + if( card == null ) { + throw new RuntimeException("Board column update: card not found."); + } + } + + card.titleSet( titleGet() ); + card.tagValueSetOnly( Card.TAG_BOARD_COLUMN_CARDS, cardIdentifiers ); + card.tagValueSetOnly( Card.TAG_BOARD_COLUMN, null ); + + try { + if( newCard ) { + identifier = Main.database.cardAdd( card ); + newCard = false; + } else { + Main.database.cardUpdate( card, false ); + } + } catch( Exception e ) { + throw new RuntimeException(e); + } + + } + + public void delete() + { + save(); + Main.database.cardDeleteByIdentifier(identifier); + } + + public void actionPerformed( ActionEvent e ) + { + Object source = e.getSource(); + if( source == this ) { + int selected = selectedCard(); + int length = cards.getComponentCount(); + + switch( e.getActionCommand() ) { + + case KEY_ACTION_CARD_UP: { + System.out.print("Move card up.\n"); + moveCard( selected, max(selected-1, 0) ); + break; + } + + case KEY_ACTION_CARD_DOWN: { + System.out.print("Move card down.\n"); + moveCard( selected, min(selected+1, cards.getComponentCount()-1) ); + break; + } + + case KEY_ACTION_CARD_FULL_UP: { + System.out.print("Move card full up.\n"); + moveCard( selected, 0 ); + break; + } + + case KEY_ACTION_CARD_FULL_DOWN: { + System.out.print("Move card full down.\n"); + moveCard( selected, cards.getComponentCount()-1 ); + break; + } + + } + } else if( source == addCard ) { + insertCard( null, -1 ); + } + } + + public void mouseClicked( MouseEvent e ) + { + Object source = e.getSource(); + if( source == this ) { + if( e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2 ) { + titleEdit(); + } + } else if( source instanceof ColumnCardWidget ) { + if( e.getButton() == MouseEvent.BUTTON2 ) { + ColumnCardWidget cardWidget = (ColumnCardWidget)e.getSource(); + cardWidget.delete(); + cards.remove(cardWidget); + cards.revalidate(); + } + } + } + + public void mouseEntered( MouseEvent e ) {} + public void mouseExited( MouseEvent e ) {} + public void mousePressed( MouseEvent e ) {} + public void mouseReleased( MouseEvent e ) {} + + } long identifier; - boolean newCard; - - JTextField titleEdit; - TitledBorder titledBorder; - Box cards; - JButton addCard; + JTextField title; + Box columns; + JScrollPane scroll; - public ColumnWidget( TabBoard parent, Card card ) + JButton back; + JButton addColumn; + JButton editAsCard; + + public TabBoard() { - this.setLayout( new GridBagLayout() ); - - titleEdit = new JTextField(""); - cards = Box.createVerticalBox(); - addCard = new JButton("+"); + this.setLayout( new BorderLayout() ); - titleEdit.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); - addCard.setFont( new Font( "Monospaced", Font.BOLD, 32 ) ); - - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.NORTHWEST; - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.weighty = 0.0; - constraints.gridx = 0; - constraints.gridy = 0; + title = new JTextField(""); + back = new JButton("Back"); + addColumn = new JButton("Add column"); + editAsCard = new JButton("As card"); - this.add( titleEdit, constraints ); - constraints.gridy++; - this.add( cards, constraints ); - constraints.gridy++; - this.add( addCard, constraints ); - constraints.gridy++; - constraints.weighty = 1.0; - this.add( Box.createVerticalGlue(), constraints ); + Box bottom = Box.createHorizontalBox(); + columns = Box.createHorizontalBox(); + scroll = new JScrollPane( columns ); - addCard.setPreferredSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); - addCard.setMaximumSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); - addCard.setAlignmentX( JButton.CENTER_ALIGNMENT ); - - //this.setPreferredSize( new Dimension( COLUMN_WIDTH, 384 ) ); - this.setMaximumSize( new Dimension( COLUMN_WIDTH, 1000000 ) ); + title.setFont( new Font( "Monospaced", Font.PLAIN, 32 ) ); - titleEdit.setVisible(false); + bottom.add( back ); + bottom.add( Box.createHorizontalGlue() ); + bottom.add( addColumn ); + bottom.add( editAsCard ); + this.add( title, BorderLayout.NORTH ); + this.add( scroll, BorderLayout.CENTER ); + this.add( bottom, BorderLayout.SOUTH ); - titledBorder = BorderFactory.createTitledBorder( - BorderFactory.createEtchedBorder(), - "", - TitledBorder.LEADING, - TitledBorder.TOP, - new Font( "Monospaced", Font.BOLD, 16 ) - ); + scroll.getHorizontalScrollBar().setUnitIncrement(COLUMN_WIDTH); + scroll.getVerticalScrollBar().setUnitIncrement(64); /* TODO: FIXME: Magic number. */ - this.setBorder( - BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder( 0, 8, 0, 8 ), - titledBorder - ) - ); + back.addActionListener(this); + addColumn.addActionListener(this); + editAsCard.addActionListener(this); + + registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); + registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - addMouseListener(this); - registerKeyboardAction( - this, - KEY_ACTION_CARD_UP, - KeyStroke.getKeyStroke( KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_DOWN, - KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_FULL_UP, - KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_FULL_DOWN, - KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_LEFT, - KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_RIGHT, - KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_FULL_LEFT, - KeyStroke.getKeyStroke( KeyEvent.VK_HOME, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_FULL_RIGHT, - KeyStroke.getKeyStroke( KeyEvent.VK_END, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); + back.setToolTipText("Go back to where the card was accessed from. Can also use [ESC]."); + addColumn.setToolTipText("Add new column to the board."); + editAsCard.setToolTipText("Edit the board as a regular card."); + + } + + public void boardEdit( Card card ) + { + identifier = card.identifierGet(); + + columns.removeAll(); + title.setText(card.titleGet()); + if( !card.isBoard() ) { + return; + } + + String columnsString = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMNS, ""); + Card[] columnCards = TagUtility.parseCardList(columnsString); + + for( int i = 0; i < columnCards.length; i++ ) { - addCard.addActionListener(this); - titleEdit.addFocusListener( - new FocusListener() - { - @Override - public void focusGained(FocusEvent e) {} - - @Override - public void focusLost(FocusEvent e) - { - titleCommit(); - } - } - ); + if( columnCards[i] == null ) { + System.out.print("Board '"+card.titleGet()+"': Failed to get card for column identifier index "+Integer.toString(i)+", aborting column loading. Full columns tag: '"+columnsString+"'\n"); + break; + } - addCard.setToolTipText("Add card."); + ColumnWidget column = new ColumnWidget(this, columnCards[i]); + insertColumnRaw(column); + } + } - newCard = card == null; - - if( newCard ) { - return; - } + public Card boardSave() + { + Component[] columnsList = columns.getComponents(); + String columnIdentifiers = ""; + for( int i = 0; i < columnsList.length; i++ ) { + ColumnWidget column = (ColumnWidget)columnsList[i]; + column.save(); - identifier = card.identifierGet(); - titleSet(card.titleGet()); - - String cardsString = card.<String>tagGetAsOr( Card.TAG_BOARD_COLUMN_CARDS, "" ); - Card[] cardsSplit = TagUtility.parseCardList(cardsString); - - for( int i = 0; i < cardsSplit.length; i++ ) { - - if( cardsSplit[i] == null ) { - System.out.print("Column '"+card.titleGet()+"', identifier "+Long.toString(card.identifierGet())+": Failed to retrieve card identifier by index "+Integer.toString(i)+". Full cards tag: '"+cardsString+"'\n"); - insertCard( null, -1 ); - continue; + if( columnIdentifiers.length() > 0 ) { + columnIdentifiers += " "; + } + columnIdentifiers += Long.toString(column.identifier); + } - insertCard( cardsSplit[i], -1 ); - - } - - } + Card card; + + card = Main.database.cardGetByIdentifier(identifier); - public void titleSet( String title ) - { - titledBorder.setTitle(title); - repaint(); - } + if( card == null ) { + throw new RuntimeException(); + } - public String titleGet() - { - return titledBorder.getTitle(); - } + card.titleSet( title.getText() ); + if( columnIdentifiers.length() > 0 ) { + card.tagValueSetOnly( Card.TAG_BOARD, null ); + card.tagValueSetOnly( Card.TAG_BOARD_COLUMNS, columnIdentifiers ); + } else { + card.tagRemove( Card.TAG_BOARD ); + card.tagRemove( Card.TAG_BOARD_COLUMNS ); + } - public void titleEdit() - { - titleEdit.setText(titleGet()); - titleEdit.setVisible(true); - titleSet(" "); - revalidate(); - titleEdit.grabFocus(); + Main.database.cardUpdate( card, true ); + Main.refreshSearches(); + + return card; + } - public void titleCommit() + public void boardReset() { - if( !titleEdit.isVisible() ) { - return; - } - titleSet(titleEdit.getText()); - titleEdit.setVisible(false); - revalidate(); - } - - public void insertCard( Card card, int at ) - { - ColumnCardWidget cardWidget = new ColumnCardWidget( card ); - insertCardRaw( cardWidget, at ); + title.setText(""); + columns.removeAll(); } - public void insertCardRaw( ColumnCardWidget cardWidget, int at ) + public void insertColumn() { - if( at == -1 ) { - at = cards.getComponentCount(); - } - cardWidget.addMouseListener(this); - /* TODO: Check if works properly. */ - cards.add( cardWidget, at ); - cards.revalidate(); + ColumnWidget column = new ColumnWidget(this, null); + column.titleSet("New column"); + column.addMouseListener(this); + columns.add(column); + columns.revalidate(); } - public void moveCard( int at, int to ) + public void insertColumnRaw( ColumnWidget column ) { - if( at < 0 ) { - return; - } - ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); - boolean focused = cardWidget.isSelected(); - cards.remove(at); - cards.add( cardWidget, to ); - cards.revalidate(); - if( focused ) { - cardWidget.select(); - } + column.addMouseListener(this); + columns.add(column); + columns.revalidate(); } - public ColumnCardWidget popCard( int at ) + public int findColumn( ColumnWidget columnWidget ) { - if( at < 0 ) { - return null; - } - ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); - cards.remove(at); - cardWidget.removeMouseListener(this); - return cardWidget; + Component[] columnsList = columns.getComponents(); + for( int i = 0; i < columnsList.length; i++ ) { + if( columnsList[i] == columnWidget ) { + return i; + } + } + return -1; } - public int selectedCard() + public void removeColumn( ColumnWidget columnWidget ) { - Component[] cardList = cards.getComponents(); - for( int i = 0; i < cardList.length; i++ ) { - if( ((ColumnCardWidget)cardList[i]).isSelected() ) { - return i; - } - } - System.out.print("Selected card not found."); - return -1; - } - - public int cardCount() - { - return cards.getComponentCount(); + columnWidget.delete(); + columns.remove( columnWidget ); + columns.validate(); + columns.repaint(); } - public void save() + public void moveCard( int from, int at, int to ) { - Component[] cardList = cards.getComponents(); - String cardIdentifiers = ""; - for( int i = 0; i < cardList.length; i++ ) { - ColumnCardWidget cardWidget = (ColumnCardWidget)cardList[i]; - cardWidget.save(); - - if( cardIdentifiers.length() > 0 ) { - cardIdentifiers += " "; + ColumnWidget fromColumn = (ColumnWidget)columns.getComponent(from); + ColumnWidget toColumn = (ColumnWidget)columns.getComponent(to); + ColumnCardWidget cardWidget = fromColumn.popCard(at); + if( cardWidget == null ) { + return; } - cardIdentifiers += Long.toString(cardWidget.identifier); - } - - Card card; - - if( newCard ) { - card = new Card(); - } else { - try { - card = Main.database.cardGetByIdentifier(identifier); - } catch( Exception e ) { - throw new RuntimeException(e); - } - - if( card == null ) { - throw new RuntimeException("Board column update: card not found."); - } - } - - card.titleSet( titleGet() ); - card.tagValueSetOnly( Card.TAG_BOARD_COLUMN_CARDS, cardIdentifiers ); - card.tagValueSetOnly( Card.TAG_BOARD_COLUMN, null ); - - try { - if( newCard ) { - identifier = Main.database.cardAdd( card ); - newCard = false; - } else { - Main.database.cardUpdate( card, false ); - } - } catch( Exception e ) { - throw new RuntimeException(e); - } - + toColumn.insertCardRaw(cardWidget, min(at, toColumn.cardCount()) ); + cardWidget.select(); } - public void delete() + public void buttonClickedAsCard() { - save(); - Main.database.cardDeleteByIdentifier(identifier); + Card card = boardSave(); + Window window = (Window)this.getTopLevelAncestor(); + window.tabEdit.cardEdit(card); + window.tabSwitch( Tab.EDIT ); + } + + public void buttonClickedBack() + { + boardSave(); + boardReset(); + Window window = (Window)this.getTopLevelAncestor(); + window.tabSwitch( Tab.SEARCH ); } public void actionPerformed( ActionEvent e ) { - Object source = e.getSource(); - if( source == this ) { - int selected = selectedCard(); - int length = cards.getComponentCount(); - - switch( e.getActionCommand() ) { + Object source = e.getSource(); + if( source == this ){ + switch( e.getActionCommand() ) { + + case KEY_ACTION_COMMIT: { + boardSave(); + return; + } - case KEY_ACTION_CARD_UP: { - System.out.print("Move card up.\n"); - moveCard( selected, max(selected-1, 0) ); - break; - } - - case KEY_ACTION_CARD_DOWN: { - System.out.print("Move card down.\n"); - moveCard( selected, min(selected+1, cards.getComponentCount()-1) ); - break; + case KEY_ACTION_BACK: { + buttonClickedBack(); + return; + } + + } + } else if( source == back ) { + buttonClickedBack(); + return; + } else if( source == addColumn ) { + insertColumn(); + return; + } else if( source == editAsCard ) { + buttonClickedAsCard(); + return; } - - case KEY_ACTION_CARD_FULL_UP: { - System.out.print("Move card full up.\n"); - moveCard( selected, 0 ); - break; + + if( source instanceof ColumnWidget ) { + ColumnWidget sourceColumn = (ColumnWidget)source; + int columnIndex = findColumn(sourceColumn); + switch( e.getActionCommand() ){ + + case KEY_ACTION_CARD_LEFT: { + moveCard( columnIndex, sourceColumn.selectedCard(), max( columnIndex-1, 0) ); + break; + } + case KEY_ACTION_CARD_RIGHT: { + moveCard( columnIndex, sourceColumn.selectedCard(), min( columnIndex+1, columns.getComponentCount()-1) ); + break; + } + case KEY_ACTION_CARD_FULL_LEFT: { + moveCard( columnIndex, sourceColumn.selectedCard(), 0 ); + break; + } + case KEY_ACTION_CARD_FULL_RIGHT: { + moveCard( columnIndex, sourceColumn.selectedCard(), columns.getComponentCount()-1 ); + break; + } + + } } - - case KEY_ACTION_CARD_FULL_DOWN: { - System.out.print("Move card full down.\n"); - moveCard( selected, cards.getComponentCount()-1 ); - break; - } - - } - } else if( source == addCard ) { - insertCard( null, -1 ); - } } public void mouseClicked( MouseEvent e ) { - Object source = e.getSource(); - if( source == this ) { - if( e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2 ) { - titleEdit(); + if( e.getButton() == MouseEvent.BUTTON2 ) { + if( !(e.getSource() instanceof ColumnWidget) ) + return; + + removeColumn( (ColumnWidget)e.getSource() ); } - } else if( source instanceof ColumnCardWidget ) { - if( e.getButton() == MouseEvent.BUTTON2 ) { - ColumnCardWidget cardWidget = (ColumnCardWidget)e.getSource(); - cardWidget.delete(); - cards.remove(cardWidget); - cards.revalidate(); - } - } } - + public void mouseEntered( MouseEvent e ) {} public void mouseExited( MouseEvent e ) {} public void mousePressed( MouseEvent e ) {} public void mouseReleased( MouseEvent e ) {} - - } - long identifier; - JTextField title; - Box columns; - JScrollPane scroll; - - JButton back; - JButton addColumn; - JButton editAsCard; - - public TabBoard() - { - this.setLayout( new BorderLayout() ); - - title = new JTextField(""); - back = new JButton("Back"); - addColumn = new JButton("Add column"); - editAsCard = new JButton("As card"); - - Box bottom = Box.createHorizontalBox(); - columns = Box.createHorizontalBox(); - scroll = new JScrollPane( columns ); - - title.setFont( new Font( "Monospaced", Font.PLAIN, 32 ) ); - - bottom.add( back ); - bottom.add( Box.createHorizontalGlue() ); - bottom.add( addColumn ); - bottom.add( editAsCard ); - this.add( title, BorderLayout.NORTH ); - this.add( scroll, BorderLayout.CENTER ); - this.add( bottom, BorderLayout.SOUTH ); - - scroll.getHorizontalScrollBar().setUnitIncrement(COLUMN_WIDTH); - scroll.getVerticalScrollBar().setUnitIncrement(64); /* TODO: FIXME: Magic number. */ - - back.addActionListener(this); - addColumn.addActionListener(this); - editAsCard.addActionListener(this); - - registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); - registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - - back.setToolTipText("Go back to where the card was accessed from. Can also use [ESC]."); - addColumn.setToolTipText("Add new column to the board."); - editAsCard.setToolTipText("Edit the board as a regular card."); - - } - - public void boardEdit( Card card ) - { - identifier = card.identifierGet(); - - columns.removeAll(); - title.setText(card.titleGet()); - if( !card.isBoard() ) { - return; - } - - String columnsString = card.<String>tagGetAsOr(Card.TAG_BOARD_COLUMNS, ""); - Card[] columnCards = TagUtility.parseCardList(columnsString); - - for( int i = 0; i < columnCards.length; i++ ) { - - if( columnCards[i] == null ) { - System.out.print("Board '"+card.titleGet()+"': Failed to get card for column identifier index "+Integer.toString(i)+", aborting column loading. Full columns tag: '"+columnsString+"'\n"); - break; - } - - ColumnWidget column = new ColumnWidget(this, columnCards[i]); - insertColumnRaw(column); - } - } - - public Card boardSave() - { - Component[] columnsList = columns.getComponents(); - String columnIdentifiers = ""; - for( int i = 0; i < columnsList.length; i++ ) { - ColumnWidget column = (ColumnWidget)columnsList[i]; - column.save(); - - if( columnIdentifiers.length() > 0 ) { - columnIdentifiers += " "; - } - columnIdentifiers += Long.toString(column.identifier); - - } - - Card card; - - card = Main.database.cardGetByIdentifier(identifier); - - if( card == null ) { - throw new RuntimeException(); - } - - card.titleSet( title.getText() ); - if( columnIdentifiers.length() > 0 ) { - card.tagValueSetOnly( Card.TAG_BOARD, null ); - card.tagValueSetOnly( Card.TAG_BOARD_COLUMNS, columnIdentifiers ); - } else { - card.tagRemove( Card.TAG_BOARD ); - card.tagRemove( Card.TAG_BOARD_COLUMNS ); - } - - Main.database.cardUpdate( card, true ); - Main.refreshSearches(); - - return card; - - } - - public void boardReset() - { - title.setText(""); - columns.removeAll(); - } - - public void insertColumn() - { - ColumnWidget column = new ColumnWidget(this, null); - column.titleSet("New column"); - column.addMouseListener(this); - columns.add(column); - columns.revalidate(); - } - - public void insertColumnRaw( ColumnWidget column ) - { - column.addMouseListener(this); - columns.add(column); - columns.revalidate(); - } - - public int findColumn( ColumnWidget columnWidget ) - { - Component[] columnsList = columns.getComponents(); - for( int i = 0; i < columnsList.length; i++ ) { - if( columnsList[i] == columnWidget ) { - return i; - } - } - return -1; - } - - public void removeColumn( ColumnWidget columnWidget ) { - columnWidget.delete(); - columns.remove( columnWidget ); - columns.validate(); - columns.repaint(); - } - - public void moveCard( int from, int at, int to ) - { - ColumnWidget fromColumn = (ColumnWidget)columns.getComponent(from); - ColumnWidget toColumn = (ColumnWidget)columns.getComponent(to); - ColumnCardWidget cardWidget = fromColumn.popCard(at); - if( cardWidget == null ) { - return; - } - toColumn.insertCardRaw(cardWidget, min(at, toColumn.cardCount()) ); - cardWidget.select(); - } - - public void buttonClickedAsCard() - { - Card card = boardSave(); - Window window = (Window)this.getTopLevelAncestor(); - window.tabEdit.cardEdit(card); - window.tabSwitch( Tab.EDIT ); - } - - public void buttonClickedBack() - { - boardSave(); - boardReset(); - Window window = (Window)this.getTopLevelAncestor(); - window.tabSwitch( Tab.SEARCH ); - } - - public void actionPerformed( ActionEvent e ) - { - Object source = e.getSource(); - if( source == this ){ - switch( e.getActionCommand() ) { - - case KEY_ACTION_COMMIT: { - boardSave(); - return; - } - - case KEY_ACTION_BACK: { - buttonClickedBack(); - return; - } - - } - } else if( source == back ) { - buttonClickedBack(); - return; - } else if( source == addColumn ) { - insertColumn(); - return; - } else if( source == editAsCard ) { - buttonClickedAsCard(); - return; - } - - if( source instanceof ColumnWidget ) { - ColumnWidget sourceColumn = (ColumnWidget)source; - int columnIndex = findColumn(sourceColumn); - switch( e.getActionCommand() ){ - - case KEY_ACTION_CARD_LEFT: { - moveCard( columnIndex, sourceColumn.selectedCard(), max( columnIndex-1, 0) ); - } - case KEY_ACTION_CARD_RIGHT: { - moveCard( columnIndex, sourceColumn.selectedCard(), min( columnIndex+1, columns.getComponentCount()-1) ); - } - case KEY_ACTION_CARD_FULL_LEFT: { - moveCard( columnIndex, sourceColumn.selectedCard(), 0 ); - } - case KEY_ACTION_CARD_FULL_RIGHT: { - moveCard( columnIndex, sourceColumn.selectedCard(), columns.getComponentCount()-1 ); - } - - } - } - } - - public void mouseClicked( MouseEvent e ) - { - if( e.getButton() == MouseEvent.BUTTON2 ) { - if( !(e.getSource() instanceof ColumnWidget) ) - return; - - removeColumn( (ColumnWidget)e.getSource() ); - } - } - - public void mouseEntered( MouseEvent e ) {} - public void mouseExited( MouseEvent e ) {} - public void mousePressed( MouseEvent e ) {} - public void mouseReleased( MouseEvent e ) {} - }
--- a/src/junotu/TabCalendarBoard.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/TabCalendarBoard.java Thu Apr 06 01:44:10 2023 +0200 @@ -67,751 +67,752 @@ public class TabCalendarBoard extends JPanel implements TabInterface, ActionListener, MouseListener, ChangeListener { - final static int COLUMN_CONTENT_WIDTH = 256; - final static int COLUMN_WIDTH = COLUMN_CONTENT_WIDTH+16; - final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); - final static SimpleDateFormat TITLE_DATE_FORMAT = new SimpleDateFormat("dd MMMM, yyyy"); - final static SimpleDateFormat DAY_OF_THE_WEEK_FORMAT = new SimpleDateFormat("EEEE"); - final static SimpleDateFormat DEBUG_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + final static int COLUMN_CONTENT_WIDTH = 256; + final static int COLUMN_WIDTH = COLUMN_CONTENT_WIDTH+16; + final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + final static SimpleDateFormat TITLE_DATE_FORMAT = new SimpleDateFormat("dd MMMM, yyyy"); + final static SimpleDateFormat DAY_OF_THE_WEEK_FORMAT = new SimpleDateFormat("EEEE"); + final static SimpleDateFormat DEBUG_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public final String KEY_ACTION_BACK = "back"; + public final String KEY_ACTION_COMMIT = "commit"; + public final String KEY_ACTION_CARD_UP = "card_up"; + public final String KEY_ACTION_CARD_DOWN = "card_down"; + public final String KEY_ACTION_CARD_FULL_UP = "card_full_up"; + public final String KEY_ACTION_CARD_FULL_DOWN = "card_full_down"; + public final String KEY_ACTION_CARD_LEFT = "card_left"; + public final String KEY_ACTION_CARD_RIGHT = "card_right"; + public final String KEY_ACTION_CARD_FULL_LEFT = "card_full_left"; + public final String KEY_ACTION_CARD_FULL_RIGHT = "card_full_right"; + + private class ColumnWidget extends JPanel implements ActionListener, MouseListener { + + long identifier; + boolean newCard; + Date date; + TabCalendarBoard parent; + + TitledBorder titledBorder; + Box cards; + JButton addCard; + + public ColumnWidget( TabCalendarBoard parent_, Card card, Date date_ ) + { + newCard = card == null; + date = date_; + parent = parent_; - public final String KEY_ACTION_BACK = "back"; - public final String KEY_ACTION_COMMIT = "commit"; - public final String KEY_ACTION_CARD_UP = "card_up"; - public final String KEY_ACTION_CARD_DOWN = "card_down"; - public final String KEY_ACTION_CARD_FULL_UP = "card_full_up"; - public final String KEY_ACTION_CARD_FULL_DOWN = "card_full_down"; - public final String KEY_ACTION_CARD_LEFT = "card_left"; - public final String KEY_ACTION_CARD_RIGHT = "card_right"; - public final String KEY_ACTION_CARD_FULL_LEFT = "card_full_left"; - public final String KEY_ACTION_CARD_FULL_RIGHT = "card_full_right"; - - private class ColumnWidget extends JPanel implements ActionListener, MouseListener { + this.setLayout( new GridBagLayout() ); + + cards = Box.createVerticalBox(); + addCard = new JButton("+"); + + addCard.setFont( new Font( "Monospaced", Font.BOLD, 32 ) ); + + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = 1.0; + constraints.weighty = 0.0; + constraints.gridx = 0; + constraints.gridy = 0; - long identifier; - boolean newCard; - Date date; - TabCalendarBoard parent; - - TitledBorder titledBorder; - Box cards; - JButton addCard; + this.add( cards, constraints ); + constraints.gridy++; + this.add( addCard, constraints ); + constraints.gridy++; + constraints.weighty = 1.0; + this.add( Box.createVerticalGlue(), constraints ); + + addCard.setPreferredSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); + addCard.setMaximumSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); + addCard.setAlignmentX( JButton.CENTER_ALIGNMENT ); + + //this.setPreferredSize( new Dimension( COLUMN_WIDTH, 384 ) ); + this.setMaximumSize( new Dimension( COLUMN_WIDTH, 1000000 ) ); + + titledBorder = BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "", + TitledBorder.LEADING, + TitledBorder.TOP, + new Font( "Monospaced", Font.BOLD, 16 ) + ); - public ColumnWidget( TabCalendarBoard parent_, Card card, Date date_ ) - { - newCard = card == null; - date = date_; - parent = parent_; - - this.setLayout( new GridBagLayout() ); - - cards = Box.createVerticalBox(); - addCard = new JButton("+"); - - addCard.setFont( new Font( "Monospaced", Font.BOLD, 32 ) ); - - GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.NORTHWEST; - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.weighty = 0.0; - constraints.gridx = 0; - constraints.gridy = 0; + this.setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder( 0, 8, 0, 8 ), + titledBorder + ) + ); - this.add( cards, constraints ); - constraints.gridy++; - this.add( addCard, constraints ); - constraints.gridy++; - constraints.weighty = 1.0; - this.add( Box.createVerticalGlue(), constraints ); - - addCard.setPreferredSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); - addCard.setMaximumSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); - addCard.setAlignmentX( JButton.CENTER_ALIGNMENT ); + addMouseListener(this); + registerKeyboardAction( + this, + KEY_ACTION_CARD_UP, + KeyStroke.getKeyStroke( KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_DOWN, + KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_FULL_UP, + KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + this, + KEY_ACTION_CARD_FULL_DOWN, + KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_LEFT, + KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_RIGHT, + KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_FULL_LEFT, + KeyStroke.getKeyStroke( KeyEvent.VK_HOME, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + registerKeyboardAction( + parent, + KEY_ACTION_CARD_FULL_RIGHT, + KeyStroke.getKeyStroke( KeyEvent.VK_END, InputEvent.ALT_DOWN_MASK ), + WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); - //this.setPreferredSize( new Dimension( COLUMN_WIDTH, 384 ) ); - this.setMaximumSize( new Dimension( COLUMN_WIDTH, 1000000 ) ); + addCard.addActionListener(this); + + addCard.setToolTipText("Add card."); + this.setToolTipText( DAY_OF_THE_WEEK_FORMAT.format(date) ); - titledBorder = BorderFactory.createTitledBorder( - BorderFactory.createEtchedBorder(), - "", - TitledBorder.LEADING, - TitledBorder.TOP, - new Font( "Monospaced", Font.BOLD, 16 ) - ); + if( newCard ) { + return; + } + + identifier = card.identifierGet(); + titleSet(card.titleGet()); + + String cardsString = card.<String>tagGetAsOr( Card.TAG_CALENDAR_BOARD_COLUMN_CARDS, "" ); + Card[] cardsSplit = TagUtility.parseCardList(cardsString); + + for( int i = 0; i < cardsSplit.length; i++ ) { - this.setBorder( - BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder( 0, 8, 0, 8 ), - titledBorder - ) - ); + if( cardsSplit[i] == null ) { + System.out.print("Column '"+card.titleGet()+"', identifier "+Long.toString(card.identifierGet())+": Failed to retrieve card identifier by index "+Integer.toString(i)+". Full cards tag: '"+cardsString+"'\n"); + insertCard( null, -1 ); + continue; + } + + insertCard( cardsSplit[i], -1 ); + + } + + } + + public void titleSet( String title ) + { + titledBorder.setTitle(title); + repaint(); + } + + public String titleGet() + { + return titledBorder.getTitle(); + } + + public void insertCard( Card card, int at ) + { + ColumnCardWidget cardWidget = new ColumnCardWidget( card ); + insertCardRaw( cardWidget, at ); + } + + public void insertCardRaw( ColumnCardWidget cardWidget, int at ) + { + if( at == -1 ) { + at = cards.getComponentCount(); + } + cardWidget.addMouseListener(this); + /* TODO: Check if works properly. */ + cards.add( cardWidget, at ); + cards.revalidate(); + } + + public void moveCard( int at, int to ) + { + if( at < 0 ) { + return; + } + ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); + boolean focused = cardWidget.isSelected(); + cards.remove(at); + cards.add( cardWidget, to ); + cards.revalidate(); + if( focused ) { + cardWidget.select(); + } + } + + public ColumnCardWidget popCard( int at ) + { + if( at < 0 ) { + return null; + } + ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); + cards.remove(at); + cardWidget.removeMouseListener(this); + checkCardCount(); + return cardWidget; + } - addMouseListener(this); - registerKeyboardAction( - this, - KEY_ACTION_CARD_UP, - KeyStroke.getKeyStroke( KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_DOWN, - KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_FULL_UP, - KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - this, - KEY_ACTION_CARD_FULL_DOWN, - KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_LEFT, - KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_RIGHT, - KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_FULL_LEFT, - KeyStroke.getKeyStroke( KeyEvent.VK_HOME, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); - registerKeyboardAction( - parent, - KEY_ACTION_CARD_FULL_RIGHT, - KeyStroke.getKeyStroke( KeyEvent.VK_END, InputEvent.ALT_DOWN_MASK ), - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT - ); + public int selectedCard() + { + Component[] cardList = cards.getComponents(); + for( int i = 0; i < cardList.length; i++ ) { + if( ((ColumnCardWidget)cardList[i]).isSelected() ) { + return i; + } + } + System.out.print("Selected card not found."); + return -1; + } + + public int cardCount() + { + return cards.getComponentCount(); + } + + public void save() + { + Component[] cardList = cards.getComponents(); + String cardIdentifiers = ""; + for( int i = 0; i < cardList.length; i++ ) { + ColumnCardWidget cardWidget = (ColumnCardWidget)cardList[i]; + cardWidget.save(); + + if( cardIdentifiers.length() > 0 ) { + cardIdentifiers += " "; + } + cardIdentifiers += Long.toString(cardWidget.identifier); + } + + if( cardList.length == 0 ) { + if( !newCard ) { + Main.database.cardDeleteByIdentifier(identifier); + identifier = -1; + newCard = true; + } + return; + } + + Card card; - addCard.addActionListener(this); - - addCard.setToolTipText("Add card."); - this.setToolTipText( DAY_OF_THE_WEEK_FORMAT.format(date) ); - - if( newCard ) { - return; - } + if( newCard ) { + card = new Card(); + } else { + try { + card = Main.database.cardGetByIdentifier(identifier); + } catch( Exception e ) { + throw new RuntimeException(e); + } + + if( card == null ) { + throw new RuntimeException("Board column update: card not found."); + } + } + + card.titleSet( titleGet() ); + card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN, null ); + card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN_DATE, DATE_FORMAT.format(date) ); + card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN_CARDS, cardIdentifiers ); - identifier = card.identifierGet(); - titleSet(card.titleGet()); - - String cardsString = card.<String>tagGetAsOr( Card.TAG_CALENDAR_BOARD_COLUMN_CARDS, "" ); - Card[] cardsSplit = TagUtility.parseCardList(cardsString); - - for( int i = 0; i < cardsSplit.length; i++ ) { - - if( cardsSplit[i] == null ) { - System.out.print("Column '"+card.titleGet()+"', identifier "+Long.toString(card.identifierGet())+": Failed to retrieve card identifier by index "+Integer.toString(i)+". Full cards tag: '"+cardsString+"'\n"); - insertCard( null, -1 ); - continue; + try { + if( newCard ) { + identifier = Main.database.cardAdd( card ); + newCard = false; + } else { + Main.database.cardUpdate( card, false ); + } + } catch( Exception e ) { + throw new RuntimeException(e); + } + + } + + public void delete() + { + save(); + parent = null; + if( !newCard ) { + Main.database.cardDeleteByIdentifier(identifier); + } + } + + public void checkCardCount() + { + if( cardCount() == 0 ) { + columnIsEmpty(this); + } } - insertCard( cardsSplit[i], -1 ); - - } - - } + public void actionPerformed( ActionEvent e ) + { + Object source = e.getSource(); + if( source == this ) { + int selected = selectedCard(); + int length = cards.getComponentCount(); + + switch( e.getActionCommand() ) { - public void titleSet( String title ) - { - titledBorder.setTitle(title); - repaint(); - } + case KEY_ACTION_CARD_UP: { + System.out.print("Move card up.\n"); + moveCard( selected, max(selected-1, 0) ); + break; + } + + case KEY_ACTION_CARD_DOWN: { + System.out.print("Move card down.\n"); + moveCard( selected, min(selected+1, cards.getComponentCount()-1) ); + break; + } + + case KEY_ACTION_CARD_FULL_UP: { + System.out.print("Move card full up.\n"); + moveCard( selected, 0 ); + break; + } - public String titleGet() - { - return titledBorder.getTitle(); - } - - public void insertCard( Card card, int at ) - { - ColumnCardWidget cardWidget = new ColumnCardWidget( card ); - insertCardRaw( cardWidget, at ); - } + case KEY_ACTION_CARD_FULL_DOWN: { + System.out.print("Move card full down.\n"); + moveCard( selected, cards.getComponentCount()-1 ); + break; + } + + } + } else if( source == addCard ) { + insertCard( null, -1 ); + } + } - public void insertCardRaw( ColumnCardWidget cardWidget, int at ) - { - if( at == -1 ) { - at = cards.getComponentCount(); - } - cardWidget.addMouseListener(this); - /* TODO: Check if works properly. */ - cards.add( cardWidget, at ); - cards.revalidate(); + public void mouseClicked( MouseEvent e ) + { + Object source = e.getSource(); + if( source instanceof ColumnCardWidget ) { + if( e.getButton() == MouseEvent.BUTTON2 ) { + ColumnCardWidget cardWidget = (ColumnCardWidget)e.getSource(); + cardWidget.delete(); + cards.remove(cardWidget); + cards.revalidate(); + checkCardCount(); + } + } + } + + public void mouseEntered( MouseEvent e ) {} + public void mouseExited( MouseEvent e ) {} + public void mousePressed( MouseEvent e ) {} + public void mouseReleased( MouseEvent e ) {} + } - public void moveCard( int at, int to ) + long identifier = -1; + Box columns; + JScrollPane scroll; + + boolean optionOnlyFilledColumns; + + JButton back; + JButton options; + JSpinner dateRangeBegin; + JSpinner dateRangeEnd; + JPopupMenu menu; + + JCheckBoxMenuItem menu_onlyFilled; + + public TabCalendarBoard() { - if( at < 0 ) { - return; - } - ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); - boolean focused = cardWidget.isSelected(); - cards.remove(at); - cards.add( cardWidget, to ); - cards.revalidate(); - if( focused ) { - cardWidget.select(); - } + this.setLayout( new BorderLayout() ); + + back = new JButton("Back"); + options = new JButton("="); + dateRangeBegin = new JSpinner( new SpinnerDateModel() ); + dateRangeEnd = new JSpinner( new SpinnerDateModel() ); + JSpinner.DateEditor dateRangeBeginEditor = (JSpinner.DateEditor)dateRangeBegin.getEditor(); + JSpinner.DateEditor dateRangeEndEditor = (JSpinner.DateEditor)dateRangeEnd.getEditor(); + Calendar calendar = Calendar.getInstance(); + + menu = new JPopupMenu("Options"); + menu_onlyFilled = new JCheckBoxMenuItem("Show only filled days"); + menu.add(menu_onlyFilled); + + Box bottom = Box.createHorizontalBox(); + columns = Box.createHorizontalBox(); + scroll = new JScrollPane( columns ); + + bottom.add( back ); + bottom.add( Box.createHorizontalGlue() ); + bottom.add( dateRangeBegin ); + bottom.add( dateRangeEnd ); + bottom.add( options ); + this.add( scroll, BorderLayout.CENTER ); + this.add( bottom, BorderLayout.SOUTH ); + + calendar.set( Calendar.HOUR_OF_DAY, 0 ); + calendar.set( Calendar.MINUTE, 0 ); + calendar.set( Calendar.SECOND, 0 ); + calendar.set( Calendar.MILLISECOND, 0 ); + + dateRangeBeginEditor.getFormat().applyPattern("yyyy-MM-dd EEEE"); + dateRangeEndEditor.getFormat().applyPattern("yyyy-MM-dd EEEE"); + + dateRangeBeginEditor.getModel().setValue(calendar.getTime()); + calendar.add( Calendar.DAY_OF_MONTH, 6 ); + dateRangeEndEditor.getModel().setValue(calendar.getTime()); + + dateRangeBeginEditor.getModel().setCalendarField( Calendar.DAY_OF_MONTH ); + dateRangeEndEditor.getModel().setCalendarField( Calendar.DAY_OF_MONTH ); + + scroll.getHorizontalScrollBar().setUnitIncrement(COLUMN_WIDTH); + scroll.getVerticalScrollBar().setUnitIncrement(64); /* TODO: FIXME: Magic number. */ + + dateRangeBegin.addChangeListener(this); + dateRangeEnd.addChangeListener(this); + + back.addActionListener(this); + options.addActionListener(this); + menu_onlyFilled.addActionListener(this); + + registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); + registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); + + back.setToolTipText("Go back to where the calendar board was accessed from. Can also use [ESC]."); + options.setToolTipText("Show calendar options."); + menu_onlyFilled.setToolTipText("If checked, days with no cards will be hidden."); + } - public ColumnCardWidget popCard( int at ) + public void boardEdit() { - if( at < 0 ) { - return null; - } - ColumnCardWidget cardWidget = (ColumnCardWidget)cards.getComponent(at); - cards.remove(at); - cardWidget.removeMouseListener(this); - checkCardCount(); - return cardWidget; - } + if( identifier != -1 ) { + populateColumns(); + return; + } + + Card card; + + Query query = new WildcardQuery( new Term(Card.TAG_CALENDAR_BOARD, "*") ); + Card cards[] = Main.database.searchCustom( query, 1, false ); - public int selectedCard() - { - Component[] cardList = cards.getComponents(); - for( int i = 0; i < cardList.length; i++ ) { - if( ((ColumnCardWidget)cardList[i]).isSelected() ) { - return i; + if( cards.length == 0 ) { + card = new Card(); + identifier = Main.database.cardAdd(card); + boardSave(); + } else if( cards.length == 1 ) { + card = cards[0]; + identifier = card.identifierGet(); + } else { + throw new RuntimeException(); } - } - System.out.print("Selected card not found."); - return -1; + + optionOnlyFilledColumns = card.tagHas( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED ); + menu_onlyFilled.setSelected(optionOnlyFilledColumns); + + populateColumns(); + scroll.getHorizontalScrollBar().setValue(0); + } - public int cardCount() + public Card boardSave() { - return cards.getComponentCount(); + Card card; + + card = Main.database.cardGetByIdentifier(identifier); + + if( card == null ) { + throw new RuntimeException(""+identifier); + } + + card.titleSet( "JUnotu calendar board" ); + card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD, null ); + + // TODO: Maybe card should have convenience functions for reading and writing options? + if( optionOnlyFilledColumns ) { + card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED, null ); + } else { + card.tagRemove( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED ); + } + + Component[] columnsList = columns.getComponents(); + for( int i = 0; i < columnsList.length; i++ ) { + ColumnWidget column = (ColumnWidget)columnsList[i]; + column.save(); + } + + Main.database.cardUpdate( card, true ); + Main.refreshSearches(); + + return card; + } + + public void boardReset() + { + columns.removeAll(); } - public void save() + public void populateColumns() { - Component[] cardList = cards.getComponents(); - String cardIdentifiers = ""; - for( int i = 0; i < cardList.length; i++ ) { - ColumnCardWidget cardWidget = (ColumnCardWidget)cardList[i]; - cardWidget.save(); - - if( cardIdentifiers.length() > 0 ) { - cardIdentifiers += " "; + JSpinner.DateEditor dateRangeBeginEditor = (JSpinner.DateEditor)dateRangeBegin.getEditor(); + JSpinner.DateEditor dateRangeEndEditor = (JSpinner.DateEditor)dateRangeEnd.getEditor(); + + Date begin = dateRangeBeginEditor.getModel().getDate(); + Date end = dateRangeEndEditor.getModel().getDate(); + + Component[] columnList = columns.getComponents(); + + if( begin.after(end) ) { + ColumnWidget columnWidget; + for( int i = 0; i < columnList.length; i++ ) { + columnWidget = (ColumnWidget)columnList[i]; + columnWidget.save(); + } + columns.removeAll(); + columns.validate(); + columns.repaint(); + return; + } + + for( int i = 0; i < columnList.length; i++ ) { + ColumnWidget columnWidget = (ColumnWidget)columnList[i]; + if( columnWidget.date.before(begin) || columnWidget.date.after(end) ) { + columnWidget.save(); + columns.remove( columnWidget ); + } } - cardIdentifiers += Long.toString(cardWidget.identifier); - } - - if( cardList.length == 0 ) { - if( !newCard ) { - Main.database.cardDeleteByIdentifier(identifier); - identifier = -1; - newCard = true; - } - return; - } + + Term term = new Term(Card.TAG_CALENDAR_BOARD_COLUMN_DATE); - Card card; + Calendar cur = Calendar.getInstance(); + cur.setTime(begin); + Date curTime = begin; + int insertPosition = 0; + for( + ; + (curTime = cur.getTime()).before(end) || curTime.equals(end); + cur.add( Calendar.DAY_OF_MONTH, 1 ) + ) { + int column = findColumn(curTime); + if( column != -1 ) { + ColumnWidget columnWidget = getColumnByIndex(column); + if( !optionOnlyFilledColumns || columnWidget.cardCount() != 0 ) { + insertPosition = column+1; + } else { + columnWidget.save(); + columns.remove( columnWidget ); + } + continue; + } - if( newCard ) { - card = new Card(); - } else { - try { - card = Main.database.cardGetByIdentifier(identifier); - } catch( Exception e ) { - throw new RuntimeException(e); + Card card = null; + + term = term.createTerm( DATE_FORMAT.format(curTime) ); + Card cards[] = Main.database.searchCustom( new TermQuery(term), 1, false ); + + if( cards.length != 0 ) { + card = cards[0]; + } + + if( optionOnlyFilledColumns && card == null ) { + continue; + } + + insertColumn( curTime, card, insertPosition ); + insertPosition++; } - if( card == null ) { - throw new RuntimeException("Board column update: card not found."); - } - } + columns.validate(); + columns.repaint(); + } - card.titleSet( titleGet() ); - card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN, null ); - card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN_DATE, DATE_FORMAT.format(date) ); - card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_COLUMN_CARDS, cardIdentifiers ); + public void insertColumn( Date date, Card card, int insertPosition ) + { + ColumnWidget column = new ColumnWidget(this, card, date); + column.titleSet( TITLE_DATE_FORMAT.format(date) ); + insertColumnRaw(column, insertPosition); + } + + public void insertColumnRaw( ColumnWidget column, int insertPosition ) + { + column.addMouseListener(this); + columns.add(column, insertPosition); + columns.revalidate(); + } - try { - if( newCard ) { - identifier = Main.database.cardAdd( card ); - newCard = false; - } else { - Main.database.cardUpdate( card, false ); + public int findColumn( ColumnWidget columnWidget ) + { + Component[] columnsList = columns.getComponents(); + for( int i = 0; i < columnsList.length; i++ ) { + if( columnsList[i] == columnWidget ) { + return i; + } } - } catch( Exception e ) { - throw new RuntimeException(e); - } - + return -1; + } + + public int findColumn( Date date ) + { + Component[] columnsList = columns.getComponents(); + for( int i = 0; i < columnsList.length; i++ ) { + if( ((ColumnWidget)columnsList[i]).date.equals(date) ) { + return i; + } + } + return -1; } - public void delete() + public ColumnWidget getColumnByIndex( int index ) + { + Component[] columnsList = columns.getComponents(); + return (ColumnWidget)columnsList[index]; + } + + public void removeColumn( ColumnWidget columnWidget ) { - save(); - parent = null; - if( !newCard ) { - Main.database.cardDeleteByIdentifier(identifier); - } + columnWidget.delete(); + columns.remove( columnWidget ); + columns.validate(); + columns.repaint(); + } + + public void columnIsEmpty( ColumnWidget columnWidget ) { + if( optionOnlyFilledColumns ) { + removeColumn(columnWidget); + } } - public void checkCardCount() + public void moveCard( int from, int at, int to ) + { + ColumnWidget fromColumn = (ColumnWidget)columns.getComponent(from); + ColumnWidget toColumn = (ColumnWidget)columns.getComponent(to); + ColumnCardWidget cardWidget = fromColumn.popCard(at); + if( cardWidget == null ) { + return; + } + toColumn.insertCardRaw(cardWidget, min(at, toColumn.cardCount()) ); + cardWidget.select(); + } + + public void buttonClickedAsCard() { - if( cardCount() == 0 ) { - columnIsEmpty(this); - } + Card card = boardSave(); + Window window = (Window)this.getTopLevelAncestor(); + window.tabEdit.cardEdit(card); + window.tabSwitch( Tab.EDIT ); + } + + public void buttonClickedBack() + { + boardSave(); + boardReset(); + Window window = (Window)this.getTopLevelAncestor(); + window.tabSwitch( Tab.SEARCH ); + } + + public void onSwitchedTo() + { + boardEdit(); } public void actionPerformed( ActionEvent e ) { - Object source = e.getSource(); - if( source == this ) { - int selected = selectedCard(); - int length = cards.getComponentCount(); - - switch( e.getActionCommand() ) { + Object source = e.getSource(); + if( source == this ){ + switch( e.getActionCommand() ) { + + case KEY_ACTION_COMMIT: { + boardSave(); + return; + } - case KEY_ACTION_CARD_UP: { - System.out.print("Move card up.\n"); - moveCard( selected, max(selected-1, 0) ); - break; - } - - case KEY_ACTION_CARD_DOWN: { - System.out.print("Move card down.\n"); - moveCard( selected, min(selected+1, cards.getComponentCount()-1) ); - break; + case KEY_ACTION_BACK: { + buttonClickedBack(); + return; + } + + } + } else if( source == back ) { + buttonClickedBack(); + return; + } else if( source == options ) { + menu.show( (Component)source, 0, 0 ); + return; + } else if( source == menu_onlyFilled ) { + optionOnlyFilledColumns = menu_onlyFilled.isSelected(); + populateColumns(); + return; } - - case KEY_ACTION_CARD_FULL_UP: { - System.out.print("Move card full up.\n"); - moveCard( selected, 0 ); - break; + + if( source instanceof ColumnWidget ) { + ColumnWidget sourceColumn = (ColumnWidget)e.getSource(); + int columnIndex = findColumn(sourceColumn); + switch( e.getActionCommand() ){ + + case KEY_ACTION_CARD_LEFT: { + moveCard( columnIndex, sourceColumn.selectedCard(), max( columnIndex-1, 0) ); + break; + } + case KEY_ACTION_CARD_RIGHT: { + moveCard( columnIndex, sourceColumn.selectedCard(), min( columnIndex+1, columns.getComponentCount()-1) ); + break; + } + case KEY_ACTION_CARD_FULL_LEFT: { + moveCard( columnIndex, sourceColumn.selectedCard(), 0 ); + break; + } + case KEY_ACTION_CARD_FULL_RIGHT: { + moveCard( columnIndex, sourceColumn.selectedCard(), columns.getComponentCount()-1 ); + break; + } + + } } - - case KEY_ACTION_CARD_FULL_DOWN: { - System.out.print("Move card full down.\n"); - moveCard( selected, cards.getComponentCount()-1 ); - break; - } - - } - } else if( source == addCard ) { - insertCard( null, -1 ); - } } public void mouseClicked( MouseEvent e ) { - Object source = e.getSource(); - if( source instanceof ColumnCardWidget ) { if( e.getButton() == MouseEvent.BUTTON2 ) { - ColumnCardWidget cardWidget = (ColumnCardWidget)e.getSource(); - cardWidget.delete(); - cards.remove(cardWidget); - cards.revalidate(); - checkCardCount(); + if( !(e.getSource() instanceof ColumnWidget) ) + return; + + removeColumn( (ColumnWidget)e.getSource() ); } - } } - + public void mouseEntered( MouseEvent e ) {} public void mouseExited( MouseEvent e ) {} public void mousePressed( MouseEvent e ) {} public void mouseReleased( MouseEvent e ) {} - - } - long identifier = -1; - Box columns; - JScrollPane scroll; - - boolean optionOnlyFilledColumns; - - JButton back; - JButton options; - JSpinner dateRangeBegin; - JSpinner dateRangeEnd; - JPopupMenu menu; - - JCheckBoxMenuItem menu_onlyFilled; - - public TabCalendarBoard() - { - this.setLayout( new BorderLayout() ); - - back = new JButton("Back"); - options = new JButton("="); - dateRangeBegin = new JSpinner( new SpinnerDateModel() ); - dateRangeEnd = new JSpinner( new SpinnerDateModel() ); - JSpinner.DateEditor dateRangeBeginEditor = (JSpinner.DateEditor)dateRangeBegin.getEditor(); - JSpinner.DateEditor dateRangeEndEditor = (JSpinner.DateEditor)dateRangeEnd.getEditor(); - Calendar calendar = Calendar.getInstance(); - - menu = new JPopupMenu("Options"); - menu_onlyFilled = new JCheckBoxMenuItem("Show only filled days"); - menu.add(menu_onlyFilled); - - Box bottom = Box.createHorizontalBox(); - columns = Box.createHorizontalBox(); - scroll = new JScrollPane( columns ); - - bottom.add( back ); - bottom.add( Box.createHorizontalGlue() ); - bottom.add( dateRangeBegin ); - bottom.add( dateRangeEnd ); - bottom.add( options ); - this.add( scroll, BorderLayout.CENTER ); - this.add( bottom, BorderLayout.SOUTH ); - - calendar.set( Calendar.HOUR_OF_DAY, 0 ); - calendar.set( Calendar.MINUTE, 0 ); - calendar.set( Calendar.SECOND, 0 ); - calendar.set( Calendar.MILLISECOND, 0 ); - - dateRangeBeginEditor.getFormat().applyPattern("yyyy-MM-dd EEEE"); - dateRangeEndEditor.getFormat().applyPattern("yyyy-MM-dd EEEE"); - - dateRangeBeginEditor.getModel().setValue(calendar.getTime()); - calendar.add( Calendar.DAY_OF_MONTH, 6 ); - dateRangeEndEditor.getModel().setValue(calendar.getTime()); - - dateRangeBeginEditor.getModel().setCalendarField( Calendar.DAY_OF_MONTH ); - dateRangeEndEditor.getModel().setCalendarField( Calendar.DAY_OF_MONTH ); - - scroll.getHorizontalScrollBar().setUnitIncrement(COLUMN_WIDTH); - scroll.getVerticalScrollBar().setUnitIncrement(64); /* TODO: FIXME: Magic number. */ - - dateRangeBegin.addChangeListener(this); - dateRangeEnd.addChangeListener(this); - - back.addActionListener(this); - options.addActionListener(this); - menu_onlyFilled.addActionListener(this); - - registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); - registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - - back.setToolTipText("Go back to where the calendar board was accessed from. Can also use [ESC]."); - options.setToolTipText("Show calendar options."); - menu_onlyFilled.setToolTipText("If checked, days with no cards will be hidden."); - - } - - public void boardEdit() - { - if( identifier != -1 ) { - populateColumns(); - return; - } - - Card card; - - Query query = new WildcardQuery( new Term(Card.TAG_CALENDAR_BOARD, "*") ); - Card cards[] = Main.database.searchCustom( query, 1, false ); - - if( cards.length == 0 ) { - card = new Card(); - identifier = Main.database.cardAdd(card); - boardSave(); - } else if( cards.length == 1 ) { - card = cards[0]; - identifier = card.identifierGet(); - } else { - throw new RuntimeException(); - } - - optionOnlyFilledColumns = card.tagHas( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED ); - menu_onlyFilled.setSelected(optionOnlyFilledColumns); - - populateColumns(); - scroll.getHorizontalScrollBar().setValue(0); - - } - - public Card boardSave() - { - Card card; - - card = Main.database.cardGetByIdentifier(identifier); - - if( card == null ) { - throw new RuntimeException(""+identifier); - } - - card.titleSet( "JUnotu calendar board" ); - card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD, null ); - - // TODO: Maybe card should have convenience functions for reading and writing options? - if( optionOnlyFilledColumns ) { - card.tagValueSetOnly( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED, null ); - } else { - card.tagRemove( Card.TAG_CALENDAR_BOARD_OPTION_ONLY_FILLED ); - } - - Component[] columnsList = columns.getComponents(); - for( int i = 0; i < columnsList.length; i++ ) { - ColumnWidget column = (ColumnWidget)columnsList[i]; - column.save(); - } - - Main.database.cardUpdate( card, true ); - Main.refreshSearches(); - - return card; - } - - public void boardReset() - { - columns.removeAll(); - } - - public void populateColumns() - { - JSpinner.DateEditor dateRangeBeginEditor = (JSpinner.DateEditor)dateRangeBegin.getEditor(); - JSpinner.DateEditor dateRangeEndEditor = (JSpinner.DateEditor)dateRangeEnd.getEditor(); - - Date begin = dateRangeBeginEditor.getModel().getDate(); - Date end = dateRangeEndEditor.getModel().getDate(); - - Component[] columnList = columns.getComponents(); - - if( begin.after(end) ) { - ColumnWidget columnWidget; - for( int i = 0; i < columnList.length; i++ ) { - columnWidget = (ColumnWidget)columnList[i]; - columnWidget.save(); - } - columns.removeAll(); - columns.validate(); - columns.repaint(); - return; - } - - for( int i = 0; i < columnList.length; i++ ) { - ColumnWidget columnWidget = (ColumnWidget)columnList[i]; - if( columnWidget.date.before(begin) || columnWidget.date.after(end) ) { - columnWidget.save(); - columns.remove( columnWidget ); - } + public void stateChanged( ChangeEvent e ) + { + Object source = e.getSource(); + if( source == dateRangeBegin || source == dateRangeEnd ) { + populateColumns(); + } } - Term term = new Term(Card.TAG_CALENDAR_BOARD_COLUMN_DATE); - - Calendar cur = Calendar.getInstance(); - cur.setTime(begin); - Date curTime = begin; - int insertPosition = 0; - for( - ; - (curTime = cur.getTime()).before(end) || curTime.equals(end); - cur.add( Calendar.DAY_OF_MONTH, 1 ) - ) { - int column = findColumn(curTime); - if( column != -1 ) { - ColumnWidget columnWidget = getColumnByIndex(column); - if( !optionOnlyFilledColumns || columnWidget.cardCount() != 0 ) { - insertPosition = column+1; - } else { - columnWidget.save(); - columns.remove( columnWidget ); - } - continue; - } - - Card card = null; - - term = term.createTerm( DATE_FORMAT.format(curTime) ); - Card cards[] = Main.database.searchCustom( new TermQuery(term), 1, false ); - - if( cards.length != 0 ) { - card = cards[0]; - } - - if( optionOnlyFilledColumns && card == null ) { - continue; - } - - insertColumn( curTime, card, insertPosition ); - insertPosition++; - } - - columns.validate(); - columns.repaint(); - } - - public void insertColumn( Date date, Card card, int insertPosition ) - { - ColumnWidget column = new ColumnWidget(this, card, date); - column.titleSet( TITLE_DATE_FORMAT.format(date) ); - insertColumnRaw(column, insertPosition); - } - - public void insertColumnRaw( ColumnWidget column, int insertPosition ) - { - column.addMouseListener(this); - columns.add(column, insertPosition); - columns.revalidate(); - } - - public int findColumn( ColumnWidget columnWidget ) - { - Component[] columnsList = columns.getComponents(); - for( int i = 0; i < columnsList.length; i++ ) { - if( columnsList[i] == columnWidget ) { - return i; - } - } - return -1; - } - - public int findColumn( Date date ) - { - Component[] columnsList = columns.getComponents(); - for( int i = 0; i < columnsList.length; i++ ) { - if( ((ColumnWidget)columnsList[i]).date.equals(date) ) { - return i; - } - } - return -1; - } - - public ColumnWidget getColumnByIndex( int index ) - { - Component[] columnsList = columns.getComponents(); - return (ColumnWidget)columnsList[index]; - } - - public void removeColumn( ColumnWidget columnWidget ) { - columnWidget.delete(); - columns.remove( columnWidget ); - columns.validate(); - columns.repaint(); - } - - public void columnIsEmpty( ColumnWidget columnWidget ) { - if( optionOnlyFilledColumns ) { - removeColumn(columnWidget); - } - } - - public void moveCard( int from, int at, int to ) - { - ColumnWidget fromColumn = (ColumnWidget)columns.getComponent(from); - ColumnWidget toColumn = (ColumnWidget)columns.getComponent(to); - ColumnCardWidget cardWidget = fromColumn.popCard(at); - if( cardWidget == null ) { - return; - } - toColumn.insertCardRaw(cardWidget, min(at, toColumn.cardCount()) ); - cardWidget.select(); - } - - public void buttonClickedAsCard() - { - Card card = boardSave(); - Window window = (Window)this.getTopLevelAncestor(); - window.tabEdit.cardEdit(card); - window.tabSwitch( Tab.EDIT ); - } - - public void buttonClickedBack() - { - boardSave(); - boardReset(); - Window window = (Window)this.getTopLevelAncestor(); - window.tabSwitch( Tab.SEARCH ); - } - - public void onSwitchedTo() - { - boardEdit(); - } - - public void actionPerformed( ActionEvent e ) - { - Object source = e.getSource(); - if( source == this ){ - switch( e.getActionCommand() ) { - - case KEY_ACTION_COMMIT: { - boardSave(); - return; - } - - case KEY_ACTION_BACK: { - buttonClickedBack(); - return; - } - - } - } else if( source == back ) { - buttonClickedBack(); - return; - } else if( source == options ) { - menu.show( (Component)source, 0, 0 ); - return; - } else if( source == menu_onlyFilled ) { - optionOnlyFilledColumns = menu_onlyFilled.isSelected(); - populateColumns(); - return; - } - - if( source instanceof ColumnWidget ) { - ColumnWidget sourceColumn = (ColumnWidget)e.getSource(); - int columnIndex = findColumn(sourceColumn); - switch( e.getActionCommand() ){ - - case KEY_ACTION_CARD_LEFT: { - moveCard( columnIndex, sourceColumn.selectedCard(), max( columnIndex-1, 0) ); - break; - } - case KEY_ACTION_CARD_RIGHT: { - moveCard( columnIndex, sourceColumn.selectedCard(), min( columnIndex+1, columns.getComponentCount()-1) ); - break; - } - case KEY_ACTION_CARD_FULL_LEFT: { - moveCard( columnIndex, sourceColumn.selectedCard(), 0 ); - break; - } - case KEY_ACTION_CARD_FULL_RIGHT: { - moveCard( columnIndex, sourceColumn.selectedCard(), columns.getComponentCount()-1 ); - break; - } - - } - } - } - - public void mouseClicked( MouseEvent e ) - { - if( e.getButton() == MouseEvent.BUTTON2 ) { - if( !(e.getSource() instanceof ColumnWidget) ) - return; - - removeColumn( (ColumnWidget)e.getSource() ); - } - } - - public void mouseEntered( MouseEvent e ) {} - public void mouseExited( MouseEvent e ) {} - public void mousePressed( MouseEvent e ) {} - public void mouseReleased( MouseEvent e ) {} - - public void stateChanged( ChangeEvent e ) - { - Object source = e.getSource(); - if( source == dateRangeBegin || source == dateRangeEnd ) { - populateColumns(); - } - } - }
--- a/src/junotu/TabEdit.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/TabEdit.java Thu Apr 06 01:44:10 2023 +0200 @@ -39,570 +39,571 @@ public class TabEdit extends JPanel implements ActionListener, MouseListener { - private class TagWidget extends JButton { - - public String tag; - public Object value; - - public TagWidget( String tag, Object value ) { - super(); - this.tag = tag; - this.value = value; - this.setToolTipText("Click to edit this tag. Use ':' to delimit name and value."); + private class TagWidget extends JButton { + + public String tag; + public Object value; + + public TagWidget( String tag, Object value ) { + super(); + this.tag = tag; + this.value = value; + this.setToolTipText("Click to edit this tag. Use ':' to delimit name and value."); - update(); + update(); + } + + public void update() + { + if( value != null ) { + setText( tag+": "+value.toString() ); + } else { + setText( tag ); + } + } + } - public void update() + private final String KEY_ACTION_BACK = "back"; + private final String KEY_ACTION_SAVE = "save"; + + private Card card = null; + private boolean newCard = true; + + private TagWidget editedTag = null; + private JTextField editedTagField; + + private JScrollPane scroll; + + private JTextField title; + private JTextArea content; + private JPanel tags; + private JButton addTag; + + private JButton back; + private JButton delete; + private JButton editAsBoard; + private JButton save; + + private JPopupMenu tagMenu; + private JMenuItem tagMenu_OpenUri; + private JMenuItem tagMenu_CopyValue; + + + public TabEdit() { - if( value != null ) { - setText( tag+": "+value.toString() ); - } else { - setText( tag ); - } - } - - } + this.setLayout( new BorderLayout() ); + + JPanel scrollContent = new JPanel( new GUIToolbox.CardEditLayout() ); + scroll = new JScrollPane( scrollContent ); + title = new JTextField(); + content = new JTextArea(); + tags = new JPanel(); + editedTagField = new JTextField(); + addTag = new JButton("+"); - private final String KEY_ACTION_BACK = "back"; - private final String KEY_ACTION_SAVE = "save"; - - private Card card = null; - private boolean newCard = true; + Box bottom = Box.createHorizontalBox(); + back = new JButton("Cancel"); + delete = new JButton("Delete"); + editAsBoard = new JButton("As board"); + save = new JButton("Save"); - private TagWidget editedTag = null; - private JTextField editedTagField; + tagMenu = new JPopupMenu("Tag menu"); + tagMenu_OpenUri = tagMenu.add("Open as URI"); + tagMenu_CopyValue = tagMenu.add("Copy value"); + + tags.setLayout( new FlowLayout() ); - private JScrollPane scroll; - - private JTextField title; - private JTextArea content; - private JPanel tags; - private JButton addTag; + title.setFont( new Font( "Monospaced", Font.PLAIN, 32 ) ); + content.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); + editedTagField.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) ); + + scroll.getVerticalScrollBar().setUnitIncrement(16); + + title.setMaximumSize( new Dimension( Integer.MAX_VALUE, 64 ) ); + //content.setMaximumSize( new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ) ); + content.setLineWrap( true ); + /* TODO: Figure out tags layout mess. */ + //tags.setPreferredSize( new Dimension( 16, 256 ) ); + //tags.setMaximumSize( new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ) ); - private JButton back; - private JButton delete; - private JButton editAsBoard; - private JButton save; + this.add( scroll, BorderLayout.CENTER ); + scrollContent.add( title ); + //scrollContent.add( Box.createVerticalStrut(10) ); + scrollContent.add( content ); + scrollContent.add( tags ); + + this.add( bottom, BorderLayout.SOUTH ); + bottom.add( back ); + bottom.add( Box.createHorizontalGlue() ); + bottom.add( delete ); + bottom.add( editAsBoard ); + bottom.add( save ); + + //scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); - private JPopupMenu tagMenu; - private JMenuItem tagMenu_OpenUri; - private JMenuItem tagMenu_CopyValue; + back.addActionListener(this); + delete.addActionListener(this); + editAsBoard.addActionListener(this); + save.addActionListener(this); + addTag.addActionListener(this); + + MenuElement tagMenuElements[] = tagMenu.getSubElements(); + for( int i = 0; i < tagMenuElements.length; i++ ) { + if( tagMenuElements[i] instanceof JMenuItem ) { + ((JMenuItem)tagMenuElements[i]).addActionListener(this); + } + } - - public TabEdit() - { - this.setLayout( new BorderLayout() ); + editedTagField.addFocusListener( + new FocusListener() + { + @Override + public void focusGained(FocusEvent e) + { + } - JPanel scrollContent = new JPanel( new GUIToolbox.CardEditLayout() ); - scroll = new JScrollPane( scrollContent ); - title = new JTextField(); - content = new JTextArea(); - tags = new JPanel(); - editedTagField = new JTextField(); - addTag = new JButton("+"); + @Override + public void focusLost(FocusEvent e) + { + tagCommit(); + } + } + ); - Box bottom = Box.createHorizontalBox(); - back = new JButton("Cancel"); - delete = new JButton("Delete"); - editAsBoard = new JButton("As board"); - save = new JButton("Save"); + title.getDocument().addDocumentListener( + new DocumentListener() + { + @Override + public void changedUpdate( DocumentEvent e ) + { + updateTitle(); + } + @Override + public void removeUpdate( DocumentEvent e ) + { + updateTitle(); + } + @Override + public void insertUpdate( DocumentEvent e ) + { + updateTitle(); + } + } + ); - tagMenu = new JPopupMenu("Tag menu"); - tagMenu_OpenUri = tagMenu.add("Open as URI"); - tagMenu_CopyValue = tagMenu.add("Copy value"); - - tags.setLayout( new FlowLayout() ); + registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); + registerKeyboardAction( this, KEY_ACTION_SAVE, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - title.setFont( new Font( "Monospaced", Font.PLAIN, 32 ) ); - content.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); - editedTagField.setFont( new Font( "Monospaced", Font.PLAIN, 12 ) ); + title.setToolTipText("Card title."); + back.setToolTipText("Go back without saving. Can also use [ESC]."); + delete.setToolTipText("Delete the card. There is no confirmation, nor going back."); + editAsBoard.setToolTipText("Edit this card as board."); + save.setToolTipText("Save and go back. Shift-click to save without exiting. Can also use [CTRL]+[S]."); - scroll.getVerticalScrollBar().setUnitIncrement(16); + addTag.setToolTipText("Add new tag."); + + tagMenu_OpenUri.setToolTipText("Open tag's value as URI; most commonly a file path ('file://') or URL ('http://')."); + tagMenu_CopyValue.setToolTipText("Copy tag's value to clipboard."); + + } - title.setMaximumSize( new Dimension( Integer.MAX_VALUE, 64 ) ); - //content.setMaximumSize( new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ) ); - content.setLineWrap( true ); - /* TODO: Figure out tags layout mess. */ - //tags.setPreferredSize( new Dimension( 16, 256 ) ); - //tags.setMaximumSize( new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ) ); + private void scrollTop() + { + JScrollBar scrollbar = scroll.getVerticalScrollBar(); + scrollbar.setValue(0); + } + + private void scrollBottom() + { + JScrollBar scrollbar = scroll.getVerticalScrollBar(); + int maximum = scrollbar.getMaximum()-scrollbar.getVisibleAmount(); + scrollbar.setValue(maximum); + } + + public void cardCreate() + { + newCard = true; + card = new Card(); + updateTitle(); + delete.setVisible(false); + updateTags(); + } - this.add( scroll, BorderLayout.CENTER ); - scrollContent.add( title ); - //scrollContent.add( Box.createVerticalStrut(10) ); - scrollContent.add( content ); - scrollContent.add( tags ); + public void cardEdit( Card card ) + { + newCard = false; + this.card = card; + title.setText( card.titleGet() ); + content.setText( card.contentGet() ); + updateTitle(); + delete.setVisible(true); + updateTags(); + /* TODO: Is this needed? */ + SwingUtilities.invokeLater( + new Runnable() + { + public void run() + { + scrollTop(); + } + } + ); + } - this.add( bottom, BorderLayout.SOUTH ); - bottom.add( back ); - bottom.add( Box.createHorizontalGlue() ); - bottom.add( delete ); - bottom.add( editAsBoard ); - bottom.add( save ); + private void reset() + { + title.setText(""); + content.setText(""); + card = null; + } + + private void updateTitle() + { + Window window = (Window)this.getTopLevelAncestor(); + + String text = title.getText(); + String action = newCard ? "Create" : "Edit"; + + if( text.length() > 0 ) { + window.setTitle( window.preferredTitle( action+": "+text ) ); + } else { + window.setTitle( window.preferredTitle( action ) ); + } - //scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); - - back.addActionListener(this); - delete.addActionListener(this); - editAsBoard.addActionListener(this); - save.addActionListener(this); - addTag.addActionListener(this); + } - MenuElement tagMenuElements[] = tagMenu.getSubElements(); - for( int i = 0; i < tagMenuElements.length; i++ ) { - if( tagMenuElements[i] instanceof JMenuItem ) { - ((JMenuItem)tagMenuElements[i]).addActionListener(this); - } + private void updateTags() + { + tags.removeAll(); + TagWidget newWidget; + for( String tag : card.tagNames() ) { + if( tag.startsWith("_") ) { + continue; + } + for( Object value : card.tagValues( tag ) ) { + newWidget = new TagWidget( tag, value ); + tags.add( newWidget ); + newWidget.addActionListener(this); + newWidget.addMouseListener(this); + } + } + tags.add( addTag ); + tags.validate(); + tags.repaint(); + } + + private void tagAdd() + { + tags.add( editedTagField, GUIToolbox.componentGetIndex( addTag ) ); + editedTagField.setText( "" ); + editedTagField.setColumns(12); + editedTagField.grabFocus(); + tags.validate(); + tags.repaint(); + System.out.print( "Opened new tag for editing.\n" ); + } + + private void tagRemove( TagWidget tagWidget ) + { + System.out.print( "Removed tag '"+tagWidget.tag+"' with value '"+tagWidget.value+"'.\n" ); + card.tagValueRemove( tagWidget.tag, tagWidget.value ); + tags.remove( tagWidget ); + + tags.validate(); + tags.repaint(); } - editedTagField.addFocusListener( - new FocusListener() - { - @Override - public void focusGained(FocusEvent e) - { - } - - @Override - public void focusLost(FocusEvent e) - { - tagCommit(); - } - } - ); + private void tagEdit( TagWidget tagWidget ) + { + editedTag = tagWidget; + tags.add( editedTagField, GUIToolbox.componentGetIndex( editedTag ) ); + if( editedTag.value != null ) { + editedTagField.setText( editedTag.tag+":"+editedTag.value.toString() ); + } else { + editedTagField.setText( editedTag.tag ); + } + editedTagField.setColumns(0); + editedTagField.grabFocus(); + editedTag.setVisible(false); + tags.validate(); + tags.repaint(); + System.out.print( "Opened existing tag for editing.\n" ); + } - title.getDocument().addDocumentListener( - new DocumentListener() - { - @Override - public void changedUpdate( DocumentEvent e ) - { - updateTitle(); - } - @Override - public void removeUpdate( DocumentEvent e ) - { - updateTitle(); - } - @Override - public void insertUpdate( DocumentEvent e ) - { - updateTitle(); - } - } - ); - - registerKeyboardAction( this, KEY_ACTION_BACK, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), WHEN_IN_FOCUSED_WINDOW ); - registerKeyboardAction( this, KEY_ACTION_SAVE, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - - title.setToolTipText("Card title."); - back.setToolTipText("Go back without saving. Can also use [ESC]."); - delete.setToolTipText("Delete the card. There is no confirmation, nor going back."); - editAsBoard.setToolTipText("Edit this card as board."); - save.setToolTipText("Save and go back. Shift-click to save without exiting. Can also use [CTRL]+[S]."); + private void tagCommit() + { - addTag.setToolTipText("Add new tag."); - - tagMenu_OpenUri.setToolTipText("Open tag's value as URI; most commonly a file path ('file://') or URL ('http://')."); - tagMenu_CopyValue.setToolTipText("Copy tag's value to clipboard."); - - } - - private void scrollTop() - { - JScrollBar scrollbar = scroll.getVerticalScrollBar(); - scrollbar.setValue(0); - } + String newTag; + Object newValue; - private void scrollBottom() - { - JScrollBar scrollbar = scroll.getVerticalScrollBar(); - int maximum = scrollbar.getMaximum()-scrollbar.getVisibleAmount(); - scrollbar.setValue(maximum); - } - - public void cardCreate() - { - newCard = true; - card = new Card(); - updateTitle(); - delete.setVisible(false); - updateTags(); - } - - public void cardEdit( Card card ) - { - newCard = false; - this.card = card; - title.setText( card.titleGet() ); - content.setText( card.contentGet() ); - updateTitle(); - delete.setVisible(true); - updateTags(); - SwingUtilities.invokeLater( - new Runnable() - { - public void run() - { - scrollTop(); - } - } - ); - } + { + String[] split = editedTagField.getText().split( ":", 2 ); + newTag = split[0]; + if( split.length > 1 && !split[1].equals("") ) { + newValue = split[1]; + } else { + newValue = null; + } + } + + /* Either editing tag, or adding a new one. */ + if( editedTag != null ) { + + String oldTag = editedTag.tag; + Object oldValue = editedTag.value; + + logTagChange( oldTag, oldValue, newTag, newValue ); - private void reset() - { - title.setText(""); - content.setText(""); - card = null; - } + if( oldTag.equals(newTag) ) { + card.tagValueReplace( oldTag, oldValue, newValue ); + editedTag.value = newValue; + editedTag.update(); + } else { /* Replace tag with another one. */ - private void updateTitle() - { - Window window = (Window)this.getTopLevelAncestor(); - - String text = title.getText(); - String action = newCard ? "Create" : "Edit"; + card.tagValueRemove( oldTag, oldValue ); + card.tagValueAdd( newTag, newValue ); - if( text.length() > 0 ) { - window.setTitle( window.preferredTitle( action+": "+text ) ); - } else { - window.setTitle( window.preferredTitle( action ) ); - } - - } - - private void updateTags() - { - tags.removeAll(); - TagWidget newWidget; - for( String tag : card.tagNames() ) { - if( tag.startsWith("_") ) { - continue; - } - for( Object value : card.tagValues( tag ) ) { - newWidget = new TagWidget( tag, value ); - tags.add( newWidget ); - newWidget.addActionListener(this); - newWidget.addMouseListener(this); - } - } - tags.add( addTag ); - tags.validate(); - tags.repaint(); - } + if( !newTag.equals("") ) { + editedTag.tag = newTag; + editedTag.value = newValue; + editedTag.update(); + } else { + tags.remove( editedTag ); + } + + } + + editedTag.setVisible( true ); - private void tagAdd() - { - tags.add( editedTagField, GUIToolbox.componentGetIndex( addTag ) ); - editedTagField.setText( "" ); - editedTagField.setColumns(12); - editedTagField.grabFocus(); - tags.validate(); - tags.repaint(); - System.out.print( "Opened new tag for editing.\n" ); - } + } else { /* Adding new tag (value). */ + if( !newTag.equals("") ) { + /* Only add new tag button if the tag value is unique. */ + if( card.tagValueAdd( newTag, newValue ) ) { + TagWidget newWidget = new TagWidget( newTag, newValue ); + tags.add( newWidget, GUIToolbox.componentGetIndex( addTag )-1 ); + newWidget.addActionListener(this); + newWidget.addMouseListener(this); + logTagChange( "", null, newTag, newValue ); + } else { + logTagChange( "", null, "", null ); + } + } else { + logTagChange( "", null, "", null ); + } + } - private void tagRemove( TagWidget tagWidget ) - { - System.out.print( "Removed tag '"+tagWidget.tag+"' with value '"+tagWidget.value+"'.\n" ); - card.tagValueRemove( tagWidget.tag, tagWidget.value ); - tags.remove( tagWidget ); - - tags.validate(); - tags.repaint(); - } - - private void tagEdit( TagWidget tagWidget ) - { - editedTag = tagWidget; - tags.add( editedTagField, GUIToolbox.componentGetIndex( editedTag ) ); - if( editedTag.value != null ) { - editedTagField.setText( editedTag.tag+":"+editedTag.value.toString() ); - } else { - editedTagField.setText( editedTag.tag ); - } - editedTagField.setColumns(0); - editedTagField.grabFocus(); - editedTag.setVisible(false); - tags.validate(); - tags.repaint(); - System.out.print( "Opened existing tag for editing.\n" ); - } + editedTagField.setText( "" ); + tags.remove( editedTagField ); - private void tagCommit() - { - - String newTag; - Object newValue; + editedTag = null; - { - String[] split = editedTagField.getText().split( ":", 2 ); - newTag = split[0]; - if( split.length > 1 && !split[1].equals("") ) { - newValue = split[1]; - } else { - newValue = null; - } + tags.validate(); + tags.repaint(); + } - /* Either editing tag, or adding a new one. */ - if( editedTag != null ) { - - String oldTag = editedTag.tag; - Object oldValue = editedTag.value; + private void logTagChange( String oldTag, Object oldValue, String newTag, Object newValue ) + { + System.out.print( "Comitted changes to tag: " ); + if( oldTag.equals("") ) { /* Creating tag. */ + if( !newTag.equals("") ) { + if( newValue == null ) { /* No value. */ + System.out.print( "Added tag '"+newTag+"' (with no value)\n" ); + } else { /* Has value. */ + System.out.print( "Added tag '"+newTag+"' with value '"+newValue.toString()+"'\n" ); + } + } else { + System.out.print( "No changes.\n" ); + } + } else { /* Editing tag. */ + if( oldTag.equals(newTag) ) { /* Same tag. */ + if( oldValue == null ) { + if( newValue == null ) { /* Clear before, clear now. */ + System.out.print( "No changes (tag '"+oldTag+"' with no value)\n" ); + } else { /* Assigned value. */ + System.out.print( "Assigned value of tag '"+oldTag+"' to '"+newValue.toString()+"'\n" ); + } + } else { + if( newValue == null ) { /* Clearing value. */ + System.out.print( "Cleared value of tag '"+oldTag+"' (was '" + +oldValue.toString()+"')\n" ); + } else if( oldValue.equals(newValue) ) { /* Value is the same. */ + System.out.print( "No changes (tag '"+oldTag+"' with value '"+oldValue+"')\n" ); + } else { /* Changing value. */ + System.out.print( "Changed value of tag '"+oldTag+"' from '" + +oldValue.toString()+"' to '"+newValue.toString()+"'\n" ); + } + } + } else { /* Replaced tag. */ + if( newTag.equals("") ) { /* Removing tag. */ + if( oldValue == null ) { + System.out.print( "Removed tag '"+oldTag+"' (with no value)\n" ); + } else { + System.out.print( "Removed tag '"+oldTag+"' with value '"+oldValue.toString()+"'\n" ); + } + } else { + if( oldValue == null ) { + if( newValue == null ) { + System.out.print( + "Renamed tag '"+oldTag+"' -> '" + +newTag+"'\n" ); + } else { + System.out.print( + "Changed tag '"+oldTag+"' -> '" + +newTag+"': '"+newValue.toString()+"'\n" ); + } + } else { + if( newValue == null ) { + System.out.print( + "Changed tag '"+oldTag+"': '"+oldValue.toString()+"' -> '" + +newTag+"'\n" ); + } else { + System.out.print( + "Changed tag '"+oldTag+"': '"+oldValue.toString()+"' -> '" + +newTag+"': '"+newValue.toString()+"'\n" ); + } + } + } + } + } + } - logTagChange( oldTag, oldValue, newTag, newValue ); - - if( oldTag.equals(newTag) ) { - card.tagValueReplace( oldTag, oldValue, newValue ); - editedTag.value = newValue; - editedTag.update(); - } else { /* Replace tag with another one. */ - - card.tagValueRemove( oldTag, oldValue ); - card.tagValueAdd( newTag, newValue ); - - if( !newTag.equals("") ) { - editedTag.tag = newTag; - editedTag.value = newValue; - editedTag.update(); - } else { - tags.remove( editedTag ); + + private void buttonClickedBack() + { + Window window = (Window)this.getTopLevelAncestor(); + reset(); + window.tabSwitch( Tab.SEARCH ); + } + + private void buttonClickedDelete() + { + + if( newCard ) { + return; } - - } + + Main.database.cardDeleteByIdentifier( card.identifierGet() ); + + Window window = (Window)this.getTopLevelAncestor(); + Main.refreshSearches(); + reset(); + window.tabSwitch( Tab.SEARCH ); - editedTag.setVisible( true ); - - } else { /* Adding new tag (value). */ - if( !newTag.equals("") ) { - /* Only add new tag button if the tag value is unique. */ - if( card.tagValueAdd( newTag, newValue ) ) { - TagWidget newWidget = new TagWidget( newTag, newValue ); - tags.add( newWidget, GUIToolbox.componentGetIndex( addTag )-1 ); - newWidget.addActionListener(this); - newWidget.addMouseListener(this); - logTagChange( "", null, newTag, newValue ); - } else { - logTagChange( "", null, "", null ); - } - } else { - logTagChange( "", null, "", null ); - } + } + + private void buttonClickedEditAsBoard() + { + Window window = (Window)this.getTopLevelAncestor(); + + buttonClickedSave(true); + window.tabBoard.boardEdit(card); + reset(); + window.tabSwitch( Tab.BOARD ); } - editedTagField.setText( "" ); - tags.remove( editedTagField ); - - editedTag = null; - - tags.validate(); - tags.repaint(); - - } + private void buttonClickedSave( boolean noSwitch ) + { - private void logTagChange( String oldTag, Object oldValue, String newTag, Object newValue ) - { - System.out.print( "Comitted changes to tag: " ); - if( oldTag.equals("") ) { /* Creating tag. */ - if( !newTag.equals("") ) { - if( newValue == null ) { /* No value. */ - System.out.print( "Added tag '"+newTag+"' (with no value)\n" ); - } else { /* Has value. */ - System.out.print( "Added tag '"+newTag+"' with value '"+newValue.toString()+"'\n" ); + card.titleSet( title.getText() ); + card.contentSet( content.getText() ); + + if( newCard ) { + Main.database.cardAdd( card ); + } else { + Main.database.cardUpdate( card, true ); } - } else { - System.out.print( "No changes.\n" ); - } - } else { /* Editing tag. */ - if( oldTag.equals(newTag) ) { /* Same tag. */ - if( oldValue == null ) { - if( newValue == null ) { /* Clear before, clear now. */ - System.out.print( "No changes (tag '"+oldTag+"' with no value)\n" ); - } else { /* Assigned value. */ - System.out.print( "Assigned value of tag '"+oldTag+"' to '"+newValue.toString()+"'\n" ); - } - } else { - if( newValue == null ) { /* Clearing value. */ - System.out.print( "Cleared value of tag '"+oldTag+"' (was '" - +oldValue.toString()+"')\n" ); - } else if( oldValue.equals(newValue) ) { /* Value is the same. */ - System.out.print( "No changes (tag '"+oldTag+"' with value '"+oldValue+"')\n" ); - } else { /* Changing value. */ - System.out.print( "Changed value of tag '"+oldTag+"' from '" - +oldValue.toString()+"' to '"+newValue.toString()+"'\n" ); - } - } - } else { /* Replaced tag. */ - if( newTag.equals("") ) { /* Removing tag. */ - if( oldValue == null ) { - System.out.print( "Removed tag '"+oldTag+"' (with no value)\n" ); - } else { - System.out.print( "Removed tag '"+oldTag+"' with value '"+oldValue.toString()+"'\n" ); - } - } else { - if( oldValue == null ) { - if( newValue == null ) { - System.out.print( - "Renamed tag '"+oldTag+"' -> '" - +newTag+"'\n" ); - } else { - System.out.print( - "Changed tag '"+oldTag+"' -> '" - +newTag+"': '"+newValue.toString()+"'\n" ); + + Main.refreshSearches(); + + if( noSwitch ) { + if( newCard ) { + cardEdit( this.card ); } - } else { - if( newValue == null ) { - System.out.print( - "Changed tag '"+oldTag+"': '"+oldValue.toString()+"' -> '" - +newTag+"'\n" ); - } else { - System.out.print( - "Changed tag '"+oldTag+"': '"+oldValue.toString()+"' -> '" - +newTag+"': '"+newValue.toString()+"'\n" ); - } - } + } else { + Window window = (Window)this.getTopLevelAncestor(); + reset(); + window.tabSwitch( Tab.SEARCH ); } - } - } - } - - - private void buttonClickedBack() - { - Window window = (Window)this.getTopLevelAncestor(); - reset(); - window.tabSwitch( Tab.SEARCH ); - } - - private void buttonClickedDelete() - { - - if( newCard ) { - return; } - - Main.database.cardDeleteByIdentifier( card.identifierGet() ); - - Window window = (Window)this.getTopLevelAncestor(); - Main.refreshSearches(); - reset(); - window.tabSwitch( Tab.SEARCH ); - - } - private void buttonClickedEditAsBoard() - { - Window window = (Window)this.getTopLevelAncestor(); - - buttonClickedSave(true); - window.tabBoard.boardEdit(card); - reset(); - window.tabSwitch( Tab.BOARD ); - } - - private void buttonClickedSave( boolean noSwitch ) - { - - card.titleSet( title.getText() ); - card.contentSet( content.getText() ); - - if( newCard ) { - Main.database.cardAdd( card ); - } else { - Main.database.cardUpdate( card, true ); + private boolean possiblyShowTagContextMenu( MouseEvent e ) + { + if( e.isPopupTrigger() ) { + TagWidget tagWidget = (TagWidget)e.getSource(); + tagMenu_OpenUri.setEnabled( tagWidget.value instanceof String ); + tagMenu_CopyValue.setEnabled( tagWidget.value != null ); + tagMenu.show( tagWidget, e.getX(), e.getY() ); + return true; + } else { + return false; + } } - Main.refreshSearches(); - - if( noSwitch ) { - if( newCard ) { - cardEdit( this.card ); - } - } else { - Window window = (Window)this.getTopLevelAncestor(); - reset(); - window.tabSwitch( Tab.SEARCH ); - } - } + public void actionPerformed( ActionEvent e ) + { + Object source = e.getSource(); + if( source == this ) { + switch( e.getActionCommand() ) { - private boolean possiblyShowTagContextMenu( MouseEvent e ) - { - if( e.isPopupTrigger() ) { - TagWidget tagWidget = (TagWidget)e.getSource(); - tagMenu_OpenUri.setEnabled( tagWidget.value instanceof String ); - tagMenu_CopyValue.setEnabled( tagWidget.value != null ); - tagMenu.show( tagWidget, e.getX(), e.getY() ); - return true; - } else { - return false; - } - } + case KEY_ACTION_BACK: { + buttonClickedBack(); + break; + } - public void actionPerformed( ActionEvent e ) - { - Object source = e.getSource(); - if( source == this ) { - switch( e.getActionCommand() ) { - - case KEY_ACTION_BACK: { - buttonClickedBack(); - break; - } + case KEY_ACTION_SAVE: { + buttonClickedSave( true ); + Main.database.databaseCommit(); + break; + } - case KEY_ACTION_SAVE: { - buttonClickedSave( true ); - Main.database.databaseCommit(); - break; - } - - } - } else if( source == back ) { - buttonClickedBack(); - } else if( source == editAsBoard ) { - buttonClickedEditAsBoard(); - } else if( source == delete ) { - buttonClickedDelete(); - } else if( source == save ) { - boolean noSwitch = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; - buttonClickedSave( noSwitch ); - } else if( source == addTag ) { - tagAdd(); - } else if( source instanceof TagWidget ) { - tagEdit( (TagWidget)source ); - } else if( source == tagMenu_OpenUri ) { - TagWidget tagWidget = (TagWidget)tagMenu.getInvoker(); - Main.actionOpenURI( (String)tagWidget.value ); - } else if( source == tagMenu_CopyValue ) { - TagWidget tagWidget = (TagWidget)tagMenu.getInvoker(); - Main.clipboardSet( String.valueOf(tagWidget.value) ); + } + } else if( source == back ) { + buttonClickedBack(); + } else if( source == editAsBoard ) { + buttonClickedEditAsBoard(); + } else if( source == delete ) { + buttonClickedDelete(); + } else if( source == save ) { + boolean noSwitch = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; + buttonClickedSave( noSwitch ); + } else if( source == addTag ) { + tagAdd(); + } else if( source instanceof TagWidget ) { + tagEdit( (TagWidget)source ); + } else if( source == tagMenu_OpenUri ) { + TagWidget tagWidget = (TagWidget)tagMenu.getInvoker(); + Main.actionOpenURI( (String)tagWidget.value ); + } else if( source == tagMenu_CopyValue ) { + TagWidget tagWidget = (TagWidget)tagMenu.getInvoker(); + Main.clipboardSet( String.valueOf(tagWidget.value) ); + } } - } + + public void mouseEntered( MouseEvent e ) {} + public void mouseExited( MouseEvent e ) {} - public void mouseEntered( MouseEvent e ) {} - public void mouseExited( MouseEvent e ) {} - - public void mouseClicked( MouseEvent e ) - { - Object source = e.getSource(); - if( e.getButton() == MouseEvent.BUTTON2 && source instanceof TagWidget ) { - tagRemove( (TagWidget)source ); + public void mouseClicked( MouseEvent e ) + { + Object source = e.getSource(); + if( e.getButton() == MouseEvent.BUTTON2 && source instanceof TagWidget ) { + tagRemove( (TagWidget)source ); + } } - } - - public void mousePressed( MouseEvent e ) - { - if( possiblyShowTagContextMenu(e) ) { - return; + + public void mousePressed( MouseEvent e ) + { + if( possiblyShowTagContextMenu(e) ) { + return; + } } - } - public void mouseReleased( MouseEvent e ) - { - if( possiblyShowTagContextMenu(e) ) { - return; + public void mouseReleased( MouseEvent e ) + { + if( possiblyShowTagContextMenu(e) ) { + return; + } } - } - + }
--- a/src/junotu/TabSimpleSearch.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/TabSimpleSearch.java Thu Apr 06 01:44:10 2023 +0200 @@ -35,209 +35,210 @@ public class TabSimpleSearch extends JPanel implements ActionListener, TabInterface { - public boolean dirty; - - private final String KEY_ACTION_COMMIT = "commit"; - - private JTextField field; - private JButton create; - private JButton context; - private JPopupMenu menu; - private Box results; - private JScrollPane scroll; + public boolean dirty; + + private final String KEY_ACTION_COMMIT = "commit"; - private JMenuItem menu_calendar; - private JMenuItem menu_resaveAll; - - public TabSimpleSearch() - { - dirty = true; - - this.setLayout( new BorderLayout() ); + private JTextField field; + private JButton create; + private JButton context; + private JPopupMenu menu; + private Box results; + private JScrollPane scroll; + + private JMenuItem menu_calendar; + private JMenuItem menu_resaveAll; + + public TabSimpleSearch() + { + dirty = true; + + this.setLayout( new BorderLayout() ); - JPanel top = new JPanel( new BorderLayout() ); - Box buttonBox = Box.createHorizontalBox(); - context = new JButton("="); - create = new JButton("+"); - field = new JTextField(); - results = Box.createVerticalBox(); - scroll = new JScrollPane( results ); - - menu = new JPopupMenu("Menu"); - menu_calendar = menu.add("Calendar board"); - menu_resaveAll = menu.add("Resave all cards (developer)"); - - context.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); - create.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); - field.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); + JPanel top = new JPanel( new BorderLayout() ); + Box buttonBox = Box.createHorizontalBox(); + context = new JButton("="); + create = new JButton("+"); + field = new JTextField(); + results = Box.createVerticalBox(); + scroll = new JScrollPane( results ); - scroll.getVerticalScrollBar().setUnitIncrement(128); + menu = new JPopupMenu("Menu"); + menu_calendar = menu.add("Calendar board"); + menu_resaveAll = menu.add("Resave all cards (developer)"); - field.setPreferredSize( new Dimension(32, 32) ); - - this.add( top, BorderLayout.NORTH ); - top.add( field, BorderLayout.CENTER ); - top.add( buttonBox, BorderLayout.EAST ); - buttonBox.add( context ); - buttonBox.add( create ); + context.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); + create.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); + field.setFont( new Font( "Monospaced", Font.PLAIN, 16 ) ); - this.add( scroll, BorderLayout.CENTER ); - - scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + scroll.getVerticalScrollBar().setUnitIncrement(128); - create.addActionListener(this); - context.addActionListener(this); - menu_calendar.addActionListener(this); - menu_resaveAll.addActionListener(this); + field.setPreferredSize( new Dimension(32, 32) ); - field.getDocument().addDocumentListener( - new DocumentListener() - { - @Override - public void changedUpdate( DocumentEvent e ) - { - updateTitle(); - search(); - } - @Override - public void removeUpdate( DocumentEvent e ) - { - updateTitle(); - search(); - } - @Override - public void insertUpdate( DocumentEvent e ) - { - updateTitle(); - search(); - } - } - ); + this.add( top, BorderLayout.NORTH ); + top.add( field, BorderLayout.CENTER ); + top.add( buttonBox, BorderLayout.EAST ); + buttonBox.add( context ); + buttonBox.add( create ); - registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); + this.add( scroll, BorderLayout.CENTER ); + + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + + create.addActionListener(this); + context.addActionListener(this); + menu_calendar.addActionListener(this); + menu_resaveAll.addActionListener(this); - field.setToolTipText("Search query."); - create.setToolTipText("Create new card. Shift-click to open it in a new window."); - context.setToolTipText("Bring up a menu with more actions."); - menu_calendar.setToolTipText("Open calendar board."); - menu_resaveAll.setToolTipText("Resave all cards. Might be useful if you updated program version and database format changed."); - - } - - private void search() { + field.getDocument().addDocumentListener( + new DocumentListener() + { + @Override + public void changedUpdate( DocumentEvent e ) + { + updateTitle(); + search(); + } + @Override + public void removeUpdate( DocumentEvent e ) + { + updateTitle(); + search(); + } + @Override + public void insertUpdate( DocumentEvent e ) + { + updateTitle(); + search(); + } + } + ); - if( !javax.swing.SwingUtilities.isEventDispatchThread() ) { - SwingUtilities.invokeLater( - new Runnable() - { - public void run() - { - search(); - } - } - ); - return; - } - - Card[] cards; + registerKeyboardAction( this, KEY_ACTION_COMMIT, KeyStroke.getKeyStroke( KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK ), WHEN_IN_FOCUSED_WINDOW ); - String text = field.getText(); - if( text.length() > 0 ) { - cards = Main.database.searchSimple( field.getText() ); - } else { - cards = Main.database.searchTopRecent( 32 ); + field.setToolTipText("Search query."); + create.setToolTipText("Create new card. Shift-click to open it in a new window."); + context.setToolTipText("Bring up a menu with more actions."); + menu_calendar.setToolTipText("Open calendar board."); + menu_resaveAll.setToolTipText("Resave all cards. Might be useful if you updated program version and database format changed."); + } - 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 search() { - /* Otherwise scrollup doesn't work. Perhaps because GUI needs to redraw first? */ - SwingUtilities.invokeLater( - new Runnable() - { - public void run() - { - scrollTop(); - } - } - ); - } + /* TODO: Is this needed? */ + if( !javax.swing.SwingUtilities.isEventDispatchThread() ) { + SwingUtilities.invokeLater( + new Runnable() + { + public void run() + { + search(); + } + } + ); + return; + } + + Card[] cards; + + String text = field.getText(); + if( text.length() > 0 ) { + cards = Main.database.searchSimple( field.getText() ); + } else { + cards = Main.database.searchTopRecent( 32 ); + } + + System.out.print("Search: Found "+cards.length+" matches.\n"); - public void refreshSearch() - { - search(); - dirty = false; - } + /* TODO: Reuse widgets. */ + results.removeAll(); + for( Card card : cards ) { + CardWidget cardWidget = new CardWidget( card ); + results.add( cardWidget ); + } + results.validate(); + results.repaint(); - private void scrollTop() - { - JScrollBar scrollbar = scroll.getVerticalScrollBar(); - scrollbar.setValue(0); - } - - private void updateTitle() - { - Window window = (Window)this.getTopLevelAncestor(); + /* Otherwise scrollup doesn't work. Perhaps because GUI needs to redraw first? */ + SwingUtilities.invokeLater( + new Runnable() + { + public void run() + { + scrollTop(); + } + } + ); + } - String text = field.getText(); + public void refreshSearch() + { + search(); + dirty = false; + } - if( text.length() > 0 ) { - window.setTitle( window.preferredTitle( "Search: "+text ) ); - } else { - window.setTitle( window.preferredTitle( "Search" ) ); + private void scrollTop() + { + JScrollBar scrollbar = scroll.getVerticalScrollBar(); + scrollbar.setValue(0); } - - } - - private void buttonClickedCreate( boolean newWindow ) - { - if( newWindow ) { - Main.actionCardCreate( Main.windowAdd( Tab.EDIT ) ); - } else { - Window window = (Window)this.getTopLevelAncestor(); - Main.actionCardCreate( window ); + + private void updateTitle() + { + Window window = (Window)this.getTopLevelAncestor(); + + String text = field.getText(); + + if( text.length() > 0 ) { + window.setTitle( window.preferredTitle( "Search: "+text ) ); + } else { + window.setTitle( window.preferredTitle( "Search" ) ); + } + } - } - public void actionPerformed( ActionEvent e ) - { - Object source = e.getSource(); - if( source == this ) { - switch( e.getActionCommand() ){ - - case KEY_ACTION_COMMIT: { - Main.database.databaseCommit(); - break; - } + private void buttonClickedCreate( boolean newWindow ) + { + if( newWindow ) { + Main.actionCardCreate( Main.windowAdd( Tab.EDIT ) ); + } else { + Window window = (Window)this.getTopLevelAncestor(); + Main.actionCardCreate( window ); + } + } - } - } else if( source == create ) { - boolean newWindow = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; - buttonClickedCreate( newWindow ); - } else if( source == context ) { - menu.show( (Component)source, 0, 0 ); - } else if( source == menu_calendar ) { - Window window = (Window)this.getTopLevelAncestor(); - window.tabSwitch( Tab.CALENDAR_BOARD ); - } else if( source == menu_resaveAll ) { - Main.database.databaseResaveAll(); - Main.refreshSearches(); + public void actionPerformed( ActionEvent e ) + { + Object source = e.getSource(); + if( source == this ) { + switch( e.getActionCommand() ){ + + case KEY_ACTION_COMMIT: { + Main.database.databaseCommit(); + break; + } + + } + } else if( source == create ) { + boolean newWindow = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; + buttonClickedCreate( newWindow ); + } else if( source == context ) { + menu.show( (Component)source, 0, 0 ); + } else if( source == menu_calendar ) { + Window window = (Window)this.getTopLevelAncestor(); + window.tabSwitch( Tab.CALENDAR_BOARD ); + } else if( source == menu_resaveAll ) { + Main.database.databaseResaveAll(); + Main.refreshSearches(); + } } - } - public void onSwitchedTo() { - if( dirty ) { - refreshSearch(); - dirty = false; + public void onSwitchedTo() { + if( dirty ) { + refreshSearch(); + dirty = false; + } } - } - + }
--- a/src/junotu/TagUtility.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/TagUtility.java Thu Apr 06 01:44:10 2023 +0200 @@ -7,25 +7,25 @@ public class TagUtility { - public static Card[] parseCardList( String value ) - { - if( value.length() == 0 ) { - return new Card[0]; + public static Card[] parseCardList( String value ) + { + if( value.length() == 0 ) { + return new Card[0]; + } + /* This split on an empty string will actually return an array of length 1. */ + String[] identifierStrings = value.split(" "); + Card[] cards = new Card[identifierStrings.length]; + for( int i = 0; i < identifierStrings.length; i++ ) { + long identifier; + try { + identifier = Long.parseLong(identifierStrings[i]); + } catch( NumberFormatException e ) { + cards[i] = null; + continue; + } + cards[i] = Main.database.cardGetByIdentifier(identifier); + } + return cards; } - /* This split on an empty string will actually return an array of length 1. */ - String[] identifierStrings = value.split(" "); - Card[] cards = new Card[identifierStrings.length]; - for( int i = 0; i < identifierStrings.length; i++ ) { - long identifier; - try { - identifier = Long.parseLong(identifierStrings[i]); - } catch( NumberFormatException e ) { - cards[i] = null; - continue; - } - cards[i] = Main.database.cardGetByIdentifier(identifier); - } - return cards; - } - + }
--- a/src/junotu/Window.java Wed Apr 05 22:58:38 2023 +0200 +++ b/src/junotu/Window.java Thu Apr 06 01:44:10 2023 +0200 @@ -29,119 +29,119 @@ public class Window extends JFrame implements ActionListener { - public static interface TabInterface { - void onSwitchedTo(); - } - - public enum Tab { - SEARCH, - EDIT, - BOARD, - CALENDAR_BOARD, - }; + public static interface TabInterface { + void onSwitchedTo(); + } + + public enum Tab { + SEARCH, + EDIT, + BOARD, + CALENDAR_BOARD, + }; - private static final String[] TAB_NAMES = { - "Search", - "Edit", - "Board", - "Calendar board", - }; + private static final String[] TAB_NAMES = { + "Search", + "Edit", + "Board", + "Calendar board", + }; - public final String KEY_ACTION_NEW_WINDOW = "new_window"; + public final String KEY_ACTION_NEW_WINDOW = "new_window"; + + public TabSimpleSearch tabSearch; + public TabEdit tabEdit; + public TabBoard tabBoard; + public TabCalendarBoard tabCalendarBoard; - public TabSimpleSearch tabSearch; - public TabEdit tabEdit; - public TabBoard tabBoard; - public TabCalendarBoard tabCalendarBoard; - - private JPanel tabs; - private CardLayout tabsLayout; + private JPanel tabs; + private CardLayout tabsLayout; + + private Tab activeTab; - private Tab activeTab; - - public Window( Tab tab ) - { + public Window( Tab tab ) + { - panelsCreate(); - tabSwitch( tab ); + panelsCreate(); + tabSwitch( tab ); - this.setSize(512, 384); - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.setVisible(true); - - } + this.setSize(512, 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); - } + @Override + protected void processWindowEvent( WindowEvent e ) + { + switch( e.getID() ) { + case WindowEvent.WINDOW_CLOSING: { + Main.windowClose(this); + } + } } - } - @Override - public void actionPerformed( ActionEvent e ) - { - if( e.getActionCommand() == KEY_ACTION_NEW_WINDOW ) { - Main.windowAdd( Tab.SEARCH ); - } - } - - public void tabSwitch( Tab tab ) - { - if( tab == activeTab ) { - return; + @Override + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == KEY_ACTION_NEW_WINDOW ) { + Main.windowAdd( Tab.SEARCH ); + } } - tabsLayout.show(tabs, TAB_NAMES[tab.ordinal()]); - Object tabObject = tabs.getComponent(tab.ordinal()); - if( tabObject instanceof TabInterface ) { - TabInterface tabInterface = (TabInterface)tabObject; - tabInterface.onSwitchedTo(); + + public void tabSwitch( Tab tab ) + { + if( tab == activeTab ) { + return; + } + tabsLayout.show(tabs, TAB_NAMES[tab.ordinal()]); + Object tabObject = tabs.getComponent(tab.ordinal()); + if( tabObject instanceof TabInterface ) { + TabInterface tabInterface = (TabInterface)tabObject; + tabInterface.onSwitchedTo(); + } + activeTab = tab; + this.setTitle(preferredTitle(TAB_NAMES[activeTab.ordinal()])); } - activeTab = tab; - this.setTitle(preferredTitle(TAB_NAMES[activeTab.ordinal()])); - } - public Tab tabCurrent() - { - return activeTab; - } + public Tab tabCurrent() + { + return activeTab; + } - public String preferredTitle( String tabStatus ) - { - return Main.PROGRAM_NAME+" - "+tabStatus; - } - - private void panelsCreate() - { + public String preferredTitle( String tabStatus ) + { + return Main.PROGRAM_NAME+" - "+tabStatus; + } + + private void panelsCreate() + { - tabsLayout = new CardLayout(); - tabs = new JPanel( tabsLayout ); + tabsLayout = new CardLayout(); + tabs = new JPanel( tabsLayout ); - tabSearch = new TabSimpleSearch(); - tabEdit = new TabEdit(); - tabBoard = new TabBoard(); - tabCalendarBoard = new TabCalendarBoard(); + tabSearch = new TabSimpleSearch(); + tabEdit = new TabEdit(); + tabBoard = new TabBoard(); + tabCalendarBoard = new TabCalendarBoard(); - this.add(tabs); - tabs.add(tabSearch); - tabs.add(tabEdit); - tabs.add(tabBoard); - tabs.add(tabCalendarBoard); - tabsLayout.addLayoutComponent( tabSearch, TAB_NAMES[Tab.SEARCH.ordinal()] ); - tabsLayout.addLayoutComponent( tabEdit, TAB_NAMES[Tab.EDIT.ordinal()] ); - tabsLayout.addLayoutComponent( tabBoard, TAB_NAMES[Tab.BOARD.ordinal()] ); - tabsLayout.addLayoutComponent( tabCalendarBoard, TAB_NAMES[Tab.CALENDAR_BOARD.ordinal()] ); + this.add(tabs); + tabs.add(tabSearch); + tabs.add(tabEdit); + tabs.add(tabBoard); + tabs.add(tabCalendarBoard); + tabsLayout.addLayoutComponent( tabSearch, TAB_NAMES[Tab.SEARCH.ordinal()] ); + tabsLayout.addLayoutComponent( tabEdit, TAB_NAMES[Tab.EDIT.ordinal()] ); + tabsLayout.addLayoutComponent( tabBoard, TAB_NAMES[Tab.BOARD.ordinal()] ); + tabsLayout.addLayoutComponent( tabCalendarBoard, TAB_NAMES[Tab.CALENDAR_BOARD.ordinal()] ); - tabs.registerKeyboardAction( - this, - KEY_ACTION_NEW_WINDOW, - KeyStroke.getKeyStroke( KeyEvent.VK_F2, 0 ), - JPanel.WHEN_IN_FOCUSED_WINDOW - ); - - } + tabs.registerKeyboardAction( + this, + KEY_ACTION_NEW_WINDOW, + KeyStroke.getKeyStroke( KeyEvent.VK_F2, 0 ), + JPanel.WHEN_IN_FOCUSED_WINDOW + ); + + } }