@@ -53,28 +53,32 @@ public class MassSetFieldAction extends MnemonicAwareAction {
53
53
private JRadioButton selected ;
54
54
private JRadioButton clear ;
55
55
private JRadioButton set ;
56
+ private JRadioButton append ;
56
57
private JRadioButton rename ;
57
58
private JComboBox <String > field ;
58
- private JTextField text ;
59
- private JTextField renameTo ;
59
+ private JTextField textFieldSet ;
60
+ private JTextField textFieldAppend ;
61
+ private JTextField textFieldRename ;
60
62
private boolean canceled = true ;
61
63
private JCheckBox overwrite ;
62
64
63
65
64
66
public MassSetFieldAction (JabRefFrame frame ) {
65
- putValue (Action .NAME , Localization .menuTitle ("Set/clear/rename fields" ) + "..." );
67
+ putValue (Action .NAME , Localization .menuTitle ("Set/clear/append/ rename fields" ) + "..." );
66
68
this .frame = frame ;
67
69
}
68
70
69
71
private void createDialog () {
70
- diag = new JDialog (frame , Localization .lang ("Set/clear/rename fields" ), true );
72
+ diag = new JDialog (frame , Localization .lang ("Set/clear/append/ rename fields" ), true );
71
73
72
74
field = new JComboBox <>();
73
75
field .setEditable (true );
74
- text = new JTextField ();
75
- text .setEnabled (false );
76
- renameTo = new JTextField ();
77
- renameTo .setEnabled (false );
76
+ textFieldSet = new JTextField ();
77
+ textFieldSet .setEnabled (false );
78
+ textFieldAppend = new JTextField ();
79
+ textFieldAppend .setEnabled (false );
80
+ textFieldRename = new JTextField ();
81
+ textFieldRename .setEnabled (false );
78
82
79
83
JButton ok = new JButton (Localization .lang ("OK" ));
80
84
JButton cancel = new JButton (Localization .lang ("Cancel" ));
@@ -83,6 +87,7 @@ private void createDialog() {
83
87
selected = new JRadioButton (Localization .lang ("Selected entries" ));
84
88
clear = new JRadioButton (Localization .lang ("Clear fields" ));
85
89
set = new JRadioButton (Localization .lang ("Set fields" ));
90
+ append = new JRadioButton (Localization .lang ("Append to fields" ));
86
91
rename = new JRadioButton (Localization .lang ("Rename field to" ) + ":" );
87
92
rename .setToolTipText (Localization .lang ("Move contents of a field into a field with a different name" ));
88
93
@@ -93,16 +98,23 @@ private void createDialog() {
93
98
}
94
99
95
100
set .addChangeListener (e ->
96
- // Entering a text is only relevant if we are setting, not clearing:
97
- text .setEnabled (set .isSelected ()));
101
+ // Entering a setText is only relevant if we are setting, not clearing:
102
+ textFieldSet .setEnabled (set .isSelected ()));
103
+
104
+ append .addChangeListener (e -> {
105
+ // Text to append is only required if we are appending:
106
+ textFieldAppend .setEnabled (append .isSelected ());
107
+ // Overwrite protection makes no sense if we are appending to a field:
108
+ overwrite .setEnabled (!clear .isSelected () && !append .isSelected ());
109
+ });
98
110
99
111
clear .addChangeListener (e ->
100
- // Overwrite protection makes no sense if we are clearing the field:
101
- overwrite .setEnabled (!clear .isSelected ()));
112
+ // Overwrite protection makes no sense if we are clearing the field:
113
+ overwrite .setEnabled (!clear . isSelected () && ! append .isSelected ()));
102
114
103
115
rename .addChangeListener (e ->
104
- // Entering a text is only relevant if we are renaming
105
- renameTo .setEnabled (rename .isSelected ()));
116
+ // Entering a setText is only relevant if we are renaming
117
+ textFieldRename .setEnabled (rename .isSelected ()));
106
118
107
119
overwrite = new JCheckBox (Localization .lang ("Overwrite existing field values" ), true );
108
120
ButtonGroup bg = new ButtonGroup ();
@@ -111,9 +123,10 @@ private void createDialog() {
111
123
bg = new ButtonGroup ();
112
124
bg .add (clear );
113
125
bg .add (set );
126
+ bg .add (append );
114
127
bg .add (rename );
115
128
FormBuilder builder = FormBuilder .create ().layout (new FormLayout (
116
- "left:pref, 4dlu, fill:100dlu:grow" , "pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref" ));
129
+ "left:pref, 4dlu, fill:100dlu:grow" , "pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref " ));
117
130
builder .addSeparator (Localization .lang ("Field name" )).xyw (1 , 1 , 3 );
118
131
builder .add (Localization .lang ("Field name" )).xy (1 , 3 );
119
132
builder .add (field ).xy (3 , 3 );
@@ -122,11 +135,13 @@ private void createDialog() {
122
135
builder .add (selected ).xyw (1 , 9 , 3 );
123
136
builder .addSeparator (Localization .lang ("New field value" )).xyw (1 , 11 , 3 );
124
137
builder .add (set ).xy (1 , 13 );
125
- builder .add (text ).xy (3 , 13 );
138
+ builder .add (textFieldSet ).xy (3 , 13 );
126
139
builder .add (clear ).xyw (1 , 15 , 3 );
127
- builder .add (rename ).xy (1 , 17 );
128
- builder .add (renameTo ).xy (3 , 17 );
129
- builder .add (overwrite ).xyw (1 , 19 , 3 );
140
+ builder .add (append ).xy (1 , 17 );
141
+ builder .add (textFieldAppend ).xy (3 , 17 );
142
+ builder .add (rename ).xy (1 , 19 );
143
+ builder .add (textFieldRename ).xy (3 , 19 );
144
+ builder .add (overwrite ).xyw (1 , 21 , 3 );
130
145
131
146
ButtonBarBuilder bb = new ButtonBarBuilder ();
132
147
bb .addGlue ();
@@ -219,31 +234,36 @@ public void actionPerformed(ActionEvent e) {
219
234
} else {
220
235
entryList = entries ;
221
236
}
222
- String toSet = text .getText ();
237
+
238
+ String toSet = textFieldSet .getText ();
223
239
if (toSet .isEmpty ()) {
224
240
toSet = null ;
225
241
}
226
242
227
243
String [] fields = getFieldNames (((String ) field .getSelectedItem ()).trim ().toLowerCase (Locale .ROOT ));
228
- NamedCompound ce = new NamedCompound (Localization .lang ("Set field" ));
244
+ NamedCompound compoundEdit = new NamedCompound (Localization .lang ("Set field" ));
229
245
if (rename .isSelected ()) {
230
246
if (fields .length > 1 ) {
231
247
JOptionPane .showMessageDialog (diag , Localization .lang ("You can only rename one field at a time" ), "" ,
232
248
JOptionPane .ERROR_MESSAGE );
233
249
return ; // Do not close the dialog.
234
250
} else {
235
- ce .addEdit (MassSetFieldAction .massRenameField (entryList , fields [0 ], renameTo .getText (),
251
+ compoundEdit .addEdit (MassSetFieldAction .massRenameField (entryList , fields [0 ], textFieldRename .getText (),
236
252
overwrite .isSelected ()));
237
253
}
254
+ } else if (append .isSelected ()) {
255
+ for (String field : fields ) {
256
+ compoundEdit .addEdit (MassSetFieldAction .massAppendField (entryList , field , textFieldAppend .getText ()));
257
+ }
238
258
} else {
239
- for (String field1 : fields ) {
240
- ce .addEdit (MassSetFieldAction .massSetField (entryList , field1 ,
259
+ for (String field : fields ) {
260
+ compoundEdit .addEdit (MassSetFieldAction .massSetField (entryList , field ,
241
261
set .isSelected () ? toSet : null ,
242
262
overwrite .isSelected ()));
243
263
}
244
264
}
245
- ce .end ();
246
- bp .getUndoManager ().addEdit (ce );
265
+ compoundEdit .end ();
266
+ bp .getUndoManager ().addEdit (compoundEdit );
247
267
bp .markBaseChanged ();
248
268
}
249
269
@@ -253,31 +273,58 @@ public void actionPerformed(ActionEvent e) {
253
273
*
254
274
* @param entries The entries to set the field for.
255
275
* @param field The name of the field to set.
256
- * @param text The value to set. This value can be null, indicating that the field should be cleared.
276
+ * @param textToSet The value to set. This value can be null, indicating that the field should be cleared.
257
277
* @param overwriteValues Indicate whether the value should be set even if an entry already has the field set.
258
278
* @return A CompoundEdit for the entire operation.
259
279
*/
260
- private static UndoableEdit massSetField (Collection <BibEntry > entries , String field , String text ,
280
+ private static UndoableEdit massSetField (Collection <BibEntry > entries , String field , String textToSet ,
261
281
boolean overwriteValues ) {
262
282
263
- NamedCompound ce = new NamedCompound (Localization .lang ("Set field" ));
283
+ NamedCompound compoundEdit = new NamedCompound (Localization .lang ("Set field" ));
264
284
for (BibEntry entry : entries ) {
265
- Optional <String > oldVal = entry .getField (field );
285
+ Optional <String > oldValue = entry .getField (field );
266
286
// If we are not allowed to overwrite values, check if there is a
267
287
// nonempty
268
288
// value already for this entry:
269
- if (!overwriteValues && (oldVal .isPresent ()) && !oldVal .get ().isEmpty ()) {
289
+ if (!overwriteValues && (oldValue .isPresent ()) && !oldValue .get ().isEmpty ()) {
270
290
continue ;
271
291
}
272
- if (text == null ) {
292
+ if (textToSet == null ) {
273
293
entry .clearField (field );
274
294
} else {
275
- entry .setField (field , text );
295
+ entry .setField (field , textToSet );
276
296
}
277
- ce .addEdit (new UndoableFieldChange (entry , field , oldVal .orElse (null ), text ));
297
+ compoundEdit .addEdit (new UndoableFieldChange (entry , field , oldValue .orElse (null ), textToSet ));
298
+ }
299
+ compoundEdit .end ();
300
+ return compoundEdit ;
301
+ }
302
+
303
+ /**
304
+ * Append a given value to a given field for all entries in a Collection. This method DOES NOT update any UndoManager,
305
+ * but returns a relevant CompoundEdit that should be registered by the caller.
306
+ *
307
+ * @param entries The entries to process the operation for.
308
+ * @param field The name of the field to append to.
309
+ * @param textToAppend The value to set. A null in this case will simply preserve the current field state.
310
+ * @return A CompoundEdit for the entire operation.
311
+ */
312
+ private static UndoableEdit massAppendField (Collection <BibEntry > entries , String field , String textToAppend ) {
313
+
314
+ String newValue = "" ;
315
+
316
+ if (textToAppend != null ) {
317
+ newValue = textToAppend ;
318
+ }
319
+
320
+ NamedCompound compoundEdit = new NamedCompound (Localization .lang ("Append field" ));
321
+ for (BibEntry entry : entries ) {
322
+ Optional <String > oldValue = entry .getField (field );
323
+ entry .setField (field , oldValue .orElse ("" ) + newValue );
324
+ compoundEdit .addEdit (new UndoableFieldChange (entry , field , oldValue .orElse (null ), newValue ));
278
325
}
279
- ce .end ();
280
- return ce ;
326
+ compoundEdit .end ();
327
+ return compoundEdit ;
281
328
}
282
329
283
330
/**
@@ -292,7 +339,7 @@ private static UndoableEdit massSetField(Collection<BibEntry> entries, String fi
292
339
*/
293
340
private static UndoableEdit massRenameField (Collection <BibEntry > entries , String field , String newField ,
294
341
boolean overwriteValues ) {
295
- NamedCompound ce = new NamedCompound (Localization .lang ("Rename field" ));
342
+ NamedCompound compoundEdit = new NamedCompound (Localization .lang ("Rename field" ));
296
343
for (BibEntry entry : entries ) {
297
344
Optional <String > valToMove = entry .getField (field );
298
345
// If there is no value, do nothing:
@@ -307,12 +354,12 @@ private static UndoableEdit massRenameField(Collection<BibEntry> entries, String
307
354
}
308
355
309
356
entry .setField (newField , valToMove .get ());
310
- ce .addEdit (new UndoableFieldChange (entry , newField , valInNewField .orElse (null ), valToMove .get ()));
357
+ compoundEdit .addEdit (new UndoableFieldChange (entry , newField , valInNewField .orElse (null ), valToMove .get ()));
311
358
entry .clearField (field );
312
- ce .addEdit (new UndoableFieldChange (entry , field , valToMove .get (), null ));
359
+ compoundEdit .addEdit (new UndoableFieldChange (entry , field , valToMove .get (), null ));
313
360
}
314
- ce .end ();
315
- return ce ;
361
+ compoundEdit .end ();
362
+ return compoundEdit ;
316
363
}
317
364
318
365
private static String [] getFieldNames (String s ) {
0 commit comments