Skip to content

Commit

Permalink
Merge pull request #821 from JabRef/save-actions-gui
Browse files Browse the repository at this point in the history
Save actions gui
  • Loading branch information
lenhard committed Feb 22, 2016
2 parents d43c8cc + a7f15f5 commit 73ee45a
Show file tree
Hide file tree
Showing 35 changed files with 1,164 additions and 474 deletions.
13 changes: 12 additions & 1 deletion src/main/java/net/sf/jabref/MetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.io.*;
import java.util.*;

import net.sf.jabref.exporter.SaveActions;
import net.sf.jabref.groups.GroupTreeNode;
import net.sf.jabref.logic.labelpattern.AbstractLabelPattern;
import net.sf.jabref.logic.labelpattern.DatabaseLabelPattern;
Expand Down Expand Up @@ -166,7 +167,7 @@ public void putData(String key, List<String> orderedData) {
* There can be up to three directory definitions for these files:
* the database's metadata can specify a general directory and/or a user-specific directory
* or the preferences can specify one.
*
* <p>
* The settings are prioritized in the following order and the first defined setting is used:
* 1. metadata user-specific directory
* 2. metadata general directory
Expand Down Expand Up @@ -373,4 +374,14 @@ public void setLabelPattern(DatabaseLabelPattern labelPattern) {
this.labelPattern = labelPattern;
}

public SaveActions getSaveActions() {
if (this.getData(SaveActions.META_KEY) == null) {
return new SaveActions(false, "");
} else {
boolean enablementStatus = this.getData(SaveActions.META_KEY).get(0).equals("enabled");
String formatterString = this.getData(SaveActions.META_KEY).get(1);
return new SaveActions(enablementStatus, formatterString);
}
}

}
34 changes: 21 additions & 13 deletions src/main/java/net/sf/jabref/exporter/BibDatabaseWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import net.sf.jabref.logic.FieldChange;
import net.sf.jabref.model.entry.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -151,7 +152,8 @@ public SaveSession savePartOfDatabase(BibDatabaseContext bibDatabaseContext, Col
exceptionCause = null;
// Get our data stream. This stream writes only to a temporary file until committed.
try (VerifyingWriter writer = session.getWriter()) {
writePartOfDatabase(writer, bibDatabaseContext, entries, preferences);
List<FieldChange> saveActionChanges = writePartOfDatabase(writer, bibDatabaseContext, entries, preferences);
session.addFieldChanges(saveActionChanges);
} catch (IOException ex) {
LOGGER.error("Could not write file", ex);
session.cancel();
Expand All @@ -162,7 +164,7 @@ public SaveSession savePartOfDatabase(BibDatabaseContext bibDatabaseContext, Col

}

public void writePartOfDatabase(Writer writer, BibDatabaseContext bibDatabaseContext, Collection<BibEntry> entries,
public List<FieldChange> writePartOfDatabase(Writer writer, BibDatabaseContext bibDatabaseContext, Collection<BibEntry> entries,
SavePreferences preferences) throws IOException {
Objects.requireNonNull(writer);

Expand All @@ -183,7 +185,7 @@ public void writePartOfDatabase(Writer writer, BibDatabaseContext bibDatabaseCon
// Write database entries.
List<BibEntry> sortedEntries = BibDatabaseWriter.getSortedEntries(bibDatabaseContext,
entries.stream().map(BibEntry::getId).collect(Collectors.toSet()), preferences);
sortedEntries = BibDatabaseWriter.applySaveActions(sortedEntries, bibDatabaseContext.getMetaData());
List<FieldChange> saveActionChanges = BibDatabaseWriter.applySaveActions(sortedEntries, bibDatabaseContext.getMetaData());
BibEntryWriter bibtexEntryWriter = new BibEntryWriter(new LatexFieldFormatter(), true);
for (BibEntry entry : sortedEntries) {
exceptionCause = entry;
Expand Down Expand Up @@ -212,6 +214,8 @@ public void writePartOfDatabase(Writer writer, BibDatabaseContext bibDatabaseCon

//finally write whatever remains of the file, but at least a concluding newline
writeEpilogue(writer, bibDatabaseContext.getDatabase());

return saveActionChanges;
}

/**
Expand All @@ -224,22 +228,20 @@ public SaveSession savePartOfDatabase(BibDatabaseContext bibDatabaseContext, Sav
return savePartOfDatabase(bibDatabaseContext, entries, preferences);
}

private static List<BibEntry> applySaveActions(List<BibEntry> toChange, MetaData metaData) {
if (metaData.getData(SaveActions.META_KEY) == null) {
// save actions defined -> apply for every entry
List<BibEntry> result = new ArrayList<>(toChange.size());
private static List<FieldChange> applySaveActions(List<BibEntry> toChange, MetaData metaData) {
List<FieldChange> changes = new ArrayList<>();

SaveActions saveActions = new SaveActions(metaData);
if (metaData.getData(SaveActions.META_KEY) != null) {
// save actions defined -> apply for every entry
SaveActions saveActions = metaData.getSaveActions();

for (BibEntry entry : toChange) {
result.add(saveActions.applySaveActions(entry));
changes.addAll(saveActions.applySaveActions(entry));
}

return result;
} else {
// no save actions defined -> do nothing
return toChange;
}

return changes;
}

/**
Expand Down Expand Up @@ -278,8 +280,14 @@ private void writeMetaData(Writer out, MetaData metaData) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(Globals.NEWLINE);
stringBuilder.append(COMMENT_PREFIX + "{").append(MetaData.META_FLAG).append(key).append(":");

for (String metaItem : metaData.getData(key)) {
stringBuilder.append(StringUtil.quote(metaItem, ";", '\\')).append(";");

//in case of save actions, add an additional newline after the enabled flag
if (key.equals(SaveActions.META_KEY) && "enabled".equals(metaItem)) {
stringBuilder.append(Globals.NEWLINE);
}
}
stringBuilder.append("}");
stringBuilder.append(Globals.NEWLINE);
Expand Down
171 changes: 143 additions & 28 deletions src/main/java/net/sf/jabref/exporter/SaveActions.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,149 @@
package net.sf.jabref.exporter;

import net.sf.jabref.MetaData;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.FieldChange;
import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
import net.sf.jabref.logic.formatter.BibtexFieldFormatters;
import net.sf.jabref.logic.formatter.CaseChangers;
import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.formatter.IdentityFormatter;
import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.BibEntry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

public class SaveActions {

private final Map<String, Formatter> actions;
private final List<FieldFormatterCleanup> actions;

private List<Formatter> availableFormatters;

public static final String META_KEY = "saveActions";

public SaveActions(MetaData metaData) {
actions = new HashMap<>();
private boolean enabled;

public static final SaveActions DEFAULT_ACTIONS;

static {
String defaultFormatterString = "pages[PageNumbersFormatter]month[MonthFormatter]booktitle[SuperscriptFormatter]";
DEFAULT_ACTIONS = new SaveActions(false, defaultFormatterString);
}

public SaveActions(boolean enabled, String formatterString) {

actions = new ArrayList<>();
setAvailableFormatters();
this.enabled = enabled;

List<String> formatters = metaData.getData(META_KEY);
if(formatters==null) {
if (formatterString == null || "".equals(formatterString)) {
// no save actions defined in the meta data
return;
} else {
for (int i = 0; i < formatters.size(); i += 2) {
try {
String field = formatters.get(i);
Formatter formatter = getFormatterFromString(formatters.get(i + 1));

actions.put(field, formatter);
} catch (IndexOutOfBoundsException e) {
// the meta data string in the file is broken. -> Ignore the last item
break;
}
}
parseSaveActions(formatterString);
}

}

public boolean isEnabled() {
return enabled;
}

public List<FieldFormatterCleanup> getConfiguredActions() {
return Collections.unmodifiableList(actions);
}

public List<Formatter> getAvailableFormatters() {
return Collections.unmodifiableList(availableFormatters);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

SaveActions that = (SaveActions) o;

if (enabled != that.enabled) return false;
return actions.equals(that.actions);

}

@Override
public int hashCode() {
int result = actions.hashCode();
result = 31 * result + (enabled ? 1 : 0);
return result;
}

private void parseSaveActions(String formatterString) {
//read concrete actions
int startIndex = 0;

// first remove all newlines for easier parsing
String remainingString = formatterString;

remainingString = StringUtil.unifyLineBreaksToConfiguredLineBreaks(remainingString).replaceAll(Globals.NEWLINE, "");
try {
while (startIndex < formatterString.length()) {
// read the field name
int currentIndex = remainingString.indexOf('[');
String fieldKey = remainingString.substring(0, currentIndex);
int endIndex = remainingString.indexOf(']');
startIndex += endIndex + 1;

//read each formatter
int tokenIndex = remainingString.indexOf(',');
do {
boolean doBreak = false;
if (tokenIndex == -1 || tokenIndex > endIndex) {
tokenIndex = remainingString.indexOf(']');
doBreak = true;
}

String formatterKey = remainingString.substring(currentIndex + 1, tokenIndex);
actions.add(new FieldFormatterCleanup(fieldKey, getFormatterFromString(formatterKey)));

remainingString = remainingString.substring(tokenIndex + 1);
if (remainingString.startsWith("]") || doBreak) {
break;
}
tokenIndex = remainingString.indexOf(',');

currentIndex = -1;
} while (true);


}
} catch (StringIndexOutOfBoundsException ignore) {
// if this exception occurs, the remaining part of the save actions string is invalid.
// Thus we stop parsing and take what we have parsed until now
return;
}
}

private void setAvailableFormatters() {
availableFormatters = new ArrayList<>();

availableFormatters.addAll(BibtexFieldFormatters.ALL);
availableFormatters.addAll(CaseChangers.ALL);
}

public BibEntry applySaveActions(BibEntry entry) {
for (String key : actions.keySet()) {
Formatter formatter = actions.get(key);
public List<FieldChange> applySaveActions(BibEntry entry) {
if (enabled) {
return applyAllActions(entry);
} else {
return new ArrayList<>();
}
}

private List<FieldChange> applyAllActions(BibEntry entry) {
List<FieldChange> result = new ArrayList<>();

String fieldContent = entry.getField(key);
String formattedContent = formatter.format(fieldContent);
entry.setField(key, formattedContent);
for (FieldFormatterCleanup action : actions) {
result.addAll(action.cleanup(entry));
}

return entry;
return result;
}

private Formatter getFormatterFromString(String formatterName) {
Expand All @@ -72,4 +155,36 @@ private Formatter getFormatterFromString(String formatterName) {
return new IdentityFormatter();
}

public static String getMetaDataString(List<FieldFormatterCleanup> actionList) {
//first, group all formatters by the field for which they apply
Map<String, List<String>> groupedByField = new HashMap<>();
for (FieldFormatterCleanup cleanup : actionList) {
String key = cleanup.getField();

// add new list into the hashmap if needed
if (!groupedByField.containsKey(key)) {
groupedByField.put(key, new ArrayList<>());
}

//add the formatter to the map if it is not already there
List<String> formattersForKey = groupedByField.get(key);
if (!formattersForKey.contains(cleanup.getFormatter().getKey())) {
formattersForKey.add(cleanup.getFormatter().getKey());
}
}

// convert the contents of the hashmap into the correct serialization
StringBuilder result = new StringBuilder();
for (Map.Entry<String, List<String>> entry : groupedByField.entrySet()) {
result.append(entry.getKey());

StringJoiner joiner = new StringJoiner(",", "[", "]" + Globals.NEWLINE);
entry.getValue().forEach(joiner::add);
result.append(joiner.toString());
}

return result.toString();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset encoding)
session = databaseWriter.saveDatabase(panel.getBibDatabaseContext(), prefs);

}
panel.registerUndoableChanges(session);

} catch (UnsupportedCharsetException ex2) {
JOptionPane.showMessageDialog(frame, Localization.lang("Could not save file.") +
Expand Down
Loading

0 comments on commit 73ee45a

Please sign in to comment.