Exemple #1
0
  @Override
  public AbstractUndoableEdit remove(BibtexEntry[] entries) {
    if (!supportsRemove()) {
      return null;
    }

    if (entries != null && entries.length > 0) {
      NamedCompound ce = new NamedCompound(Globals.lang("remove from group"));
      boolean modified = false;
      for (BibtexEntry entry : entries) {
        if (getSearchRule().applyRule(SearchRule.NULL_QUERY, entry)) {
          String oldContent = entry.getField(searchField);
          removeMatches(entry);
          // Store undo information.
          ce.addEdit(
              new UndoableFieldChange(entry, searchField, oldContent, entry.getField(searchField)));
          modified = true;
        }
      }
      if (modified) {
        ce.end();
      }

      return modified ? ce : null;
    }

    return null;
  }
Exemple #2
0
 private void parseField(BibtexEntry entry) throws IOException {
   String key = parseTextToken().toLowerCase();
   // Util.pr("Field: _"+key+"_");
   skipWhitespace();
   consume('=');
   String content = parseFieldContent(key);
   // Now, if the field in question is set up to be fitted automatically
   // with braces around
   // capitals, we should remove those now when reading the field:
   if (Globals.prefs.putBracesAroundCapitals(key)) {
     content = Util.removeBracesAroundCapitals(content);
   }
   if (content.length() > 0) {
     if (entry.getField(key) == null) entry.setField(key, content);
     else {
       // The following hack enables the parser to deal with multiple
       // author or
       // editor lines, stringing them together instead of getting just
       // one of them.
       // Multiple author or editor lines are not allowed by the bibtex
       // format, but
       // at least one online database exports bibtex like that, making
       // it inconvenient
       // for users if JabRef didn't accept it.
       if (key.equals("author") || key.equals("editor"))
         entry.setField(key, entry.getField(key) + " and " + content);
     }
   }
 }
 public void mouseClicked(MouseEvent e) {
   if (e.isPopupTrigger()) {
     processPopupTrigger(e);
     return;
   }
   // if (e.)
   final int col = entryTable.columnAtPoint(e.getPoint()),
       row = entryTable.rowAtPoint(e.getPoint());
   if (col < PAD) {
     BibtexEntry entry = sortedEntries.get(row);
     BasePanel p = entryHome.get(entry);
     switch (col) {
       case FILE_COL:
         Object o = entry.getField(GUIGlobals.FILE_FIELD);
         if (o != null) {
           FileListTableModel tableModel = new FileListTableModel();
           tableModel.setContent((String) o);
           if (tableModel.getRowCount() == 0) return;
           FileListEntry fl = tableModel.getEntry(0);
           (new ExternalFileMenuItem(
                   frame, entry, "", fl.getLink(), null, p.metaData(), fl.getType()))
               .actionPerformed(null);
         }
         break;
       case URL_COL:
         Object link = entry.getField("url");
         try {
           if (link != null) Util.openExternalViewer(p.metaData(), (String) link, "url");
         } catch (IOException ex) {
           ex.printStackTrace();
         }
         break;
     }
   }
 }
 public Object getColumnValue(BibtexEntry entry, int column) {
   if (column < PAD) {
     Object o;
     switch (column) {
       case FILE_COL:
         o = entry.getField(GUIGlobals.FILE_FIELD);
         if (o != null) {
           FileListTableModel model = new FileListTableModel();
           model.setContent((String) o);
           fileLabel.setToolTipText(model.getToolTipHTMLRepresentation());
           if (model.getRowCount() > 0) fileLabel.setIcon(model.getEntry(0).getType().getIcon());
           return fileLabel;
         } else return null;
       case URL_COL:
         o = entry.getField("url");
         if (o != null) {
           urlLabel.setToolTipText((String) o);
           return urlLabel;
         } else return null;
       default:
         return null;
     }
   } else {
     String field = fields[column - PAD];
     if (field.equals("author") || field.equals("editor")) {
       // For name fields, tap into a MainTableFormat instance and use
       // the same name formatting as is used in the entry table:
       if (frame.basePanel() != null)
         return frame.basePanel().tableFormat.formatName(entry.getField(field));
     }
     return entry.getField(field);
   }
 }
 /**
  * updates field values according to keywords
  *
  * @param ce indicates the undo named compound. May be null
  */
 public static void syncSpecialFieldsFromKeywords(BibtexEntry be, NamedCompound ce) {
   if (be.getField("keywords") == null) {
     return;
   }
   ArrayList<String> keywordList = Util.getSeparatedKeywords(be.getField("keywords"));
   SpecialFieldsUtils.importKeywordsForField(keywordList, Priority.getInstance(), be, ce);
   SpecialFieldsUtils.importKeywordsForField(keywordList, Rank.getInstance(), be, ce);
   SpecialFieldsUtils.importKeywordsForField(keywordList, Quality.getInstance(), be, ce);
   SpecialFieldsUtils.importKeywordsForField(keywordList, Relevance.getInstance(), be, ce);
   SpecialFieldsUtils.importKeywordsForField(keywordList, ReadStatus.getInstance(), be, ce);
   SpecialFieldsUtils.importKeywordsForField(keywordList, Printed.getInstance(), be, ce);
 }
Exemple #6
0
  /**
   * Removes matches of searchString in the entry's field. This is only possible if the search
   * expression is not a regExp.
   */
  private void removeMatches(BibtexEntry entry) {
    String content = entry.getField(searchField);
    if (content == null) {
      return; // nothing to modify
    }
    StringBuffer sbOrig = new StringBuffer(content);
    StringBuffer sbLower = new StringBuffer(content.toLowerCase());
    StringBuffer haystack = caseSensitive ? sbOrig : sbLower;
    String needle = caseSensitive ? searchExpression : searchExpression.toLowerCase();
    int i;
    int j;
    int k;
    final String separator = Globals.prefs.get(JabRefPreferences.GROUP_KEYWORD_SEPARATOR);
    while ((i = haystack.indexOf(needle)) >= 0) {
      sbOrig.replace(i, i + needle.length(), "");
      sbLower.replace(i, i + needle.length(), "");
      // reduce spaces at i to 1
      j = i;
      k = i;
      while (j - 1 >= 0 && separator.indexOf(haystack.charAt(j - 1)) >= 0) {
        --j;
      }
      while (k < haystack.length() && separator.indexOf(haystack.charAt(k)) >= 0) {
        ++k;
      }
      sbOrig.replace(j, k, j >= 0 && k < sbOrig.length() ? separator : "");
      sbLower.replace(j, k, j >= 0 && k < sbOrig.length() ? separator : "");
    }

    String result = sbOrig.toString().trim();
    entry.setField(searchField, !result.isEmpty() ? result : null);
  }
Exemple #7
0
  @Override
  public AbstractUndoableEdit add(BibtexEntry[] entries) {
    if (!supportsAdd()) {
      return null;
    }
    if (entries != null && entries.length > 0) {
      NamedCompound ce = new NamedCompound(Globals.lang("add entries to group"));
      boolean modified = false;
      for (BibtexEntry entry : entries) {
        if (!getSearchRule().applyRule(SearchRule.NULL_QUERY, entry)) {
          String oldContent = entry.getField(searchField);
          String pre = Globals.prefs.get(JabRefPreferences.GROUP_KEYWORD_SEPARATOR);
          String newContent = (oldContent == null ? "" : oldContent + pre) + searchExpression;
          entry.setField(searchField, newContent);

          // Store undo information.
          ce.addEdit(new UndoableFieldChange(entry, searchField, oldContent, newContent));
          modified = true;
        }
      }
      if (modified) {
        ce.end();
      }

      return modified ? ce : null;
    }

    return null;
  }
    /**
     * If the user has signalled the opening of a context menu, the event gets redirected to this
     * method. Here we open a file link menu if the user is pointing at a file link icon. Otherwise
     * a general context menu should be shown.
     *
     * @param e The triggering mouse event.
     */
    public void processPopupTrigger(MouseEvent e) {
      BibtexEntry entry = sortedEntries.get(entryTable.rowAtPoint(e.getPoint()));
      BasePanel p = entryHome.get(entry);
      int col = entryTable.columnAtPoint(e.getPoint());
      JPopupMenu menu = new JPopupMenu();
      int count = 0;

      if (col == FILE_COL) {
        // We use a FileListTableModel to parse the field content:
        Object o = entry.getField(GUIGlobals.FILE_FIELD);
        FileListTableModel fileList = new FileListTableModel();
        fileList.setContent((String) o);
        // If there are one or more links, open the first one:
        for (int i = 0; i < fileList.getRowCount(); i++) {
          FileListEntry flEntry = fileList.getEntry(i);
          String description = flEntry.getDescription();
          if ((description == null) || (description.trim().length() == 0))
            description = flEntry.getLink();
          menu.add(
              new ExternalFileMenuItem(
                  p.frame(),
                  entry,
                  description,
                  flEntry.getLink(),
                  flEntry.getType().getIcon(),
                  p.metaData(),
                  flEntry.getType()));
          count++;
        }
      }

      if (count > 0) menu.show(entryTable, e.getX(), e.getY());
    }
Exemple #9
0
    public boolean compare(BibtexEntry entry) {
      // specification of fields to search is done in the search expression itself
      String[] searchKeys = entry.getAllFields().toArray(new String[entry.getAllFields().size()]);

      boolean noSuchField = true;
      // this loop iterates over all regular keys, then over pseudo keys like "type"
      for (int i = 0; i < searchKeys.length + 1; i++) {
        String content;
        if (i - searchKeys.length == 0) {
          // PSEUDOFIELD_TYPE
          if (!fieldPattern.matcher("entrytype").matches()) continue;
          content = entry.getType().getName();
        } else {
          String searchKey = searchKeys[i];
          if (!fieldPattern.matcher(searchKey).matches()) continue;
          content = entry.getField(searchKey);
        }
        noSuchField = false;
        if (content == null) continue; // paranoia

        if (matchInField(content)) {
          return true;
        }
      }

      return noSuchField && operator == ComparisonOperator.DOES_NOT_CONTAIN;
    }
 /**
  * Check the database to find out whether any of a set of fields are used for any of the entries.
  *
  * @param database The bib database.
  * @param fields The set of fields to look for.
  * @return true if at least one of the given fields is set in at least one entry, false otherwise.
  */
 private boolean linksFound(BibtexDatabase database, String[] fields) {
   for (BibtexEntry entry : database.getEntries()) {
     for (String field : fields) {
       if (entry.getField(field) != null) {
         return true;
       }
     }
   }
   return false;
 }
 /**
  * @param e - Field to be handled
  * @param value - may be null to state that field should be emptied
  * @param be - BibTeXEntry to be handled
  * @param ce - Filled with undo info (if necessary)
  * @param nullFieldIfValueIsTheSame - true: field is nulled if value is the same than the current
  *     value in be
  */
 public static void updateField(
     SpecialField e,
     String value,
     BibtexEntry be,
     NamedCompound ce,
     boolean nullFieldIfValueIsTheSame) {
   Util.updateField(be, e.getFieldName(), value, ce, nullFieldIfValueIsTheSame);
   // we cannot use "value" here as updateField has side effects: "nullFieldIfValueIsTheSame" nulls
   // the field if value is the same
   SpecialFieldsUtils.exportFieldToKeywords(e, be.getField(e.getFieldName()), be, ce);
 }
Exemple #12
0
 @Override
 public boolean contains(BibtexEntry entry) {
   String content = entry.getField(searchField);
   if (content == null) {
     return false;
   }
   if (regExp) {
     return pattern.matcher(content).find();
   }
   if (caseSensitive) {
     return KeywordGroup.containsWord(searchExpression, content);
   }
   return KeywordGroup.containsWord(searchExpression.toLowerCase(), content.toLowerCase());
 }
Exemple #13
0
 public static void removeDOIfromBibtexEntryField(
     BibtexEntry bes, String fieldName, NamedCompound ce) {
   String origValue = bes.getField(fieldName);
   String value = origValue;
   value = value.replaceAll(REGEXP_DOI_WITH_HTTP_PREFIX, "");
   value = value.replaceAll(REGEXP_PLAINDOI, "");
   value = value.trim();
   if (value.isEmpty()) {
     value = null;
   }
   if (!origValue.equals(value)) {
     ce.addEdit(new UndoableFieldChange(bes, fieldName, origValue, value));
     bes.setField(fieldName, value);
   }
 }
Exemple #14
0
 private void insertFields(String[] fields, BibtexEntry entry, XmlDocument xmlDocument) {
   DocumentWrapper document = new DocumentWrapper(xmlDocument);
   for (String field : fields) {
     if (entry.getField(field) != null) {
       continue;
     }
     if (field.equalsIgnoreCase("author")) {
       entry.setField(field, document.getAuthors("and"));
     }
     if (field.equalsIgnoreCase("title")) {
       entry.setField(field, document.getTitle());
     }
     if (field.equalsIgnoreCase("abstract")) {
       entry.setField(field, document.getAbstract());
     }
     if (field.equalsIgnoreCase("keywords")) {
       entry.setField(field, document.getKeyWords());
     }
     if (field.equalsIgnoreCase("doi")) {
       entry.setField(field, document.getDoi());
     }
     if (field.equalsIgnoreCase("pages")) {
       entry.setField(field, document.getPages());
     }
     if (field.equalsIgnoreCase("volume")) {
       entry.setField(field, document.getVolume());
     }
     if (field.equalsIgnoreCase("number")) {
       entry.setField(field, document.getNumber());
     }
     if (field.equalsIgnoreCase("year")) {
       entry.setField(field, document.getYear());
     }
     if (field.equalsIgnoreCase("month")) {
       entry.setField(field, document.getMonth());
     }
     if (field.equalsIgnoreCase("day")) {
       entry.setField(field, document.getDay());
     }
     if (field.equalsIgnoreCase("booktitle")) {
       entry.setField(field, document.getVenue());
     }
     if (field.equalsIgnoreCase("journal")) {
       entry.setField(field, document.getVenue());
     }
   }
 }
  @Override
  public boolean applyRule(String query, BibtexEntry bibtexEntry) {

    String searchString = query;
    if (!caseSensitive) {
      searchString = searchString.toLowerCase();
    }

    List<String> words = new SentenceAnalyzer(searchString).getWords();

    // We need match for all words:
    boolean[] matchFound = new boolean[words.size()];

    for (String field : bibtexEntry.getAllFields()) {
      Object fieldContentAsObject = bibtexEntry.getField(field);
      if (fieldContentAsObject != null) {
        String fieldContent =
            ContainBasedSearchRule.REMOVE_LATEX_COMMANDS.format(fieldContentAsObject.toString());
        if (!caseSensitive) {
          fieldContent = fieldContent.toLowerCase();
        }

        int index = 0;
        // Check if we have a match for each of the query words, ignoring
        // those words for which we already have a match:
        for (String word : words) {
          matchFound[index] = matchFound[index] || fieldContent.contains(word);

          index++;
        }
      }
    }
    for (boolean aMatchFound : matchFound) {
      if (!aMatchFound) {
        return false; // Didn't match all words.
      }
    }
    return true; // Matched all words.
  }
  private void parse(ImportInspector dialog, String text, int startIndex, int firstEntryNumber) {
    piv = startIndex;
    int entryNumber = firstEntryNumber;

    if (importBibtex) {
      // TODO: Login
      ArrayList<String> idSelected = new ArrayList<String>();
      String id;
      while ((id = parseNextEntryId(text, piv)) != null && shouldContinue) {
        idSelected.add(id);
        entryNumber++;
      }
      try {
        BibtexDatabase dbase = parseBibtexDatabase(idSelected, includeAbstract);
        Collection<BibtexEntry> items = dbase.getEntries();
        for (BibtexEntry entry : items) {
          dialog.addEntry(cleanup(entry));
          dialog.setProgress(parsed + unparseable, hits);
          parsed++;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      // for
    } else {
      BibtexEntry entry;
      while ((entry = parseNextEntry(text, piv)) != null && shouldContinue) {
        if (entry.getField("title") != null) {
          dialog.addEntry(entry);
          dialog.setProgress(parsed + unparseable, hits);
          parsed++;
        }
        entryNumber++;
      }
    }
  }
Exemple #17
0
  public void run() {

    if (!goOn) return;

    for (int i = 0; i < entries.length; i++) {

      BibtexEntry entry = entries[i];

      // Make a list of all PDFs linked from this entry:
      List<File> files = new ArrayList<File>();

      // First check the (legacy) "pdf" field:
      String pdf = entry.getField("pdf");
      String dir = panel.metaData().getFileDirectory("pdf");
      File f = Util.expandFilename(pdf, new String[] {dir, "."});
      if (f != null) files.add(f);

      // Then check the "file" field:
      dir = panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD);
      String field = entry.getField(GUIGlobals.FILE_FIELD);
      if (field != null) {
        FileListTableModel tm = new FileListTableModel();
        tm.setContent(field);
        for (int j = 0; j < tm.getRowCount(); j++) {
          FileListEntry flEntry = tm.getEntry(j);
          if ((flEntry.getType() != null)
              && (flEntry.getType().getName().toLowerCase().equals("pdf"))) {
            f = Util.expandFilename(flEntry.getLink(), new String[] {dir, "."});
            if (f != null) files.add(f);
          }
        }
      }

      optDiag.progressArea.append(entry.getCiteKey() + "\n");

      if (files.size() == 0) {
        skipped++;
        optDiag.progressArea.append("  " + Globals.lang("Skipped - No PDF linked") + ".\n");
      } else
        for (File file : files) {
          if (!file.exists()) {
            skipped++;
            optDiag.progressArea.append(
                "  " + Globals.lang("Skipped - PDF does not exist") + ":\n");
            optDiag.progressArea.append("    " + file.getPath() + "\n");

          } else {
            try {
              XMPUtil.writeXMP(file, entry, database);
              optDiag.progressArea.append("  " + Globals.lang("Ok") + ".\n");
              entriesChanged++;
            } catch (Exception e) {
              optDiag.progressArea.append(
                  "  " + Globals.lang("Error while writing") + " '" + file.getPath() + "':\n");
              optDiag.progressArea.append("    " + e.getLocalizedMessage() + "\n");
              errors++;
            }
          }
        }

      if (optDiag.canceled) {
        optDiag.progressArea.append("\n" + Globals.lang("Operation canceled.\n"));
        break;
      }
    }
    optDiag.progressArea.append(
        "\n"
            + Globals.lang(
                "Finished writing XMP for %0 file (%1 skipped, %2 errors).",
                String.valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors)));
    optDiag.done();
  }
 private static void exportFieldToKeywords(SpecialField e, BibtexEntry be, NamedCompound ce) {
   SpecialFieldsUtils.exportFieldToKeywords(e, be.getField(e.getFieldName()), be, ce);
 }
  private BibtexEntry cleanup(BibtexEntry entry) {
    if (entry == null) {
      return null;
    }

    // clean up title
    String title = entry.getField("title");
    if (title != null) {
      // USe the alt-text and replace image links
      title = title.replaceAll("[ ]?img src=[^ ]+ alt=\"([^\"]+)\">[ ]?", "\\$$1\\$");
      // Try to sort out most of the /spl / conversions
      // Deal with this specific nested type first
      title = title.replaceAll("/sub /spl infin//", "\\$_\\\\infty\\$");
      title = title.replaceAll("/sup /spl infin//", "\\$\\^\\\\infty\\$");
      // Replace general expressions
      title = title.replaceAll("/[sS]pl ([^/]+)/", "\\$\\\\$1\\$");
      // Deal with subscripts and superscripts
      if (Globals.prefs.getBoolean(JabRefPreferences.USE_CONVERT_TO_EQUATION)) {
        title = title.replaceAll("/sup ([^/]+)/", "\\$\\^\\{$1\\}\\$");
        title = title.replaceAll("/sub ([^/]+)/", "\\$_\\{$1\\}\\$");
        title = title.replaceAll("\\(sup\\)([^(]+)\\(/sup\\)", "\\$\\^\\{$1\\}\\$");
        title = title.replaceAll("\\(sub\\)([^(]+)\\(/sub\\)", "\\_\\{$1\\}\\$");
      } else {
        title = title.replaceAll("/sup ([^/]+)/", "\\\\textsuperscript\\{$1\\}");
        title = title.replaceAll("/sub ([^/]+)/", "\\\\textsubscript\\{$1\\}");
        title = title.replaceAll("\\(sup\\)([^(]+)\\(/sup\\)", "\\\\textsuperscript\\{$1\\}");
        title = title.replaceAll("\\(sub\\)([^(]+)\\(/sub\\)", "\\\\textsubscript\\{$1\\}");
      }

      // Replace \infin with \infty
      title = title.replaceAll("\\\\infin", "\\\\infty");

      // Unit formatting
      if (Globals.prefs.getBoolean(JabRefPreferences.USE_UNIT_FORMATTER_ON_SEARCH)) {
        title = unitFormatter.format(title);
      }

      // Automatic case keeping
      if (Globals.prefs.getBoolean(JabRefPreferences.USE_CASE_KEEPER_ON_SEARCH)) {
        title = caseKeeper.format(title);
      }
      // Write back
      entry.setField("title", title);
    }

    // clean up author
    /*   	String author = (String)entry.getField("author");
       	if (author != null) {
        if (author.indexOf("a href=") >= 0) {  // Author parsing failed because it was empty
    	entry.setField("author","");  // Maybe not needed anymore due to another change
        } else {
        	author = author.replaceAll("\\s+", " ");
        	author = author.replaceAll("\\.", ". ");
        	author = author.replaceAll("([^;]+),([^;]+),([^;]+)","$1,$3,$2"); // Change order in case of Jr. etc
        	author = author.replaceAll("  ", " ");
        	author = author.replaceAll("\\. -", ".-");
                   author = author.replaceAll("; ", " and ");
        	author = author.replaceAll(" ,", ",");
        	author = author.replaceAll("  ", " ");
        	author = author.replaceAll("[ ,;]+$", "");
        	entry.setField("author", author);
        }
    }*/
    // clean up month
    String month = entry.getField("month");
    if (month != null && !month.isEmpty()) {
      month = month.replaceAll("\\.", "");
      month = month.toLowerCase();

      Pattern monthPattern = Pattern.compile("(\\d*+)\\s*([a-z]*+)-*(\\d*+)\\s*([a-z]*+)");
      Matcher mm = monthPattern.matcher(month);
      String date = month;
      if (mm.find()) {
        if (mm.group(3).isEmpty()) {
          if (!mm.group(2).isEmpty()) {
            date = "#" + mm.group(2).substring(0, 3) + "#";
            if (!mm.group(1).isEmpty()) {
              date += " " + mm.group(1) + ",";
            }
          } else {
            date = mm.group(1) + ",";
          }
        } else if (mm.group(2).isEmpty()) {
          if (!mm.group(4).isEmpty()) {
            date =
                "#" + mm.group(4).substring(0, 3) + "# " + mm.group(1) + "--" + mm.group(3) + ",";
          } else {
            date += ",";
          }
        } else {
          date =
              "#"
                  + mm.group(2).substring(0, 3)
                  + "# "
                  + mm.group(1)
                  + "--#"
                  + mm.group(4).substring(0, 3)
                  + "# "
                  + mm.group(3)
                  + ",";
        }
      }
      // date = date.trim();
      // if (!date.isEmpty()) {
      entry.setField("month", date);
      // }
    }

    // clean up pages
    String field = "pages";
    String pages = entry.getField(field);
    if (pages != null) {
      String[] pageNumbers = pages.split("-");
      if (pageNumbers.length == 2) {
        if (pageNumbers[0].equals(pageNumbers[1])) { // single page
          entry.setField(field, pageNumbers[0]);
        } else {
          entry.setField(field, pages.replaceAll("-", "--"));
        }
      }
    }

    // clean up publication field
    BibtexEntryType type = entry.getType();
    String sourceField = "";
    if (type.getName().equals("Article")) {
      sourceField = "journal";
      entry.clearField("booktitle");
    } else if (type.getName().equals("Inproceedings")) {
      sourceField = "booktitle";
    }
    String fullName = entry.getField(sourceField);
    if (fullName != null) {
      if (type.getName().equals("Article")) {
        int ind = fullName.indexOf(": Accepted for future publication");
        if (ind > 0) {
          fullName = fullName.substring(0, ind);
          entry.setField("year", "to be published");
          entry.clearField("month");
          entry.clearField("pages");
          entry.clearField("number");
        }
        String[] parts = fullName.split("[\\[\\]]"); // [see also...], [legacy...]
        fullName = parts[0];
        if (parts.length == 3) {
          fullName += parts[2];
        }
        if (entry.getField("note").equals("Early Access")) {
          entry.setField("year", "to be published");
          entry.clearField("month");
          entry.clearField("pages");
          entry.clearField("number");
        }
      } else {
        fullName =
            fullName
                .replace("Conference Proceedings", "Proceedings")
                .replace("Proceedings of", "Proceedings")
                .replace("Proceedings.", "Proceedings");
        fullName = fullName.replaceAll("International", "Int.");
        fullName = fullName.replaceAll("Symposium", "Symp.");
        fullName = fullName.replaceAll("Conference", "Conf.");
        fullName = fullName.replaceAll(" on", " ").replace("  ", " ");
      }

      Matcher m1 = publicationPattern.matcher(fullName);
      String abrvPattern = ".*[^,] '?\\d+\\)?";
      if (m1.find()) {
        String prefix = m1.group(2).trim();
        String postfix = m1.group(1).trim();
        String abrv = "";
        String[] parts = prefix.split("\\. ", 2);
        if (parts.length == 2) {
          if (parts[0].matches(abrvPattern)) {
            prefix = parts[1];
            abrv = parts[0];
          } else {
            prefix = parts[0];
            abrv = parts[1];
          }
        }
        if (!prefix.matches(abrvPattern)) {
          fullName = prefix + " " + postfix + " " + abrv;
          fullName = fullName.trim();
        } else {
          fullName = postfix + " " + prefix;
        }
      }
      if (type.getName().equals("Article")) {
        fullName = fullName.replace(" - ", "-"); // IEE Proceedings-

        fullName = fullName.trim();
        if (Globals.prefs.getBoolean(JabRefPreferences.USE_IEEE_ABRV)) {
          fullName = Globals.journalAbbrev.getMedlineAbbreviation(fullName).orElse(fullName);
        }
      }
      if (type.getName().equals("Inproceedings")) {
        Matcher m2 = proceedingPattern.matcher(fullName);
        if (m2.find()) {
          String prefix = m2.group(2);
          String postfix = m2.group(1).replaceAll("\\.$", "");
          if (!prefix.matches(abrvPattern)) {
            String abrv = "";

            String[] parts = postfix.split("\\. ", 2);
            if (parts.length == 2) {
              if (parts[0].matches(abrvPattern)) {
                postfix = parts[1];
                abrv = parts[0];
              } else {
                postfix = parts[0];
                abrv = parts[1];
              }
            }
            fullName = prefix.trim() + " " + postfix.trim() + " " + abrv;

          } else {
            fullName = postfix.trim() + " " + prefix.trim();
          }
        }

        fullName = fullName.trim();

        fullName =
            fullName.replaceAll("^[tT]he ", "").replaceAll("^\\d{4} ", "").replaceAll("[,.]$", "");
        String year = entry.getField("year");
        fullName = fullName.replaceAll(", " + year + "\\.?", "");

        if (!fullName.contains("Abstract")
            && !fullName.contains("Summaries")
            && !fullName.contains("Conference Record")) {
          fullName = "Proc. " + fullName;
        }
      }
      entry.setField(sourceField, fullName);
    }

    // clean up abstract
    String abstr = entry.getField("abstract");
    if (abstr != null) {
      // Try to sort out most of the /spl / conversions
      // Deal with this specific nested type first
      abstr = abstr.replaceAll("/sub /spl infin//", "\\$_\\\\infty\\$");
      abstr = abstr.replaceAll("/sup /spl infin//", "\\$\\^\\\\infty\\$");
      // Replace general expressions
      abstr = abstr.replaceAll("/[sS]pl ([^/]+)/", "\\$\\\\$1\\$");
      // Deal with subscripts and superscripts
      if (Globals.prefs.getBoolean(JabRefPreferences.USE_CONVERT_TO_EQUATION)) {
        abstr = abstr.replaceAll("/sup ([^/]+)/", "\\$\\^\\{$1\\}\\$");
        abstr = abstr.replaceAll("/sub ([^/]+)/", "\\$_\\{$1\\}\\$");
        abstr = abstr.replaceAll("\\(sup\\)([^(]+)\\(/sup\\)", "\\$\\^\\{$1\\}\\$");
        abstr = abstr.replaceAll("\\(sub\\)([^(]+)\\(/sub\\)", "\\_\\{$1\\}\\$");
      } else {
        abstr = abstr.replaceAll("/sup ([^/]+)/", "\\\\textsuperscript\\{$1\\}");
        abstr = abstr.replaceAll("/sub ([^/]+)/", "\\\\textsubscript\\{$1\\}");
        abstr = abstr.replaceAll("\\(sup\\)([^(]+)\\(/sup\\)", "\\\\textsuperscript\\{$1\\}");
        abstr = abstr.replaceAll("\\(sub\\)([^(]+)\\(/sub\\)", "\\\\textsubscript\\{$1\\}");
      }
      // Replace \infin with \infty
      abstr = abstr.replaceAll("\\\\infin", "\\\\infty");
      // Write back
      entry.setField("abstract", abstr);
    }

    // Clean up url
    String url = entry.getField("url");
    if (url != null) {
      entry.setField("url", "http://ieeexplore.ieee.org" + url.replace("tp=&", ""));
    }
    return entry;
  }
  private BibtexEntry parseNextEntry(String allText, int startIndex) {
    BibtexEntry entry = null;

    int index = allText.indexOf("<div class=\"detail", piv);
    int endIndex = allText.indexOf("</div>", index);

    if (index >= 0 && endIndex > 0) {
      endIndex += 6;
      piv = endIndex;
      String text = allText.substring(index, endIndex);

      BibtexEntryType type = null;
      String sourceField = null;

      String typeName = "";
      Matcher typeMatcher = typePattern.matcher(text);
      if (typeMatcher.find()) {
        typeName = typeMatcher.group(1);
        if (typeName.equalsIgnoreCase("IEEE Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("IEEE Early Access Articles")
            || typeName.equalsIgnoreCase("IET Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("AIP Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("AVS Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("IBM Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("TUP Journals &amp; Magazines")
            || typeName.equalsIgnoreCase("BIAI Journals &amp; Magazines")) {
          type = BibtexEntryType.getType("article");
          sourceField = "journal";
        } else if (typeName.equalsIgnoreCase("IEEE Conference Publications")
            || typeName.equalsIgnoreCase("IET Conference Publications")
            || typeName.equalsIgnoreCase("VDE Conference Publications")) {
          type = BibtexEntryType.getType("inproceedings");
          sourceField = "booktitle";
        } else if (typeName.equalsIgnoreCase("IEEE Standards")
            || typeName.equalsIgnoreCase("Standards")) {
          type = BibtexEntryType.getType("standard");
          sourceField = "number";
        } else if (typeName.equalsIgnoreCase("IEEE eLearning Library Courses")) {
          type = BibtexEntryType.getType("Electronic");
          sourceField = "note";
        } else if (typeName.equalsIgnoreCase("Wiley-IEEE Press eBook Chapters")
            || typeName.equalsIgnoreCase("MIT Press eBook Chapters")
            || typeName.equalsIgnoreCase("IEEE USA Books &amp; eBooks")) {
          type = BibtexEntryType.getType("inCollection");
          sourceField = "booktitle";
        }
      }

      if (type == null) {
        type = BibtexEntryType.getType("misc");
        sourceField = "note";
        System.err.println("Type detection failed. Use MISC instead.");
        unparseable++;
        System.err.println(text);
      }

      entry = new BibtexEntry(IdGenerator.next(), type);

      if (typeName.equalsIgnoreCase("IEEE Standards")) {
        entry.setField("organization", "IEEE");
      }

      if (typeName.equalsIgnoreCase("Wiley-IEEE Press eBook Chapters")) {
        entry.setField("publisher", "Wiley-IEEE Press");
      } else if (typeName.equalsIgnoreCase("MIT Press eBook Chapters")) {
        entry.setField("publisher", "MIT Press");
      } else if (typeName.equalsIgnoreCase("IEEE USA Books &amp; eBooks")) {
        entry.setField("publisher", "IEEE USA");
      }

      if (typeName.equalsIgnoreCase("IEEE Early Access Articles")) {
        entry.setField("note", "Early Access");
      }

      Set<String> fields = fieldPatterns.keySet();
      for (String field : fields) {
        Matcher fieldMatcher = Pattern.compile(fieldPatterns.get(field)).matcher(text);
        if (fieldMatcher.find()) {
          entry.setField(field, htmlConverter.format(fieldMatcher.group(1)));
          if (field.equals("title") && fieldMatcher.find()) {
            String sec_title = htmlConverter.format(fieldMatcher.group(1));
            if (entry.getType() == BibtexEntryType.getStandardType("standard")) {
              sec_title = sec_title.replaceAll("IEEE Std ", "");
            }
            entry.setField(sourceField, sec_title);
          }
          if (field.equals("pages") && fieldMatcher.groupCount() == 2) {
            entry.setField(field, fieldMatcher.group(1) + "-" + fieldMatcher.group(2));
          }
        }
      }

      Matcher authorMatcher = authorPattern.matcher(text);
      // System.out.println(text);
      StringBuilder authorNames = new StringBuilder("");
      int authorCount = 0;
      while (authorMatcher.find()) {
        if (authorCount >= 1) {
          authorNames.append(" and ");
        }
        authorNames.append(htmlConverter.format(authorMatcher.group(1)));
        // System.out.println(authorCount + ": " + authorMatcher.group(1));
        authorCount++;
      }
      entry.setField("author", authorNames.toString());
      if (entry.getField("author") == null
          || entry.getField("author").startsWith("a href")
          || entry
              .getField("author")
              .startsWith("Topic(s)")) { // Fix for some documents without authors
        entry.setField("author", "");
      }
      if (entry.getType() == BibtexEntryType.getStandardType("inproceedings")
          && entry.getField("author").equals("")) {
        entry.setType(BibtexEntryType.getStandardType("proceedings"));
      }

      if (includeAbstract) {
        index = text.indexOf("id=\"abstract");
        if (index >= 0) {
          endIndex = text.indexOf("</div>", index) + 6;

          text = text.substring(index, endIndex);
          Matcher absMatcher = absPattern.matcher(text);
          if (absMatcher.find()) {
            // Clean-up abstract
            String abstr = absMatcher.group(1);
            abstr = abstr.replaceAll("<span class='snippet'>([\\w]+)</span>", "$1");

            entry.setField("abstract", htmlConverter.format(abstr));
          }
        }
      }
    }

    if (entry == null) {
      return null;
    } else {
      return cleanup(entry);
    }
  }