/*
* Copyright (c) 2015, MGrossmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the jo-widgets.org nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.jowidgets.spi.impl.swt.common.widgets.base;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Composite;
import org.jowidgets.common.types.EllipsisMode;
import org.jowidgets.util.Assert;
public final class JoCLabel extends CLabel {
private static final String ELLIPSIS = "...";
private static final int DRAW_FLAGS = SWT.DRAW_MNEMONIC | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT | SWT.DRAW_DELIMITER;
private final EllipsisMode ellipsisMode;
public JoCLabel(final Composite parent, final int style, final EllipsisMode ellipsis) {
super(parent, style);
Assert.paramNotNull(ellipsis, "ellipseMode");
this.ellipsisMode = ellipsis;
}
@Override
protected String shortenText(final GC gc, final String t, final int width) {
if (EllipsisMode.LEFT.equals(ellipsisMode)) {
return shortenTextLeft(gc, t, width);
}
else if (EllipsisMode.RIGHT.equals(ellipsisMode)) {
return shortenTextRight(gc, t, width);
}
else if (EllipsisMode.CENTER.equals(ellipsisMode)) {
return shortenTextCenter(gc, t, width);
}
else {
throw new IllegalStateException("The ellipse mode '" + ellipsisMode + "' is not supported");
}
}
private String shortenTextLeft(final GC gc, final String text, final int width) {
if (text == null) {
return null;
}
final int ellipseWidth = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
if (width <= ellipseWidth) {
return ELLIPSIS;
}
else if ((gc.textExtent(text, DRAW_FLAGS)).x <= width) {
return text;
}
final int length = text.length();
for (int index = 0; index < text.length(); index++) {
final String substring = text.substring(index, length);
final int subWidth = gc.textExtent(substring, DRAW_FLAGS).x;
if (ellipseWidth + subWidth <= width) {
return ELLIPSIS + substring;
}
}
return ELLIPSIS;
}
private String shortenTextRight(final GC gc, final String text, final int width) {
if (text == null) {
return null;
}
final int ellipseWidth = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
if (width <= ellipseWidth) {
return ELLIPSIS;
}
else if ((gc.textExtent(text, DRAW_FLAGS)).x <= width) {
return text;
}
final int length = text.length();
for (int index = 0; index < text.length(); index++) {
final String substring = text.substring(0, length - index);
final int subWidth = gc.textExtent(substring, DRAW_FLAGS).x;
if (subWidth + ellipseWidth <= width) {
return substring + ELLIPSIS;
}
}
return ELLIPSIS;
}
private String shortenTextCenter(final GC gc, final String text, final int width) {
if (text == null) {
return null;
}
final int ellipseWidth = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
if (width <= ellipseWidth) {
return ELLIPSIS;
}
else if ((gc.textExtent(text, DRAW_FLAGS)).x <= width) {
return text;
}
final int l = text.length();
int max = l / 2;
int min = 0;
int mid = (max + min) / 2 - 1;
if (mid <= 0) {
return ELLIPSIS;
}
final TextLayout layout = new TextLayout(getDisplay());
layout.setText(text);
mid = calculateOffset(layout, mid);
while (min < mid && mid < max) {
final String s1 = text.substring(0, mid);
final String s2 = text.substring(calculateOffset(layout, l - mid), l);
final int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
final int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
if (l1 + ellipseWidth + l2 > width) {
max = mid;
mid = calculateOffset(layout, (max + min) / 2);
}
else if (l1 + ellipseWidth + l2 < width) {
min = mid;
mid = calculateOffset(layout, (max + min) / 2);
}
else {
min = max;
}
}
final String result = mid == 0 ? ELLIPSIS : text.substring(0, mid)
+ ELLIPSIS
+ text.substring(calculateOffset(layout, l - mid), l);
layout.dispose();
return result;
}
int calculateOffset(final TextLayout layout, final int offset) {
final int nextOffset = layout.getNextOffset(offset, SWT.MOVEMENT_CLUSTER);
if (nextOffset != offset) {
return layout.getPreviousOffset(nextOffset, SWT.MOVEMENT_CLUSTER);
}
return offset;
}
}