/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui;
import java.lang.ref.*;
import malik.emulator.media.graphics.RasterCanvas;
public class Alert extends Container
{
private static final class ComputeScrollBarsEvent extends WeakReference
implements Runnable
{
ComputeScrollBarsEvent(Alert thisScreen)
{
super(thisScreen);
}
public void run()
{
Alert thisScreen;
if((thisScreen = (Alert) get()) == null)
{
return;
}
thisScreen.computeScrollBars(thisScreen.getClientWidth());
}
}
private static final class ChangeIndicatorEvent extends Object
implements Runnable
{
private Displayable screen;
private Item oldIndicator;
private Item newIndicator;
ChangeIndicatorEvent(Displayable screen, Item oldIndicator, Item newIndicator)
{
this.screen = screen;
this.oldIndicator = oldIndicator;
this.newIndicator = newIndicator;
}
public void run()
{
Item indicator;
if(!screen.isReallyShown())
{
return;
}
if((indicator = oldIndicator) != null)
{
indicator.setVisible(false);
try
{
indicator.onHide();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
if((indicator = newIndicator) != null)
{
indicator.setVisible(true);
try
{
indicator.onShow();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
}
}
public static final int FOREVER = -2;
public static final Command DISMISS_COMMAND;
private static final Font FONT;
static
{
DISMISS_COMMAND = new Command("Закрыть", Command.OK, Integer.MIN_VALUE);
FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL);
}
private boolean stayComputeScrollBars;
private boolean hasCommandListener;
private String text;
private Image icon;
private AlertType type;
private Gauge indicator;
private Runnable computeScrollBarsEvent;
private TextOutputMultilined lines;
public Alert(String title)
{
this(false, title, null, null, null, null, null, null, null, null);
}
public Alert(String title, String text, Image icon, AlertType type)
{
this(false, title, null, null, null, null, text, icon, type, null);
}
public Alert(String title, Ticker ticker,
Command[] commands, Command dismissCommand, CommandListener listener,
String text, Image icon, AlertType type, Gauge indicator)
{
this(true, title, ticker, commands, dismissCommand, listener, text, icon, type, indicator);
}
private Alert(boolean system, String title, Ticker ticker,
Command[] commands, Command dismissCommand, CommandListener listener,
String text, Image icon, AlertType type, Gauge indicator)
{
super(system, title, ticker, commands,
dismissCommand == null && (commands == null || commands.length <= 0) ?
DISMISS_COMMAND : dismissCommand, listener, VERTICAL);
int error;
TextOutputMultilined lines;
if(indicator != null)
{
error = 0;
synchronized(getOwningLock())
{
label0:
{
if(indicator.getOwner() != null)
{
error = 1;
break label0;
}
if(!indicator.isMatchForAlert())
{
error = 2;
break label0;
}
indicator.setOwner(this);
}
}
switch(error)
{
case 1:
throw new IllegalStateException("Alert: " +
"индикатор уже принадлежит контейнеру.");
case 2:
throw new IllegalArgumentException("Alert: " +
"индикатор не соответствует требованиям " +
"для размещения его на диалоговом экране.");
}
}
this.hasCommandListener = listener != null;
this.icon = icon != null ? Image.createImage(icon) : null;
this.text = text;
this.type = type;
this.indicator = indicator;
this.computeScrollBarsEvent = new ComputeScrollBarsEvent(this);
this.lines = lines = new TextOutputMultilinedExt(0);
lines.setText(text);
}
public void addCommand(Command command)
{
if(command == DISMISS_COMMAND)
{
return;
}
super.removeCommand(DISMISS_COMMAND);
super.addCommand(command);
}
public void removeCommand(Command command)
{
boolean needAddDismissCommand;
CommandEnumeration enumeration;
if(command == DISMISS_COMMAND)
{
return;
}
super.removeCommand(command);
synchronized((enumeration = getCommands()).getMonitor())
{
needAddDismissCommand =
enumeration.getCommandsCount() == 0 &&
enumeration.getDefaultCommand() == null;
}
if(needAddDismissCommand)
{
super.addCommand(DISMISS_COMMAND);
}
}
public void setCommandListener(CommandListener listener)
{
this.hasCommandListener = listener != null;
super.setCommandListener(listener);
}
public void setTimeout(int timeout)
{
if(timeout <= 0 && timeout != FOREVER)
{
throw new IllegalArgumentException("Alert.setTimeout: " +
"недопустимое значение параметра timeout.");
}
}
public void setType(AlertType type)
{
synchronized(lines)
{
this.type = type;
callSeriallyComputeScrollBars();
callSeriallyPaintScreen(CLIENT);
}
}
public void setImage(Image icon)
{
synchronized(lines)
{
this.icon = icon != null ? Image.createImage(icon) : null;
callSeriallyComputeScrollBars();
callSeriallyPaintScreen(CLIENT);
}
}
public void setIndicator(Gauge indicator)
{
int error;
Gauge oldIndicator;
error = 0;
synchronized(lines)
{
label0:
{
oldIndicator = this.indicator;
synchronized(getOwningLock())
{
label1:
{
if(indicator != null)
{
if(indicator.getOwner() != null)
{
error = 1;
break label1;
}
if(!indicator.isMatchForAlert())
{
error = 2;
break label1;
}
indicator.setOwner(this);
}
if(oldIndicator != null)
{
oldIndicator.setOwner(null);
}
}
}
if(error != 0)
{
break label0;
}
this.indicator = indicator;
callSeriallyComputeScrollBars();
callSerially(new ChangeIndicatorEvent(this, oldIndicator, indicator));
callSeriallyPaintScreen(CLIENT);
}
}
switch(error)
{
case 1:
throw new IllegalStateException("Alert.setIndicator: " +
"индикатор уже принадлежит контейнеру.");
case 2:
throw new IllegalArgumentException("Alert.setIndicator: " +
"индикатор не соответствует требованиям " +
"для размещения его на диалоговом экране.");
}
}
public void setString(String text)
{
TextOutputMultilined lines;
synchronized(lines = this.lines)
{
lines.setText(text);
this.text = text;
callSeriallyComputeScrollBars();
callSeriallyPaintScreen(CLIENT);
}
}
public int getDefaultTimeout()
{
return FOREVER;
}
public int getTimeout()
{
return FOREVER;
}
public AlertType getType()
{
return type;
}
public Image getImage()
{
return icon;
}
public Gauge getIndicator()
{
return indicator;
}
public String getString()
{
return text;
}
void paint(GraphicsClipRestricted render, ScrollBar horzScrollBar, ScrollBar vertScrollBar)
{
int l;
int t;
int s;
int h;
int ih;
int tx;
int ty;
int ct;
int cb;
int i;
int len;
char[] chars;
Image icon;
Item indicator;
TextOutputMultilined lines;
render.setFont(FONT);
render.setColor(RasterCanvas.getSystemColor(0x28));
synchronized(lines = this.lines)
{
l = 0;
s = FONT.getHeight();
h = getClientHeight();
ih = 0;
tx = horzScrollBar.getPosition();
ty = vertScrollBar.getPosition();
cb = (ct = render.getClipY()) + render.getClipHeight();
if((indicator = this.indicator) != null)
{
ih = indicator.getHeight();
h -= ih;
cb -= ih;
}
if((icon = getOutputIcon()) != null)
{
render.drawStretchRegion(icon, 0, 0, icon.getWidth(), icon.getHeight(), 0,
tx, ((ct + cb) / 2), 48, 48, Graphics.LEFT | Graphics.VCENTER);
l = 50;
}
l += tx;
len = lines.getLinesCount();
chars = lines.getChars();
t = (Math.max(h, vertScrollBar.getRange() - ih) - (s * len)) / 2;
for(i = 0; i < len; t += s, i++)
{
if(t < cb && t + s > ct)
{
render.drawChars(chars,
lines.getLineStart(i), lines.getLineLength(i), l, t, 0);
}
}
if(indicator != null)
{
render.translate(tx, ty + h);
render.restrictClipRect(0, 0, indicator.getWidth(), ih);
indicator.onPaint(render);
}
}
}
void onShow()
{
Item indicator;
AlertType type;
super.onShow();
if((type = this.type) != null && type.isSystem())
{
type.playSound(MIDletProxy.getInstance().getEmulatorScreen());
}
if((indicator = this.indicator) != null)
{
indicator.setVisible(true);
try
{
indicator.onShow();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
}
void onHide()
{
Item indicator;
if((indicator = this.indicator) != null)
{
indicator.setVisible(false);
try
{
indicator.onHide();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
super.onHide();
}
void onSizeChanged(int width, int height)
{
computeScrollBars(width);
super.onSizeChanged(width, height);
}
void onKeyPressed(int key, int charCode)
{
MIDletProxy proxy = MIDletProxy.getInstance();
if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_UP))
{
scroll(0, -getVertScrollBar().getPage() / 4);
return;
}
if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_DOWN))
{
scroll(0, getVertScrollBar().getPage() / 4);
return;
}
super.onKeyPressed(key, charCode);
}
void onCommandAction(Command command)
{
Display display;
if((!hasCommandListener) && command == DISMISS_COMMAND)
{
(display = MIDletProxy.getInstance().getEmulatorScreen()).setCurrent(
display.getScreenAfterAlert());
return;
}
super.onCommandAction(command);
}
void notifyPlaceItems()
{
}
final void setCurrent(Item item, Display display)
{
throw new IllegalStateException("Display.setCurrentItem: " +
"постановка фокуса ввода невозможна - " +
"заданный элемент находится на диалоговом экране.");
}
private void computeScrollBars(int containerClientWidth)
{
int iconWidth;
int indHeight;
Item indicator;
TextOutputMultilined lines;
synchronized(lines = this.lines)
{
stayComputeScrollBars = false;
iconWidth = getOutputIcon() != null ? 50 : 0;
indHeight = 0;
if((indicator = this.indicator) != null)
{
indicator.computeSizes(containerClientWidth);
indHeight = indicator.getHeight();
}
lines.split(FONT, containerClientWidth - iconWidth);
getVertScrollBar().setRange(FONT.getHeight() * lines.getLinesCount() + indHeight);
}
}
private void callSeriallyComputeScrollBars()
{
if(stayComputeScrollBars)
{
return;
}
stayComputeScrollBars = true;
callSerially(computeScrollBarsEvent);
}
private Image getOutputIcon()
{
Image icon;
AlertType type;
return (icon = this.icon) != null ? icon :
((type = this.type) != null ? type.getIcon() : null);
}
}