/** * * 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.caselog; import ca.odell.glazedlists.swing.EventListModel; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.factories.Borders; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.Sizes; import org.jdesktop.application.Action; import org.jdesktop.application.ApplicationContext; import org.jdesktop.swingx.JXList; import org.jdesktop.swingx.decorator.HighlighterFactory; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Uses; import se.streamsource.streamflow.api.workspace.cases.caselog.CaseLogEntryDTO; import se.streamsource.streamflow.client.Icons; import se.streamsource.streamflow.client.ui.workspace.WorkspaceResources; import se.streamsource.streamflow.client.util.CommandTask; import se.streamsource.streamflow.client.util.RefreshWhenShowing; import se.streamsource.streamflow.client.util.Refreshable; import se.streamsource.streamflow.client.util.StreamflowToggleButton; import se.streamsource.streamflow.client.util.i18n; import se.streamsource.streamflow.client.util.popup.PopupHandler; import se.streamsource.streamflow.client.util.popup.PopupHandler.Position; import se.streamsource.streamflow.client.util.popup.RefreshHandler; import se.streamsource.streamflow.client.util.popup.SelectionList; import se.streamsource.streamflow.client.util.popup.StandardPopupHandler; import se.streamsource.streamflow.client.util.popup.ValueToLabelConverter; import se.streamsource.streamflow.infrastructure.event.domain.TransactionDomainEvents; import se.streamsource.streamflow.infrastructure.event.domain.source.TransactionListener; import se.streamsource.streamflow.util.Strings; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Arrays; import static se.streamsource.streamflow.api.workspace.cases.caselog.CaseLogEntryTypes.*; import static se.streamsource.streamflow.client.util.i18n.*; import static se.streamsource.streamflow.infrastructure.event.domain.source.helper.Events.*; public class CaseLogView extends JPanel implements TransactionListener, Refreshable { private final CaseLogModel model; private JList filtersList; private JList list = new JXList(){ @Override public Object[] getSelectedValues() { int[] selectedIndexes = getSelectedIndices(); Object[] selectedValues = new Object[selectedIndexes.length]; for (int i = 0; i < selectedIndexes.length; i++) { CaseLogEntryDTO link = (CaseLogEntryDTO)getElementAt(selectedIndexes[i]); selectedValues[i] = link.message().get(); } return selectedValues; } }; private JScrollPane newMessagePane; private JTextArea newMessageArea; private PopupHandler filterPopupHandler; private boolean editMode = false; private ListSelectionListener listSelectionListener; private JScrollPane scroll; private StreamflowToggleButton editButton; private ImageIcon notPublishedIcon; private ImageIcon publishedIcon; public CaseLogView(@Service final ApplicationContext context, @Uses CaseLogModel logmodel) { this.model = logmodel; setActionMap( context.getActionMap( this ) ); // Load icons notPublishedIcon = icon( Icons.not_published, ICON_16 ); publishedIcon = icon( Icons.published, ICON_16 ); // Layout and form for the left panel FormLayout rightLayout = new FormLayout( "30dlu, 300:grow, 50dlu, 20dlu", "pref, fill:pref:grow, 60dlu" ); setLayout( rightLayout ); setFocusable( false ); DefaultFormBuilder rightBuilder = new DefaultFormBuilder( rightLayout, this ); rightBuilder.setBorder( Borders.createEmptyBorder( Sizes.DLUY2, Sizes.DLUX2, Sizes.DLUY2, Sizes.DLUX2 ) ); JLabel caseLogLabel = new JLabel( i18n.text( WorkspaceResources.case_log ) ); rightBuilder.add( caseLogLabel, new CellConstraints( 1, 1, 2, 1, CellConstraints.LEFT, CellConstraints.TOP, new Insets( 0, 0, 0, 0 ) ) ); rightBuilder.nextColumn(); filtersList = new SelectionList( Arrays.asList( system.name(), system_trace.name(), custom.name(), contact.name(), form.name(), conversation.name(), attachment.name() ), model.getSelectedFilters(), new ValueToLabelConverter() { public String convert(String value) { return text( valueOf( value.toString() ) ); } }, new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { if (!event.getValueIsAdjusting()) { String selectedValue = (String) ((JList) event.getSource()).getSelectedValue(); if (selectedValue != null) { if (model.getSelectedFilters().contains( selectedValue )) { model.getSelectedFilters().remove( selectedValue ); } else { model.getSelectedFilters().add( selectedValue ); } model.refresh(); ((JList) event.getSource()).clearSelection(); } } } } ); filterPopupHandler = new StandardPopupHandler( CaseLogView.this, getActionMap().get( "filter" ), Position.right, false, new RefreshHandler() { public void refresh() { model.refresh(); list.ensureIndexIsVisible( list.getModel().getSize() - 1 ); } } ); rightBuilder.add( filterPopupHandler.getButton(), new CellConstraints( 3, 1, 1, 1, CellConstraints.RIGHT, CellConstraints.TOP, new Insets( 0, 0, 0, 0 ) ) ); filtersList.addFocusListener( new FocusAdapter() { @Override public void focusLost(FocusEvent e) { if (e.getOppositeComponent() != null && (e.getOppositeComponent().equals( filterPopupHandler.getButton() ))) filterPopupHandler.kill(); } } ); editButton = new StreamflowToggleButton( getActionMap().get( "edit")); editButton.setMargin( new Insets( 3, 7, 1, 5 ) ); rightBuilder.add(editButton, new CellConstraints( 4, 1, 1, 1, CellConstraints.RIGHT, CellConstraints.TOP, new Insets( 0, 0, 0, 0 ) ) ); // Caselog rightBuilder.nextLine(); ((JXList) list).addHighlighter( HighlighterFactory.createAlternateStriping() ); list.setModel( new EventListModel<CaseLogEntryDTO>( model.caselogs() ) ); list.setCellRenderer( new CaseLogListCellRenderer() ); list.setFixedCellHeight( -1 ); list.getSelectionModel().setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); final JList tmpList = list; list.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { int index = tmpList.locationToIndex( new Point( e.getX(),e.getY() ) ); if( tmpList.getSelectedIndex() != index ) { tmpList.setSelectedIndex( index ); } final JPopupMenu menu = new JPopupMenu(); JMenuItem item = new JMenuItem(); item.setAction( context.getActionMap().get( "copy" ) ); item.setIcon( null ); menu.add( item ); final int x = e.getX(); final int y = e.getY(); final Component c = e.getComponent(); SwingUtilities.invokeLater( new Runnable() { public void run() { menu.show( c, x, y ); } } ); } } }); scroll = new JScrollPane( list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER ); scroll.setMinimumSize( new Dimension( 250, 100 ) ); scroll.setPreferredSize( new Dimension( 400, 300 ) ); rightBuilder.setExtent( 3, 1 ); rightBuilder.add( scroll, new CellConstraints( 1, 2, 4, 1, CellConstraints.FILL, CellConstraints.FILL, new Insets( 0, 0, 0, 0 ) ) ); // Add caselog message ImageIcon icon = i18n.icon( Icons.message_add, 24 ); rightBuilder.add( new JLabel( icon ), new CellConstraints( 1, 3, 1, 1, CellConstraints.LEFT, CellConstraints.TOP, new Insets( 10, 10, 0, 0 ) ) ); newMessageArea = new JTextArea( 10, 30 ); newMessageArea.setLineWrap( true ); newMessageArea.setWrapStyleWord( true ); newMessagePane = new JScrollPane( newMessageArea ); newMessagePane.setMinimumSize( new Dimension( 10, 10 ) ); newMessagePane.setPreferredSize( new Dimension( 10, 70 ) ); rightBuilder.add( newMessagePane, new CellConstraints( 2, 3, 3, 1, CellConstraints.FILL, CellConstraints.TOP, new Insets( 10, 0, 0, 0 ) ) ); newMessageArea.addKeyListener( new KeyListener() { public void keyTyped(KeyEvent e) { } public void keyReleased(KeyEvent e) { if (e.getKeyCode() == 10) { if (!e.isControlDown()) { newMessageArea.setText( "" ); } } } public void keyPressed(KeyEvent e) { if (e.getKeyCode() == 10) { if (e.isControlDown()) { newMessageArea.append( "\n" ); } else { addMessage(); } } } } ); listSelectionListener = new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { if (! event.getValueIsAdjusting()){ final CaseLogEntryDTO selectedValue = (CaseLogEntryDTO) ((JList) event.getSource()).getSelectedValue(); if (selectedValue != null) { new CommandTask(){ @Override protected void command() throws Exception { model.togglepublish( selectedValue); } }.execute(); ((JList) event.getSource()).clearSelection(); } } } }; addHierarchyListener( new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && !isShowing() && editMode){ editButton.setSelected( false ); configureComponentsForEdit( false ); } } }); new RefreshWhenShowing( this, this ); } @Action public void filter() { JPanel filterPanel = new JPanel( new BorderLayout() ); filterPanel.setPreferredSize( new Dimension( 130, 138 ) ); filterPanel.setMaximumSize( new Dimension( 130, 138 ) ); filterPanel.setMaximumSize( new Dimension( 130, 138 ) ); filterPanel.add( filtersList, BorderLayout.CENTER ); filterPopupHandler.setPanelContent( filterPanel ); } @Action public void edit() { // Toggle edit mode configureComponentsForEdit( !editMode ); } private void configureComponentsForEdit(boolean edit){ editMode = edit; if (editMode) { editButton.setIcon( publishedIcon ); scroll.setBorder( BorderFactory.createLineBorder( list.getSelectionBackground(), 2) ); list.addListSelectionListener( listSelectionListener ); } else { editButton.setIcon( notPublishedIcon ); scroll.setBorder( BorderFactory.createLineBorder( Color.GRAY, 1)); list.removeListSelectionListener( listSelectionListener ); } } public void refresh() { model.refresh(); boolean isEditable = model.getCommandEnabled( "addmessage" ); newMessagePane.getViewport().getView().setEnabled( isEditable ); editButton.setEnabled( isEditable ); if (!editMode) { list.ensureIndexIsVisible( list.getModel().getSize() - 1 ); } } public void notifyTransactions(Iterable<TransactionDomainEvents> transactions) { // on usecase delete no update necessary if( matches( withUsecases( "delete" ),transactions )) return; if (matches( withNames( "addedEntry", "modifiedMyPagesVisibility" ), transactions )) { refresh(); } } public void addMessage() { if (!Strings.empty( newMessageArea.getText() )) { model.addMessage( newMessageArea.getText() ); newMessageArea.setText( "" ); newMessageArea.setCaretPosition( 0 ); newMessageArea.requestFocusInWindow(); refresh(); } } }