/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/agpl.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package se.streamsource.streamflow.client.ui.workspace.cases.conversations; import ca.odell.glazedlists.gui.TableFormat; import ca.odell.glazedlists.swing.EventJXTableModel; import ca.odell.glazedlists.swing.EventTableModel; import org.jdesktop.application.Action; import org.jdesktop.application.ApplicationAction; import org.jdesktop.application.ApplicationContext; import org.jdesktop.application.Task; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.decorator.HighlighterFactory; import org.jdesktop.swingx.renderer.DefaultTableRenderer; import org.jdesktop.swingx.renderer.StringValue; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; import org.qi4j.api.structure.Module; import se.streamsource.streamflow.api.workspace.cases.conversation.MessageDTO; import se.streamsource.streamflow.client.Icons; import se.streamsource.streamflow.client.MacOsUIWrapper; import se.streamsource.streamflow.client.StreamflowResources; import se.streamsource.streamflow.client.ui.DateFormats; import se.streamsource.streamflow.client.util.CommandTask; import se.streamsource.streamflow.client.util.RefreshComponents; import se.streamsource.streamflow.client.util.RefreshWhenShowing; import se.streamsource.streamflow.client.util.StreamflowButton; import se.streamsource.streamflow.client.util.dialog.ConfirmationDialog; import se.streamsource.streamflow.client.util.dialog.DialogService; import se.streamsource.streamflow.client.util.i18n; import se.streamsource.streamflow.infrastructure.event.domain.TransactionDomainEvents; import se.streamsource.streamflow.infrastructure.event.domain.source.TransactionListener; import se.streamsource.streamflow.infrastructure.event.domain.source.helper.Events; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.Font; import java.awt.KeyboardFocusManager; import java.awt.font.TextAttribute; import java.util.Date; import java.util.Locale; import java.util.Map; import static se.streamsource.streamflow.client.ui.workspace.WorkspaceResources.*; import static se.streamsource.streamflow.client.util.i18n.*; import static se.streamsource.streamflow.infrastructure.event.domain.source.helper.Events.*; public class MessagesView extends JPanel implements TransactionListener { private static final long serialVersionUID = -4508473068931275932L; @Structure Module module; @Service DialogService dialogs; private MessagesModel model; private JXTable messageTable; private JPanel detailMessagePanel; private JPanel sendPanel = new JPanel( new BorderLayout( ) ); private JPanel messageViewPanel = new JPanel( new BorderLayout( ) ); private MessageView messageView; private MessageDraftView messageDraftView; private StreamflowButton writeMessage; private javax.swing.Action createMessage; public MessagesView(@Service ApplicationContext context, @Uses MessagesModel model ) { setActionMap(context.getActionMap(this)); MacOsUIWrapper.convertAccelerators(getActionMap()); setLayout(new BorderLayout()); this.model = model; // Add proxy actions ApplicationAction closeMessageDetailsAction = (ApplicationAction)getActionMap().get("closeMessageDetails"); javax.swing.Action closeMessageDetails = context.getActionMap().get("closeMessageDetails"); closeMessageDetails.putValue("proxy", closeMessageDetailsAction); ApplicationAction createMessageAction = (ApplicationAction)getActionMap().get("createMessage"); createMessage = context.getActionMap().get("createMessage"); createMessage.putValue("proxy", createMessageAction); ApplicationAction cancelNewMessageAction = (ApplicationAction)getActionMap().get("cancelNewMessage"); javax.swing.Action cancelNewMessage = context.getActionMap().get("cancelNewMessage"); cancelNewMessage.putValue("proxy", cancelNewMessageAction); messageTable = new JXTable(new EventJXTableModel<MessageDTO>(model.messages(), new TableFormat<MessageDTO>() { String[] columnNames = new String[] { "", text(sender_column_header), text(message_column_header), text(created_column_header), "" }; public int getColumnCount() { return columnNames.length; } public String getColumnName(int i) { return columnNames[i]; } public Object getColumnValue(MessageDTO o, int i) { switch (i) { case 0: return o.hasAttachments().get(); case 1: return o.sender().get(); case 2: return o.text().get(); case 3: return o.createdOn().get(); case 4: return o.id().get(); } return null; } })){ public Component prepareRenderer( TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); // add custom rendering here EventTableModel model = (EventTableModel) getModel(); if( model.getElementAt( row ) instanceof MessageDTO) { Map attributes = c.getFont().getAttributes(); if ( ((MessageDTO) model.getElementAt( row )).unread().get() ) { attributes.put( TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD ); } c.setFont( new Font(attributes) ); } return c; } }; messageTable.getColumnExt( messageTable.getColumnCount()-1 ).setVisible( false ); messageTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); messageTable .setFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)); messageTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, KeyboardFocusManager .getCurrentKeyboardFocusManager() .getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS)); messageTable.getColumn(3).setCellRenderer(new DefaultTableRenderer(new StringValue() { private static final long serialVersionUID = -6677363096055906298L; public String getString(Object value) { return DateFormats.getProgressiveDateTimeValue((Date) value, Locale.getDefault()); } })); messageTable.getColumn(0).setCellRenderer( new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column ) { ImageIcon icon = i18n.icon( Icons.attachments, 11 ); JLabel iconLabel = (Boolean) value ? new JLabel( icon ) : new JLabel( " " ); iconLabel.setOpaque( true ); if (isSelected) iconLabel.setBackground( messageTable.getSelectionBackground() ); return iconLabel; } } ); ListSelectionModel selectionModel = messageTable.getSelectionModel(); selectionModel.addListSelectionListener(new MessageListSelectionHandler()); messageTable.addHighlighter(HighlighterFactory.createAlternateStriping()); messageTable.getColumn(0).setPreferredWidth( 20 ); messageTable.getColumn( 0 ).setWidth( 20 ); messageTable.getColumn(0).setMaxWidth( 20 ); messageTable.getColumn(0).setResizable( false ); messageTable.getColumn( 1 ).setPreferredWidth(250); messageTable.getColumn( 1 ).setMaxWidth( 250 ); messageTable.getColumn(2).setPreferredWidth(300); messageTable.getColumn(3).setPreferredWidth(60); messageTable.getColumn(3).setMaxWidth(100); detailMessagePanel = new JPanel(new CardLayout()); JPanel createPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); javax.swing.Action writeMessageAction = getActionMap().get("writeMessage"); writeMessage = new StreamflowButton(writeMessageAction); writeMessage.registerKeyboardAction(writeMessageAction, (KeyStroke) writeMessageAction.getValue(javax.swing.Action.ACCELERATOR_KEY), JComponent.WHEN_IN_FOCUSED_WINDOW); createPanel.add(writeMessage); detailMessagePanel.add( createPanel, "INITIAL"); detailMessagePanel.add( sendPanel, "NEW_MESSAGE" ); detailMessagePanel.add( messageViewPanel, "SHOW_MESSAGE" ); ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "INITIAL" ); JScrollPane scrollMessages = new JScrollPane(messageTable); add(scrollMessages, BorderLayout.CENTER); add(detailMessagePanel, BorderLayout.SOUTH); model.addObserver( new RefreshComponents().visibleOn( "createmessagefromdraft", writeMessage ) ); new RefreshWhenShowing(this, model); } @Action public void writeMessage() { sendPanel.removeAll(); messageDraftView = module.objectBuilderFactory().newObjectBuilder( MessageDraftView.class ).use( model.newMessageDraftModel() ).newInstance(); sendPanel.add( messageDraftView, BorderLayout.CENTER ); ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "NEW_MESSAGE" ); messageDraftView.requestFocusInWindow(); } @Action public Task createMessage() { ConfirmationDialog dialog = module.objectBuilderFactory().newObject(ConfirmationDialog.class); dialogs.showOkCancelHelpDialog( this, dialog, text( StreamflowResources.confirmation ) ); if( dialog.isConfirmed( ) ) { sendPanel.removeAll(); ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "INITIAL" ); return new CommandTask() { @Override public void command() throws Exception { model.createMessageFromDraft(); } }; } return null; } @Action public void cancelNewMessage() { sendPanel.removeAll(); ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "INITIAL" ); } @Action public void closeMessageDetails() { messageTable.getSelectionModel().clearSelection(); messageViewPanel.removeAll(); ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "INITIAL" ); } public void notifyTransactions(Iterable<TransactionDomainEvents> transactions) { if ( matches(Events.withNames("createdMessage", "createdMessageFromDraft", "setUnread"), transactions) || matches( withUsecases( "resolve", "reopen" ),transactions )) { model.refresh(); } } class MessageListSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { int index = messageTable.getSelectedRow(); if (index >= 0) { Object selectedValue = messageTable.getModel().getValueAt( messageTable.convertRowIndexToModel( index ), messageTable.getColumnCount() ); String href = (String) selectedValue; ((CardLayout) detailMessagePanel.getLayout()).show( detailMessagePanel, "INITIAL" ); messageViewPanel.removeAll(); messageView = module.objectBuilderFactory().newObjectBuilder( MessageView.class ).use( model.newMessageModel( href ) ).newInstance(); EventTableModel model = (EventTableModel) messageTable.getModel(); MessageDTO messageDTO = (MessageDTO)model.getElementAt( index ); if( messageDTO.unread().get() ) { messageView.read(); } messageViewPanel.add( messageView, BorderLayout.CENTER ); ((CardLayout) detailMessagePanel.getLayout()).show(detailMessagePanel, "SHOW_MESSAGE"); } } } } }