Mercurial Hosting > junotu
view src/junotu/TabBoard.java @ 65:4dd7d78e19a1
Moved recursive card deletion logic to Database class
author | Fox |
---|---|
date | Fri, 23 Dec 2022 22:25:27 +0100 |
parents | e8d83f1a6100 |
children | df652edb3c0e |
line wrap: on
line source
package junotu; /* TODO: Clean-up imports. */ import java.lang.RuntimeException; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseListener; import java.awt.event.MouseAdapter; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.JPanel; import javax.swing.Box; import java.awt.BorderLayout; import java.awt.GridBagLayout; import javax.swing.BoxLayout; import java.awt.Component; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JScrollPane; import javax.swing.JScrollBar; import javax.swing.BorderFactory; import javax.swing.border.TitledBorder; import static java.lang.Math.min; import static java.lang.Math.max; import junotu.Main; import junotu.Window.Tab; import junotu.Card; public class TabBoard extends JPanel implements ActionListener, MouseListener { final static int COLUMN_CONTENT_WIDTH = 256; final static int COLUMN_WIDTH = COLUMN_CONTENT_WIDTH+16; 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)+", aborting cards loading. Full cards tag: '"+cardsString+"'\n"); break; } insertCard( cardsSplit[i], -1 ); } } public void titleSet( String title ) { titledBorder.setTitle(title); repaint(); } public String titleGet() { return titledBorder.getTitle(); } 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); } } 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 ) {} } private class ColumnCardWidget extends JPanel { public boolean newCard; public long identifier; public JTextArea title; public ColumnCardWidget( Card card ) { this.setLayout( new BorderLayout() ); title = new JTextArea(""); title.setFont( new Font( "Monospaced", Font.BOLD, 16 ) ); this.setMinimumSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); this.setPreferredSize( new Dimension( COLUMN_CONTENT_WIDTH, 64 ) ); this.setMaximumSize( new Dimension( COLUMN_CONTENT_WIDTH, 128 ) ); //title.setMinimumSize( new Dimension( 32, 32 ) ); this.setBorder( BorderFactory.createRaisedBevelBorder() ); title.setEditable( true ); title.setLineWrap( true ); title.setWrapStyleWord( true ); title.setOpaque( false ); this.add( title, BorderLayout.CENTER ); 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()); } } 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); } } catch( Exception e ) { throw new RuntimeException(e); } } public void delete() { if( newCard ) { return; } Main.database.cardDeleteByIdentifier(identifier, true); } public boolean isSelected() { return title.isFocusOwner(); } public void select() { title.requestFocusInWindow(); } } 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 ); back.addActionListener(this); addColumn.addActionListener(this); editAsCard.addActionListener(this); back.setToolTipText("Go back to where the card was accessed from."); 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() ); card.tagValueSetOnly( Card.TAG_BOARD, null ); card.tagValueSetOnly( Card.TAG_BOARD_COLUMNS, columnIdentifiers ); Main.database.cardUpdate(card); 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.tabSearch.search(); window.tabSwitch( Tab.SEARCH ); } public void actionPerformed( ActionEvent e ) { if( e.getSource() == back ) { buttonClickedBack(); return; } else if( e.getSource() == addColumn ) { insertColumn(); return; } else if( e.getSource() == editAsCard ) { buttonClickedAsCard(); return; } ColumnWidget sourceColumn = (ColumnWidget)e.getSource(); if( sourceColumn != null ) { 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 ) {} }