package org.gphoto2;
import static org.gphoto2.GPhotoException.check;
import java.io.Closeable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.AbstractList;
import java.util.Calendar;
import java.util.List;
import java.util.WeakHashMap;
import org.gphoto2.jna.Gphoto2Library;
import org.gphoto2.jna.Gphoto2Library.CameraWidgetCallback;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.FloatByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
public abstract class CameraWidget implements Closeable {
public enum Type {
Window,
Section,
Text,
Range,
Toggle,
Radio,
Menu,
Button,
Date
}
protected static WeakHashMap<Pointer, CameraWidget> widgetsByNativePointer =
new WeakHashMap<Pointer, CameraWidget>();
protected Pointer nativePointer;
protected CameraWidget(Type type, String label) {
PointerByReference ptrWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_new(type.ordinal(), label, ptrWidget));
this.nativePointer = ptrWidget.getValue();
synchronized (widgetsByNativePointer) {
widgetsByNativePointer.put(nativePointer, this);
}
}
protected CameraWidget(Pointer widget) {
this.nativePointer = widget;
synchronized (widgetsByNativePointer) {
widgetsByNativePointer.put(nativePointer, this);
}
}
protected static CameraWidget getByNativePointer(Pointer nativePointer) {
synchronized (widgetsByNativePointer) {
CameraWidget widget = widgetsByNativePointer.get(nativePointer);
if (widget != null) {
return widget;
} else if (nativePointer == null || nativePointer.equals(Pointer.NULL)) {
return null;
} else {
IntByReference ptrInt = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_type(nativePointer, ptrInt));
Type type = Type.values()[ptrInt.getValue()];
switch (type) {
case Window:
return new WindowWidget(nativePointer);
case Section:
return new SectionWidget(nativePointer);
case Text:
return new TextWidget(nativePointer);
case Range:
return new RangeWidget(nativePointer);
case Toggle:
return new ToggleWidget(nativePointer);
case Radio:
return new RadioWidget(nativePointer);
case Menu:
return new MenuWidget(nativePointer);
case Button:
return new ButtonWidget(nativePointer);
case Date:
return new DateWidget(nativePointer);
default:
throw new IllegalArgumentException("Unsupported Widget type: " + type);
}
}
}
}
protected Pointer getNativePointer() {
if (nativePointer == null) {
throw new IllegalStateException("closed");
} else {
return nativePointer;
}
}
@Override
public void close() {
if (nativePointer != null) {
//Close children recursively
if (this instanceof ContainerWidget) {
for (CameraWidget child : ((ContainerWidget)this).getChildren()) {
child.close();
}
}
//Only use gp_widget_free() on the root node
if (getParent() == null) {
check(Gphoto2Library.INSTANCE.gp_widget_free(nativePointer));
}
synchronized (widgetsByNativePointer) {
widgetsByNativePointer.remove(nativePointer);
nativePointer = null;
}
}
}
@Override
protected void finalize() throws Throwable {
close();
super.finalize();
}
public CameraWidget getParent() {
PointerByReference ptrParentWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_parent(getNativePointer(), ptrParentWidget));
return getByNativePointer(ptrParentWidget.getValue());
}
public CameraWidget getRoot() {
PointerByReference ptrParentWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_root(getNativePointer(), ptrParentWidget));
return getByNativePointer(ptrParentWidget.getValue());
}
public String getName() {
PointerByReference ptrString = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_name(getNativePointer(), ptrString));
return ptrString.getValue().getString(0);
}
public void setName(String name) {
check(Gphoto2Library.INSTANCE.gp_widget_set_name(getNativePointer(), name));
}
public String getInfo() {
PointerByReference ptrString = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_info(getNativePointer(), ptrString));
return ptrString.getValue().getString(0);
}
public void setInfo(String name) {
check(Gphoto2Library.INSTANCE.gp_widget_set_info(getNativePointer(), name));
}
public int getId() {
IntByReference ptrInt = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_id(getNativePointer(), ptrInt));
return ptrInt.getValue();
}
public String getLabel() {
PointerByReference ptrString = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_label(getNativePointer(), ptrString));
return ptrString.getValue().getString(0);
}
public Type getType() {
IntByReference ptrInt = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_type(getNativePointer(), ptrInt));
return Type.values()[ptrInt.getValue()];
}
public void setChanged(boolean changed) {
check(Gphoto2Library.INSTANCE.gp_widget_set_changed(getNativePointer(), changed ? 1 : 0));
}
public boolean changed() {
return check(Gphoto2Library.INSTANCE.gp_widget_changed(getNativePointer())) != 0;
}
public void setReadOnly(boolean readonly) {
check(Gphoto2Library.INSTANCE.gp_widget_set_readonly(getNativePointer(), readonly ? 1 : 0));
}
public boolean isReadOnly() {
IntByReference ptrInt = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_readonly(getNativePointer(), ptrInt));
return ptrInt.getValue() != 0;
}
@Override
public String toString() {
return toString("");
}
public String toString(String ident) {
String ret = ident + " " + getType() + " 0x" + Integer.toHexString(getId()) + " " + getLabel();
String name = getName();
if (!name.isEmpty()) {
ret += " (" + name + ")";
}
return ret;
}
public abstract static class ContainerWidget extends CameraWidget {
List<CameraWidget> children = new ChildrenList();
protected ContainerWidget(Pointer pointer) {
super(pointer);
}
protected ContainerWidget(Type type, String label) {
super(type, label);
}
public List<CameraWidget> getChildren() {
return children;
}
public CameraWidget getChildById(int id) {
PointerByReference ptrChildWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_child_by_id(getNativePointer(), id, ptrChildWidget));
return getByNativePointer(ptrChildWidget.getValue());
}
public CameraWidget getChildByName(String name) {
PointerByReference ptrChildWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_child_by_name(getNativePointer(), name, ptrChildWidget));
return getByNativePointer(ptrChildWidget.getValue());
}
public CameraWidget getChildByLabel(String label) {
PointerByReference ptrChildWidget = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_child_by_label(getNativePointer(), label, ptrChildWidget));
return getByNativePointer(ptrChildWidget.getValue());
}
@Override
public String toString(String ident) {
String ret = super.toString(ident);
for (CameraWidget child : getChildren()) {
ret += "\n" + child.toString(ident + " ");
}
return ret;
}
}
public static class WindowWidget extends ContainerWidget {
protected WindowWidget(Pointer pointer) {
super(pointer);
}
protected WindowWidget(String label) {
super(Type.Window, label);
}
}
public static class SectionWidget extends ContainerWidget {
protected SectionWidget(Pointer pointer) {
super(pointer);
}
protected SectionWidget(String label) {
super(Type.Section, label);
}
}
public static class TextWidget extends CameraWidget {
protected TextWidget(Pointer pointer) {
super(pointer);
}
protected TextWidget(String label) {
super(Type.Text, label);
}
public String getValue() {
PointerByReference ptrValue = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
return ptrValue.getValue().getString(0);
}
public void setValue(String value) {
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), value));
}
@Override
public String toString(String ident) {
return super.toString(ident) + " = " + getValue();
}
}
public static class RangeWidget extends CameraWidget {
protected RangeWidget(Pointer pointer) {
super(pointer);
}
protected RangeWidget(String label) {
super(Type.Range, label);
}
public float getValue() {
FloatByReference ptrValue = new FloatByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
return ptrValue.getValue();
}
public void setValue(float value) {
FloatByReference ptrValue = new FloatByReference(value);
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), ptrValue));
}
/**
* @return [min, max, increment]
*/
public float[] getRange() {
FloatByReference min = new FloatByReference();
FloatByReference max = new FloatByReference();
FloatByReference inc = new FloatByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_range(getNativePointer(), min, max, inc));
return new float[] {min.getValue(), max.getValue(), inc.getValue()};
}
public void setRange(float min, float max, float increment) {
check(Gphoto2Library.INSTANCE.gp_widget_set_range(getNativePointer(), min, max, increment));
}
public float getMin() {
return getRange()[0];
}
public float getMax() {
return getRange()[1];
}
public float getIncrement() {
return getRange()[2];
}
public void setMin(float min) {
float[] range = getRange();
setRange(min, range[1], range[2]);
}
public void setMax(float max) {
float[] range = getRange();
setRange(range[0], max, range[2]);
}
public void setIncrement(float increment) {
float[] range = getRange();
setRange(range[0], range[1], increment);
}
@Override
public String toString(String ident) {
float[] range = getRange();
return super.toString(ident) + " = " + getValue() +
" (Range=[" + range[0] + ".." + range[1] + "], increment=" + range[2] + ")";
}
}
public static class ToggleWidget extends CameraWidget {
protected ToggleWidget(Pointer pointer) {
super(pointer);
}
protected ToggleWidget(String label) {
super(Type.Toggle, label);
}
public boolean getValue() {
IntByReference ptrValue = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
return ptrValue.getValue() != 0;
}
public void setValue(boolean value) {
IntByReference ptrValue = new IntByReference(value ? 1 : 0);
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), ptrValue));
}
@Override
public String toString(String ident) {
return super.toString(ident) + " = " + getValue();
}
}
public static abstract class ChoiceWidget extends CameraWidget {
List<String> choices = new ChoiceList();
protected ChoiceWidget(Pointer pointer) {
super(pointer);
}
protected ChoiceWidget(Type type, String label) {
super(type, label);
}
public List<String> getChoices() {
return choices;
}
public String getValue() {
PointerByReference ptrValue = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
return ptrValue.getValue().getString(0);
}
public void setValue(String value) {
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), value));
}
@Override
public String toString(String ident) {
return super.toString(ident) + " = " + getValue() + " (Choices=" + getChoices() + ")";
}
}
public static class RadioWidget extends ChoiceWidget {
protected RadioWidget(Pointer pointer) {
super(pointer);
}
protected RadioWidget(String label) {
super(Type.Radio, label);
}
}
public static class MenuWidget extends ChoiceWidget {
protected MenuWidget(Pointer pointer) {
super(pointer);
}
protected MenuWidget(String label) {
super(Type.Radio, label);
}
}
public static class ButtonWidget extends CameraWidget {
protected ButtonWidget(Pointer pointer) {
super(pointer);
}
protected ButtonWidget(String label) {
super(Type.Button, label);
}
public void click(Camera camera, Context context) {
getCallback().apply(
camera.getNativePointer(),
getNativePointer(),
Context.cContext(context));
}
public CameraWidgetCallback getCallback() {
PointerByReference ptrValue = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
//FIXME: Convert pointer to Callback
return null;
}
public void setCallback(CameraWidgetCallback value) {
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), value));
}
}
public static class DateWidget extends CameraWidget {
protected DateWidget(Pointer pointer) {
super(pointer);
}
protected DateWidget(String label) {
super(Type.Date, label);
}
public Calendar getValue() {
IntByReference ptrValue = new IntByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_value(getNativePointer(), ptrValue));
Calendar ret = Calendar.getInstance();
ret.setTimeInMillis(ptrValue.getValue() * 1000L);
return ret;
}
public void setValue(Calendar value) {
IntByReference ptrValue = new IntByReference((int)(value.getTimeInMillis() / 1000L));
check(Gphoto2Library.INSTANCE.gp_widget_set_value(getNativePointer(), ptrValue));
}
@Override
public String toString(String ident) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
return super.toString(ident) + " = " + df.format(getValue().getTime());
}
}
protected class ChildrenList extends AbstractList<CameraWidget> {
@Override
public int size() {
return check(Gphoto2Library.INSTANCE.gp_widget_count_children(getNativePointer()));
}
@Override
public CameraWidget get(int index) {
PointerByReference ptrChild = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_child(getNativePointer(), index, ptrChild));
return getByNativePointer(ptrChild.getValue());
}
@Override
public void add(int index, CameraWidget element) {
if (index == 0) {
check(Gphoto2Library.INSTANCE.gp_widget_prepend(getNativePointer(), element.getNativePointer()));
} else if (index == size()) {
check(Gphoto2Library.INSTANCE.gp_widget_append(getNativePointer(), element.getNativePointer()));
} else {
throw new UnsupportedOperationException("Can only add to the beginning or to the end of the list");
}
}
}
protected class ChoiceList extends AbstractList<String> {
@Override
public int size() {
return check(Gphoto2Library.INSTANCE.gp_widget_count_choices(getNativePointer()));
}
@Override
public String get(int index) {
PointerByReference ptrChoice = new PointerByReference();
check(Gphoto2Library.INSTANCE.gp_widget_get_choice(getNativePointer(), index, ptrChoice));
return ptrChoice.getValue().getString(0);
}
@Override
public void add(int index, String element) {
if (index == size()) {
check(Gphoto2Library.INSTANCE.gp_widget_add_choice(getNativePointer(), element));
} else {
throw new UnsupportedOperationException("Can only add to the the end of the list");
}
}
}
}