/******************************************************************************* * Copyright (c) 2011 Google, Inc and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sergey Prigogin (Google) - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.ui.util; import java.util.ArrayList; import java.util.List; import com.ibm.icu.text.BreakIterator; import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.internal.ui.text.CBreakIterator; /** * Composes names according to a particular style. A seed name is split into * words at non-alphanumeric characters and camel case boundaries. The resulting * words are capitalized according to the given capitalization style, joined * using the given delimiter and combined with the given prefix and suffix. */ public class NameComposer { private static final int CAPITALIZATION_ORIGINAL = PreferenceConstants.NAME_STYLE_CAPITALIZATION_ORIGINAL; private static final int CAPITALIZATION_UPPER_CASE = PreferenceConstants.NAME_STYLE_CAPITALIZATION_UPPER_CASE; private static final int CAPITALIZATION_LOWER_CASE = PreferenceConstants.NAME_STYLE_CAPITALIZATION_LOWER_CASE; private static final int CAPITALIZATION_CAMEL_CASE = PreferenceConstants.NAME_STYLE_CAPITALIZATION_CAMEL_CASE; private static final int CAPITALIZATION_LOWER_CAMEL_CASE = PreferenceConstants.NAME_STYLE_CAPITALIZATION_LOWER_CAMEL_CASE; private final int capitalization; private final String wordDelimiter; private final String prefix; private final String suffix; /** * Creates a name composer for a given style. * * @param capitalization capitalization transformation applied to name. Possible values: <ul> * <li>PreferenceConstants.NAME_STYLE_CAPITALIZATION_ORIGINAL,</li> * <li>PreferenceConstants.NAME_STYLE_CAPITALIZATION_UPPER_CASE,</li> * <li>PreferenceConstants.NAME_STYLE_CAPITALIZATION_LOWER_CASE,</li> * <li>PreferenceConstants.NAME_STYLE_CAPITALIZATION_CAMEL_CASE,</li> * <li>PreferenceConstants.NAME_STYLE_CAPITALIZATION_LOWER_CAMEL_CASE.</li> * </ul> * @param wordDelimiter delimiter inserted between words * @param prefix prefix prepended to the name * @param suffix suffix appended to the name */ public NameComposer(int capitalization, String wordDelimiter, String prefix, String suffix) { this.capitalization = capitalization; this.wordDelimiter = wordDelimiter; this.prefix = prefix; this.suffix = suffix; } /** * Composes a name according to the composer's style based on a seed name. * * @param seedName the name used as an inspiration * @return the composed name */ public String compose(String seedName) { List<CharSequence> words = splitIntoWords(seedName); return compose(words); } /** * Composes a name according to the composer's style based on a seed words. * * @param words the words that that should be combined to form the name * @return the composed name */ public String compose(List<CharSequence> words) { StringBuilder buf = new StringBuilder(); buf.append(prefix); for (int i = 0; i < words.size(); i++) { if (i > 0) { buf.append(wordDelimiter); } CharSequence word = words.get(i); switch (capitalization) { case CAPITALIZATION_ORIGINAL: buf.append(word); break; case CAPITALIZATION_UPPER_CASE: appendUpperCase(buf, word); break; case CAPITALIZATION_LOWER_CASE: appendLowerCase(buf, word); break; case CAPITALIZATION_CAMEL_CASE: appendTitleCase(buf, word); break; case CAPITALIZATION_LOWER_CAMEL_CASE: if (i == 0) { appendLowerCase(buf, word); } else { appendTitleCase(buf, word); } break; } } buf.append(suffix); return buf.toString(); } /** * Splits a name into words at non-alphanumeric characters and camel case boundaries. */ public List<CharSequence> splitIntoWords(CharSequence name) { List<CharSequence> words = new ArrayList<CharSequence>(); CBreakIterator iterator = new CBreakIterator(); iterator.setText(name); int end; for (int start = iterator.first(); (end = iterator.next()) != BreakIterator.DONE; start = end) { if (Character.isLetterOrDigit(name.charAt(start))) { int pos = end; while (--pos >= start && !Character.isLetterOrDigit(name.charAt(pos))) { } words.add(name.subSequence(start, pos + 1)); } } return words; } private void appendUpperCase(StringBuilder buf, CharSequence word) { for (int i = 0; i < word.length(); i++) { buf.append(Character.toUpperCase(word.charAt(i))); } } private void appendLowerCase(StringBuilder buf, CharSequence word) { for (int i = 0; i < word.length(); i++) { buf.append(Character.toLowerCase(word.charAt(i))); } } private void appendTitleCase(StringBuilder buf, CharSequence word) { for (int i = 0; i < word.length(); i++) { buf.append(i == 0 ? Character.toUpperCase(word.charAt(i)) : Character.toLowerCase(word.charAt(i))); } } /** * Returns the trimmed field name. Leading and trailing non-alphanumeric characters are trimmed. * If the first word of the name consists of a single letter and the name contains more than * one word, the first word is removed. * * @param fieldName a field name to trim * @return the trimmed field name */ public static String trimFieldName(String fieldName){ CBreakIterator iterator = new CBreakIterator(); iterator.setText(fieldName); int firstWordStart = -1; int firstWordEnd = -1; int secondWordStart = -1; int lastWordEnd = -1; int end; for (int start = iterator.first(); (end = iterator.next()) != BreakIterator.DONE; start = end) { if (Character.isLetterOrDigit(fieldName.charAt(start))) { int pos = end; while (--pos >= start && !Character.isLetterOrDigit(fieldName.charAt(pos))) { } lastWordEnd = pos + 1; if (firstWordStart < 0) { firstWordStart = start; firstWordEnd = lastWordEnd; } else if (secondWordStart < 0) { secondWordStart = start; } } } // Skip the first word if it consists of a single letter and the name contains more than // one word. if (firstWordStart >= 0 && firstWordStart + 1 == firstWordEnd && secondWordStart >= 0) { firstWordStart = secondWordStart; } if (firstWordStart < 0) { return fieldName; } else { return fieldName.substring(firstWordStart, lastWordEnd); } } }