IDEA-127205 Specify Editor Tab Width

This commit is contained in:
Vassiliy
2014-08-01 22:50:46 +04:00
parent 7df9813355
commit 8ede9e40b4
11 changed files with 150 additions and 12 deletions
@@ -72,6 +72,7 @@ public class UISettings implements PersistentStateComponent<UISettings>, Exporta
public int RECENT_FILES_LIMIT = 50;
public int CONSOLE_COMMAND_HISTORY_LIMIT = 300;
public int EDITOR_TAB_LIMIT = 10;
public int EDITOR_TAB_TITLE_LIMIT = 30;
public boolean ANIMATE_WINDOWS = true;
public int ANIMATION_SPEED = 2000; // Pixels per second
public boolean SHOW_TOOL_WINDOW_NUMBERS = true;
@@ -3,7 +3,7 @@
<grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="527"/>
<xy x="20" y="20" width="500" height="585"/>
</constraints>
<properties/>
<border type="none"/>
@@ -108,7 +108,7 @@
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="eb8d0" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="10">
<grid id="eb8d0" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="10">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -119,7 +119,7 @@
</clientProperties>
<border type="none" title-resource-bundle="messages/ApplicationBundle" title-key="group.tab.closing.policy"/>
<children>
<grid id="5a5a7" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="5a5a7" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -129,7 +129,9 @@
<children>
<component id="527a6" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
<preferred-size width="60" height="27"/>
</grid>
</constraints>
<properties>
<text resource-bundle="messages/ApplicationBundle" key="editbox.tab.limit"/>
@@ -138,19 +140,38 @@
<component id="16477" class="javax.swing.JTextField" binding="myEditorTabLimitField">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false">
<preferred-size width="30" height="-1"/>
<preferred-size width="30" height="27"/>
</grid>
</constraints>
<properties>
<text value="15"/>
</properties>
</component>
<component id="2479d" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/ApplicationBundle" key="editbox.tab.title.limit"/>
</properties>
</component>
<component id="3499c" class="javax.swing.JTextField" binding="myTabTitleLimitField">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false">
<preferred-size width="30" height="27"/>
</grid>
</constraints>
<properties>
<columns value="2"/>
<text value="30"/>
</properties>
</component>
</children>
</grid>
<grid id="9b723" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="2">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -184,7 +205,7 @@
<grid id="611cc" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="2">
<margin top="10" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -45,6 +45,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
private JCheckBox myShowCloseButtonOnCheckBox;
private JCheckBox myShowDirectoryInTabCheckBox;
private JRadioButton myActivateRightNeighbouringTabRadioButton;
private JTextField myTabTitleLimitField;
public EditorTabsConfigurable() {
myEditorTabPlacement.setModel(new DefaultComboBoxModel(new Object[]{
@@ -119,6 +120,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
myHideKnownExtensions.setSelected(uiSettings.HIDE_KNOWN_EXTENSION_IN_TABS);
myShowDirectoryInTabCheckBox.setSelected(uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES);
myEditorTabLimitField.setText(Integer.toString(uiSettings.EDITOR_TAB_LIMIT));
myTabTitleLimitField.setText(Integer.toString(uiSettings.EDITOR_TAB_TITLE_LIMIT));
myShowCloseButtonOnCheckBox.setSelected(uiSettings.SHOW_CLOSE_BUTTON);
if (uiSettings.CLOSE_NON_MODIFIED_FILES_FIRST) {
@@ -171,14 +173,29 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
uiSettings.ACTIVATE_RIGHT_EDITOR_ON_CLOSE = myActivateRightNeighbouringTabRadioButton.isSelected();
String temp = myEditorTabLimitField.getText();
if(temp.trim().length() > 0){
if (temp.trim().length() > 0) {
try {
int newEditorTabLimit = Integer.parseInt(temp);
if(newEditorTabLimit>0&&newEditorTabLimit!=uiSettings.EDITOR_TAB_LIMIT){
uiSettings.EDITOR_TAB_LIMIT=newEditorTabLimit;
if (newEditorTabLimit > 0 && newEditorTabLimit != uiSettings.EDITOR_TAB_LIMIT) {
uiSettings.EDITOR_TAB_LIMIT = newEditorTabLimit;
uiSettingsChanged = true;
}
}catch (NumberFormatException ignored){}
}
catch (NumberFormatException ignored) {
}
}
temp = myTabTitleLimitField.getText();
if (temp.trim().length() > 0) {
try {
int newTabTitleLimit = Integer.parseInt(temp);
newTabTitleLimit = Math.max(10, Math.min(100, newTabTitleLimit));
if (newTabTitleLimit != uiSettings.EDITOR_TAB_TITLE_LIMIT){
uiSettings.EDITOR_TAB_TITLE_LIMIT = newTabTitleLimit;
uiSettingsChanged = true;
}
}
catch (NumberFormatException ignored) {
}
}
if(uiSettingsChanged){
uiSettings.fireUISettingsChanged();
@@ -191,6 +208,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
boolean isModified = isModified(myCbModifiedTabsMarkedWithAsterisk, uiSettings.MARK_MODIFIED_TABS_WITH_ASTERISK);
isModified |= isModified(myShowTabsTooltipsCheckBox, uiSettings.SHOW_TABS_TOOLTIPS);
isModified |= isModified(myEditorTabLimitField, uiSettings.EDITOR_TAB_LIMIT);
isModified |= isModified(myTabTitleLimitField, uiSettings.EDITOR_TAB_TITLE_LIMIT);
int tabPlacement = ((Integer)myEditorTabPlacement.getSelectedItem()).intValue();
isModified |= tabPlacement != uiSettings.EDITOR_TAB_PLACEMENT;
isModified |= myHideKnownExtensions.isSelected() != uiSettings.HIDE_KNOWN_EXTENSION_IN_TABS;
@@ -92,6 +92,7 @@ public final class TabInfo implements Queryable, PlaceProvider<String> {
* out of its container. (IDEA-61536)
*/
private WeakReference<TabInfo> myPreviousSelection = new WeakReference<TabInfo>(null);
private boolean myTitleShortened;
public TabInfo(final JComponent component) {
myComponent = component;
@@ -392,6 +393,14 @@ public final class TabInfo implements Queryable, PlaceProvider<String> {
return myPreviousSelection.get();
}
public boolean isTitleShortened() {
return myTitleShortened;
}
public void setTitleIsShortened(boolean titleIsShortened) {
myTitleShortened = titleIsShortened;
}
public interface DragOutDelegate {
void dragOutStarted(MouseEvent mouseEvent, TabInfo info);
@@ -44,6 +44,7 @@ import java.util.List;
*/
public class JBEditorTabs extends JBTabsImpl {
public static final String TABS_ALPHABETICAL_KEY = "tabs.alphabetical";
static final String TABS_CHORTEN_TITLE_IF_NEED = "tabs.shorten.title.if.need";
private JBEditorTabsPainter myDarkPainter = new DarculaEditorTabsPainter();
private JBEditorTabsPainter myDefaultPainter = new DefaultEditorTabsPainter();
@@ -60,6 +61,13 @@ public class JBEditorTabs extends JBTabsImpl {
return super.createSingleRowLayout();
}
@Override
protected TabLabel createTabLabel(TabInfo info) {
TabLabel label = super.createTabLabel(info);
label.putClientProperty(TABS_CHORTEN_TITLE_IF_NEED, Boolean.TRUE);
return label;
}
@Override
public boolean isEditorTabs() {
return true;
@@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.tabs.JBTabsPosition;
@@ -317,6 +318,16 @@ public class TabLabel extends JPanel {
public void setText(final SimpleColoredText text) {
myInfo.setTitleIsShortened(false);
if (text != null && text.getTexts().size() == 1 && Boolean.TRUE == getClientProperty(JBEditorTabs.TABS_CHORTEN_TITLE_IF_NEED)) {
String title = text.getTexts().get(0);
if (title.length() > UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT) {
SimpleTextAttributes attributes = text.getAttributes().get(0);
text.clear();
text.append(StringUtil.getShortened(title, UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT), attributes);
myInfo.setTitleIsShortened(true);
}
}
myLabel.change(new Runnable() {
public void run() {
myLabel.clear();
@@ -277,6 +277,8 @@ public final class EditorTabbedContainer implements Disposable, CloseAction.Clos
myTabs.getTabAt(index).setTooltipText(text);
}
public boolean isTitleShortened(int index) { return myTabs.getTabAt(index).isTitleShortened(); }
public void setBackgroundColorAt(final int index, final Color color) {
myTabs.getTabAt(index).setTabColor(color);
}
@@ -464,6 +464,10 @@ public class EditorWindow {
}
}
private boolean isTitleShortenedAt(int index) {
return myTabbedPane != null && myTabbedPane.isTitleShortened(index);
}
private void setBackgroundColorAt(final int index, final Color color) {
if (myTabbedPane != null) {
myTabbedPane.setBackgroundColorAt(index, color);
@@ -908,7 +912,9 @@ public class EditorWindow {
final int index = findEditorIndex(findFileComposite(file));
if (index != -1) {
setTitleAt(index, EditorTabbedContainer.calcTabTitle(getManager().getProject(), file));
setToolTipTextAt(index, UISettings.getInstance().SHOW_TABS_TOOLTIPS ? getManager().getFileTooltipText(file) : null);
setToolTipTextAt(index, UISettings.getInstance().SHOW_TABS_TOOLTIPS || isTitleShortenedAt(index)
? getManager().getFileTooltipText(file)
: null);
}
}
@@ -360,6 +360,7 @@ label.collapse.by.default=Collapse by default:
checkbox.show.code.folding.outline=Show code folding outline
group.tab.appearance=Tab Appearance
editbox.tab.limit=Tab limit:
editbox.tab.title.limit=Tab title limit:
combobox.editor.tab.placement=Placement:
checkbox.editor.tabs.in.single.row=Show tabs in single row
checkbox.editor.tabs.show.close.button=Show "close" button on editor tabs
@@ -2658,6 +2658,56 @@ public class StringUtil extends StringUtilRt {
return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s);
}
public static String getShortened(String s, int maxWidth) {
int length = s.length();
if (isEmpty(s) || length <= maxWidth) return s;
ArrayList<String> words = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (i == length - 1) {
builder.append(ch);
words.add(builder.toString());
builder.delete(0, builder.length());
continue;
}
if (i > 0 && (ch == '/' || ch == '.' || Character.isUpperCase(ch))) {
words.add(builder.toString());
builder.delete(0, builder.length());
}
builder.append(ch);
}
int removedLength = 0;
String toPaste = "...";
int index;
while (true) {
index = Math.max(0, words.size() / 2 - 1);
String aWord = words.get(index);
words.remove(index);
if (words.size() < 2) {
int toCut = length - removedLength - maxWidth + 3;
int pos = (aWord.length() - toCut) / 2;
toPaste = aWord.substring(0, pos) + "..." + aWord.substring(pos+toCut);
break;
}
removedLength += aWord.length();
if (length - removedLength <= maxWidth - 3) {
break;
}
}
for (int i = 0; i < words.size(); i++) {
String word = words.get(i);
if (i == index || words.size() == 1) builder.append(toPaste);
builder.append(word);
}
return builder.toString().replaceAll("\\.{4,}", "...");
}
/**
* Expirable CharSequence. Very useful to control external library execution time,
* i.e. when java.util.regex.Pattern match goes out of control.
@@ -195,4 +195,15 @@ public class StringUtilTest extends TestCase {
assertEquals(Arrays.asList("\n", "\r\n", "\n", "\r\n", "\r", "\r", "aa\r", "bb\r\n", "cc\n", "\r", "dd\n", "\n", "\r\n", "\r"),
Arrays.asList(StringUtil.splitByLinesKeepSeparators("\n\r\n\n\r\n\r\raa\rbb\r\ncc\n\rdd\n\n\r\n\r")));
}
public void testShortened() {
String[] names = {"AVeryVeeryLongClassName.java", "com.test.SomeJAVAClassName.java", "strangelowercaseclassname.java"};
for (String name : names) {
for (int i = name.length() + 1; i > 15; i--) {
String shortened = StringUtil.getShortened(name, i);
assertTrue(shortened.length() <= i);
assertTrue(!shortened.contains("...."));
}
}
}
}