Skip to content

Commit 2cb78d3

Browse files
committed
Add recent filters list to message browser
Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
1 parent 1d5e2cd commit 2cb78d3

3 files changed

Lines changed: 234 additions & 4 deletions

File tree

client/src/com/mirth/connect/client/ui/browsers/message/MessageBrowser.java

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ public class MessageBrowser extends javax.swing.JPanel {
150150
private String channelId;
151151
protected List<String> channelIds = new ArrayList<String>();
152152
private String channelName;
153+
private MessageBrowserRecentFilterStore recentFilterStore;
153154
private boolean isChannelDeployed;
154155
private boolean isCURESPHILoggingOn;
155156
protected boolean isChannelMessagesPanelFirstLoadSearch;
@@ -331,6 +332,7 @@ public void loadChannel(MessageBrowserChannelModel channelModel) {
331332

332333
this.channelId = channelId;
333334
this.channelName = channelName;
335+
this.recentFilterStore = new MessageBrowserRecentFilterStore(channelId);
334336
this.connectors = connectors;
335337
this.connectors.put(null, "Deleted Connectors");
336338
initMetaDataColumns(channelModel);
@@ -340,6 +342,7 @@ public void loadChannel(MessageBrowserChannelModel channelModel) {
340342
resetSearchCriteria();
341343
advancedSearchPopup.setSelectedMetaDataIds(selectedMetaDataIds);
342344
updateAdvancedSearchButtonFont();
345+
recentFiltersButton.setEnabled(!recentFilterStore.getRecentFilters().isEmpty());
343346

344347
lastUserSelectedMessageType = "Raw";
345348
updateMessageRadioGroup();
@@ -452,6 +455,75 @@ public void updateAdvancedSearchButtonFont() {
452455
}
453456
}
454457

458+
private void restoreRecentFilter() {
459+
// Multi-channel browse may be null
460+
if (recentFilterStore == null) return;
461+
462+
JPopupMenu popupMenu = new JPopupMenu();
463+
for (MessageFilter filter : recentFilterStore.getRecentFilters()) {
464+
var menuItem = new JMenuItem(filter.toString(connectors, "; ", /* includeEmptyCriteria: */ false));
465+
menuItem.addActionListener(e -> applyMessageFilter(filter));
466+
popupMenu.add(menuItem);
467+
}
468+
popupMenu.show(recentFiltersButton, 0, recentFiltersButton.getHeight());
469+
}
470+
471+
private void applyMessageFilter(MessageFilter filter) {
472+
resetSearchCriteria();
473+
474+
boolean allDay = inferAllDay(filter);
475+
476+
mirthDatePicker1.setDate((filter.getStartDate() == null) ? null : filter.getStartDate().getTime());
477+
mirthDatePicker2.setDate((filter.getEndDate() == null) ? null : filter.getEndDate().getTime());
478+
allDayCheckBox.setSelected(allDay);
479+
mirthTimePicker1.setEnabled(mirthDatePicker1.getDate() != null && !allDay);
480+
mirthTimePicker2.setEnabled(mirthDatePicker2.getDate() != null && !allDay);
481+
482+
if (filter.getStartDate() != null) {
483+
mirthTimePicker1.setDate(new SimpleDateFormat("HH:mm").format(filter.getStartDate().getTime()));
484+
}
485+
if (filter.getEndDate() != null && !allDay) {
486+
mirthTimePicker2.setDate(new SimpleDateFormat("HH:mm").format(filter.getEndDate().getTime()));
487+
}
488+
489+
textSearchField.setText(StringUtils.defaultString(filter.getTextSearch()));
490+
regexTextSearchCheckBox.setSelected(Boolean.TRUE.equals(filter.getTextSearchRegex()));
491+
492+
Set<Status> statuses = filter.getStatuses();
493+
statusBoxReceived.setSelected(statuses != null && statuses.contains(Status.RECEIVED));
494+
statusBoxTransformed.setSelected(statuses != null && statuses.contains(Status.TRANSFORMED));
495+
statusBoxFiltered.setSelected(statuses != null && statuses.contains(Status.FILTERED));
496+
statusBoxQueued.setSelected(statuses != null && statuses.contains(Status.QUEUED));
497+
statusBoxPending.setSelected(statuses != null && statuses.contains(Status.PENDING));
498+
statusBoxSent.setSelected(statuses != null && statuses.contains(Status.SENT));
499+
statusBoxError.setSelected(statuses != null && statuses.contains(Status.ERROR));
500+
501+
advancedSearchPopup.applyFilter(filter);
502+
updateAdvancedSearchButtonFont();
503+
updateFilterButtonFont(Font.BOLD);
504+
}
505+
506+
private boolean inferAllDay(MessageFilter filter) {
507+
if (filter == null) {
508+
return false;
509+
}
510+
511+
Calendar endDate = filter.getEndDate();
512+
if (endDate != null) {
513+
return endDate.get(Calendar.HOUR_OF_DAY) == 23
514+
&& endDate.get(Calendar.MINUTE) == 59
515+
&& endDate.get(Calendar.SECOND) == 59
516+
&& endDate.get(Calendar.MILLISECOND) == 999;
517+
}
518+
519+
Calendar startDate = filter.getStartDate();
520+
return startDate != null
521+
&& startDate.get(Calendar.HOUR_OF_DAY) == 0
522+
&& startDate.get(Calendar.MINUTE) == 0
523+
&& startDate.get(Calendar.SECOND) == 0
524+
&& startDate.get(Calendar.MILLISECOND) == 0;
525+
}
526+
455527
public String getChannelId() {
456528
return channelId;
457529
}
@@ -654,6 +726,13 @@ protected boolean generateMessageFilter() {
654726
advancedSearchPopup.applySelectionsToFilter(messageFilter);
655727
selectedMetaDataIds = messageFilter.getIncludedMetaDataIds();
656728

729+
if (recentFilterStore != null && !messageFilter.isEmpty()) {
730+
recentFilterStore.addRecentFilter(messageFilter);
731+
recentFiltersButton.setEnabled(true);
732+
}
733+
734+
// To keep page results consistent, the search is "capped" to the most
735+
// recent message that has been received by the channel.
657736
if (messageFilter.getMaxMessageId() == null) {
658737
try {
659738
Long maxMessageId = parent.mirthClient.getMaxMessageId(channelId);
@@ -684,7 +763,7 @@ protected void runSearch() {
684763
clearCache();
685764
loadPageNumber(1);
686765

687-
updateSearchCriteriaPane();
766+
lastSearchCriteria.setText(messageFilter.toString(connectors, "\n", /* includeEmptyCriteria: */ true));
688767
auditSearch();
689768
}
690769
}
@@ -2648,6 +2727,11 @@ public void actionPerformed(java.awt.event.ActionEvent evt) {
26482727
}
26492728
});
26502729

2730+
recentFiltersButton = new javax.swing.JButton();
2731+
recentFiltersButton.setText("Recent...");
2732+
recentFiltersButton.setEnabled(false);
2733+
recentFiltersButton.addActionListener(e -> restoreRecentFilter());
2734+
26512735
statusBoxFiltered.setBackground(new java.awt.Color(255, 255, 255));
26522736
statusBoxFiltered.setText("FILTERED");
26532737
statusBoxFiltered.setFont(new java.awt.Font("Lucida Grande", 0, 11)); // NOI18N
@@ -2775,8 +2859,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) {
27752859
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
27762860
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
27772861
.addComponent(allDayCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
2778-
.addComponent(filterButton, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
2779-
.addComponent(regexTextSearchCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
2862+
.addComponent(recentFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
2863+
.addComponent(regexTextSearchCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
2864+
.addComponent(filterButton, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE))
27802865
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
27812866
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
27822867
.addComponent(statusBoxQueued, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
@@ -2830,7 +2915,8 @@ public void actionPerformed(java.awt.event.ActionEvent evt) {
28302915
.addComponent(mirthTimePicker2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
28312916
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
28322917
.addComponent(mirthDatePicker2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
2833-
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
2918+
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
2919+
.addComponent(recentFiltersButton))
28342920
.addGap(7, 7, 7)
28352921
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
28362922
.addComponent(textSearchField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
@@ -3110,6 +3196,7 @@ private void textSearchFieldActionPerformed(java.awt.event.ActionEvent evt) {//G
31103196
private javax.swing.JLabel processedResponseLabel;
31113197
private javax.swing.JLabel processedResponseStatusLabel;
31123198
private com.mirth.connect.client.ui.components.MirthSyntaxTextArea processedResponseStatusTextArea;
3199+
private javax.swing.JButton recentFiltersButton;
31133200
private com.mirth.connect.client.ui.components.MirthCheckBox regexTextSearchCheckBox;
31143201
private javax.swing.JButton resetButton;
31153202
private javax.swing.JLabel responseLabel;

client/src/com/mirth/connect/client/ui/browsers/message/MessageBrowserAdvancedFilter.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,81 @@ public Boolean hasAdvancedCriteria() {
510510
return hasAdvancedCriteria;
511511
}
512512

513+
public void applyFilter(MessageFilter messageFilter) {
514+
stopEditing();
515+
resetSelections();
516+
517+
if (messageFilter == null) {
518+
return;
519+
}
520+
521+
ItemSelectionTableModel<Integer, String> connectorModel = ((ItemSelectionTableModel<Integer, String>) connectorTable.getModel());
522+
DefaultTableModel contentSearchModel = ((DefaultTableModel) contentSearchTable.getModel());
523+
DefaultTableModel metaDataSearchModel = ((DefaultTableModel) metaDataSearchTable.getModel());
524+
525+
List<Integer> includedMetaDataIds = messageFilter.getIncludedMetaDataIds();
526+
List<Integer> excludedMetaDataIds = messageFilter.getExcludedMetaDataIds();
527+
528+
if (includedMetaDataIds != null) {
529+
connectorModel.unselectAllKeys();
530+
for (Integer metaDataId : includedMetaDataIds) {
531+
connectorModel.selectKey(metaDataId);
532+
}
533+
} else if (excludedMetaDataIds != null) {
534+
connectorModel.selectAllKeys();
535+
for (int row = 0; row < connectorModel.getRowCount(); row++) {
536+
Integer metaDataId = (Integer) connectorModel.getValueAt(row, ItemSelectionTableModel.KEY_COLUMN);
537+
if (excludedMetaDataIds.contains(metaDataId)) {
538+
connectorModel.setValueAt(Boolean.FALSE, row, ItemSelectionTableModel.CHECKBOX_COLUMN);
539+
}
540+
}
541+
}
542+
543+
messageIdLowerField.setText((messageFilter.getMinMessageId() == null) ? "" : String.valueOf(messageFilter.getMinMessageId()));
544+
messageIdUpperField.setText((messageFilter.getMaxMessageId() == null) ? "" : String.valueOf(messageFilter.getMaxMessageId()));
545+
originalIdLowerField.setText((messageFilter.getOriginalIdLower() == null) ? "" : String.valueOf(messageFilter.getOriginalIdLower()));
546+
originalIdUpperField.setText((messageFilter.getOriginalIdUpper() == null) ? "" : String.valueOf(messageFilter.getOriginalIdUpper()));
547+
importIdLowerField.setText((messageFilter.getImportIdLower() == null) ? "" : String.valueOf(messageFilter.getImportIdLower()));
548+
importIdUpperField.setText((messageFilter.getImportIdUpper() == null) ? "" : String.valueOf(messageFilter.getImportIdUpper()));
549+
serverIdField.setText(StringUtils.defaultString(messageFilter.getServerId()));
550+
sendAttemptsLower.setValue((messageFilter.getSendAttemptsLower() == null) ? 0 : messageFilter.getSendAttemptsLower());
551+
sendAttemptsUpper.setValue((messageFilter.getSendAttemptsUpper() == null) ? "" : String.valueOf(messageFilter.getSendAttemptsUpper()));
552+
attachmentCheckBox.setSelected(Boolean.TRUE.equals(messageFilter.getAttachment()));
553+
errorCheckBox.setSelected(Boolean.TRUE.equals(messageFilter.getError()));
554+
555+
if (messageFilter.getContentSearch() != null) {
556+
for (ContentSearchElement contentSearchElement : messageFilter.getContentSearch()) {
557+
for (String search : contentSearchElement.getSearches()) {
558+
contentSearchModel.addRow(new Object[] { ContentType.fromCode(contentSearchElement.getContentCode()), search });
559+
}
560+
}
561+
}
562+
563+
if (messageFilter.getMetaDataSearch() != null) {
564+
for (MetaDataSearchElement metaDataSearchElement : messageFilter.getMetaDataSearch()) {
565+
if (cachedMetaDataColumns.containsKey(metaDataSearchElement.getColumnName())) {
566+
metaDataSearchModel.addRow(new Object[] {
567+
metaDataSearchElement.getColumnName(),
568+
MetaDataSearchOperator.fromString(metaDataSearchElement.getOperator()),
569+
formatMetaDataValue(metaDataSearchElement.getValue()),
570+
Boolean.TRUE.equals(metaDataSearchElement.getIgnoreCase()) });
571+
}
572+
}
573+
}
574+
}
575+
576+
private String formatMetaDataValue(Object value) {
577+
if (value == null) {
578+
return "";
579+
}
580+
581+
if (value instanceof java.util.Calendar) {
582+
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(((java.util.Calendar) value).getTime());
583+
}
584+
585+
return String.valueOf(value);
586+
}
587+
513588
private void stopEditing() {
514589
// if the user had typed in a value in the content search table, close the cell editor so that any value that was entered will be included in the search
515590
TableCellEditor cellEditor = contentSearchTable.getCellEditor();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) Mirth Corporation. All rights reserved.
3+
*
4+
* http://www.mirthcorp.com
5+
*
6+
* The software in this package is published under the terms of the MPL license a copy of which has
7+
* been included with this distribution in the LICENSE.txt file.
8+
*/
9+
10+
package com.mirth.connect.client.ui.browsers.message;
11+
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.prefs.Preferences;
15+
16+
import org.apache.commons.lang3.StringUtils;
17+
18+
import com.mirth.connect.client.ui.Mirth;
19+
import com.mirth.connect.model.converters.ObjectXMLSerializer;
20+
import com.mirth.connect.model.filters.MessageFilter;
21+
22+
class MessageBrowserRecentFilterStore {
23+
private static final int MAX_RECENT_FILTERS = 10;
24+
private static final String RECENT_FILTERS_PREFERENCE_PREFIX = "messageBrowserRecentFilters.";
25+
26+
private final String prefKey;
27+
28+
public MessageBrowserRecentFilterStore(String channelId) {
29+
this.prefKey = RECENT_FILTERS_PREFERENCE_PREFIX + channelId;
30+
}
31+
32+
public List<MessageFilter> getRecentFilters() {
33+
try {
34+
String serialized = Preferences.userNodeForPackage(Mirth.class).get(prefKey, "");
35+
if (StringUtils.isBlank(serialized)) return List.of();
36+
37+
return (List<MessageFilter>) ObjectXMLSerializer.getInstance().deserialize(serialized, List.class);
38+
} catch (Exception e) {
39+
// Fail quietly if the stored filters cannot be deserialized for any reason.
40+
e.printStackTrace();
41+
return List.of();
42+
}
43+
}
44+
45+
public void addRecentFilter(MessageFilter filter) {
46+
if (filter == null) {
47+
throw new IllegalArgumentException("Filter cannot be null");
48+
}
49+
50+
var filters = new ArrayList<MessageFilter>(getRecentFilters());
51+
52+
// Remove then re-add to avoid duplicates
53+
filters.remove(filter);
54+
filters.add(0, filter);
55+
56+
// Trim to the maximum number of recent filters
57+
if (filters.size() > MAX_RECENT_FILTERS) {
58+
filters.subList(MAX_RECENT_FILTERS, filters.size()).clear();
59+
}
60+
61+
try {
62+
var preferences = Preferences.userNodeForPackage(Mirth.class);
63+
preferences.put(prefKey, ObjectXMLSerializer.getInstance().serialize(filters));
64+
} catch (Exception e) {
65+
e.printStackTrace();
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)