JComboBox list based model - list

In my program I use couple JComboBoxes with a simple list combo box model:
public class ListComboBoxModel<T> extends AbstractListModel implements ComboBoxModel {
protected List<T> list;
private T selection;
public ListComboBoxModel(List<T> list) {
this.list = list;
this.selection = getDefaultSelection();
}
protected T getDefaultSelection() {
if (list.size() > 0) {
return list.get(0);
} else {
return null;
}
}
#Override
public Object getSelectedItem() {
return selection;
}
#Override
public void setSelectedItem(Object anItem) {
selection = (T) anItem;
}
#Override
public int getSize() {
return list.size();
}
#Override
public T getElementAt(int index) {
return list.get(index);
}
}
And the problem is that when I add elements to the list that combobox is using it doesn't work as intended anymore. If I click on combo box, the list has correct length but all elements in there are empty so the list is all white. When I roll over an element it doesn't highlight. When I click anywhere in the list it always works as if I selected the recently added element. If I reduce list size back to original or even decrease it, combo box works as it should have.
To edit the lists that combo boxes use, I use JTables and the add method I implemented in their models.
public void add(T element) {
list.add(element);
fireTableDataChanged();
}
Any ideas how can I fix that?

Well if anyone were interested I solved problem by adding
fireContentsChanged(this, 0, getSize());
in a method that gets called when by table/list gets changed anywhere in the program using observer pattern.

Related

how to decouple complex Qt widget classes

I have lots of custom Qt widgets that have their own layouts and contain lists of even more widgets.
I ended up having a ManagerWidget that controls everything (including listening to all events) and propagating them to the widget that needs to update its content. It seems there are too many methods that just pass the information along.
Is there a better way of doing this? Connecting the classes through signal/slots doesn't really work in this case because there's a map of them and I wouldn't know which one was fired.
Would the Mediator pattern fit in this case?
class ManagerWidget : public QWidget {
public:
map<ID, MainWidgetContainer*> mainWidgetMap;
RecordsContainer *recentRecords; // This widget can contain any number of widgets, each showing a record
// events are caught here and propagated to the widgets
void AddNewEntry(ID id) {
MainWidgetContainer *w = new MainWidgetContainer(id);
mainWidgetMap.insert(id, w);
}
void UpdatePictureWidget(ID id) {
mainWidgetMap.value(id)->UpdatePictureWidget();
}
void AddXItem(ID id, Type1 k) {
if(id == 0)
recentRecords->AddXItem(k);
else
mainWidgetMap.value(id)->AddXItem(k);
}
void UpdateEntry(ID id, string newName) { }
};
class MainWidgetContainer : public QWidget {
public:
NameWidget *name;
PictureWidget *pic;
RecordsContainer *records; // This widget can contain any number of widgets, each showing a record
MainWidgetContainer(ID id) {
name = new NameWidget(id);
records = new RecordsContainer();
pic = new PictureWidget();
// setup layout and add items to records as they come in later
}
AddXItem(Type1 k) { records->AddXItem(k); }
UpdatePictureWidget() { pic->Update(); }
};
class RecordsContainer : public QWidget {
public:
map<Type1, Item*> itemMap;
AddXItem(Type1 k) {
Item *item = new Item(k);
itemMap.insert(k, item);
mainLayout->addWidget(item);
}
AddYItem(Type2 k);
// etc
};

JavaFX - using toggle isSelected() in conditional statements

I'm building a simple sketch program using JavaFX. I want the user to be able to switch between drawing a rectangle, circle or line and I've put toggle radio buttons in the menu for these options.
Is it possible to write an if/else statement so I can write code for three different functions depending on which is selected? At the moment it will only draw lines. This is part of my code so far (sorry it's messy):
package Sketchbook;
public class Sketchbook extends Application {
final static int CANVAS_WIDTH = 800;
final static int CANVAS_HEIGHT = 600;
ColorPicker colorPicker1;
ColorPicker colorPicker2;
#Override
public void start(final Stage primaryStage) {
final Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
final GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
initDraw(graphicsContext);
canvas.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
graphicsContext.beginPath();
graphicsContext.moveTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
}
});
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
graphicsContext.lineTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
}
});
canvas.addEventHandler(MouseEvent.MOUSE_RELEASED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
}
});
Group root = new Group();
ToggleGroup toggleGroup = new ToggleGroup();
RadioButton rectangle = new RadioButton("Rectangle");
RadioButton circle = new RadioButton("Circle");
RadioButton line = new RadioButton("Line");
rectangle.setSelected(true);
rectangle.setToggleGroup(toggleGroup);
circle.setToggleGroup(toggleGroup);
line.setToggleGroup(toggleGroup);
You've pretty much already described what you need to do:
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
if (toggleGroup.getSelectedToggle() == line) {
graphicsContext.lineTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
} else if (toggleGroup.getSelectedToggle() == rectangle) {
// etc...
} // etc...
}
}
});
Obviously you may need to reorder the code a little to make sure variables are declared and initialized before you use them.

Repaining listfield on editfield change Input

I am using Google place API in my application for searching location. When user input text in edit field then the API called and resulted output will shown in a list.
I implemented it successfully but the problem is that each time edit field text changes, the list is not repainting and output is added to the end of the list. I want every time the text changes in the edit text field, the list must remove its previous content that are invalid.
This can be seen in pictures:
For Implementing this, I have written this code:
public final class MyScreen extends MainScreen {
/**
* Creates a new MyScreen object
*/
private Vector _listElements;
ListField list;
JSONObject[] jsonobject;
EditField editfield;
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=";
String[] locationName;
VerticalFieldManager verticalFieldManager = new VerticalFieldManager();
public MyScreen() {
ButtonField search = new ButtonField("Search");
_listElements = new Vector();
list = new ListField();
ListCallback _callback = new ListCallback(this);
// Set the displayed title of the screen
setTitle("Search Edit Field");
editfield = new EditField();
editfield.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
list.invalidate();
createField();
}
});
}
});
list.setCallback(_callback);
add(editfield);
add(new SeparatorField());
verticalFieldManager.add(list);
add(verticalFieldManager);
}
protected void createField() {
ShowList();
reloadList();
}
private void reloadList() {
list.setSize(_listElements.size());
}
class ListCallback implements ListFieldCallback {
MyScreen listDemoScreen;
public ListCallback(MyScreen listDemoScreen) {
this.listDemoScreen = listDemoScreen;
}
public void drawListRow(ListField list, Graphics g, int index, int y,
int w) {
String text = (String) _listElements.elementAt(index);
list.setRowHeight(getFont().getHeight());
g.drawText(text, 0, y, 0, -1);
}
public Object get(ListField list, int index) {
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string) {
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list) {
return Display.getWidth();
}
}
protected void ShowList() {
HttpConnection httpConn;
InputStream in;
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
String response;
String fieldText = editfield.getText();
connDesc = connFact.getConnection(url + fieldText
+ "%#&sensor=true&key=xxxxxxxxxxxxx"
+ ConnectionType.getConnectionType());
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
try {
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
in = httpConn.openInputStream();
StringBuffer buf = new StringBuffer();
int read = -1;
while ((read = in.read()) != -1)
buf.append((char) read);
response = buf.toString();
try {
JSONObject object = new JSONObject(response);
JSONArray ar = object.getJSONArray("predictions");
jsonobject = new JSONObject[ar.length()];
locationName = new String[ar.length()];
list.invalidate();
for (int i = 0; i < ar.length(); i++) {
jsonobject[i] = ar.getJSONObject(i);
_listElements.addElement(jsonobject[i]
.getString("description"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
Dialog.alert("Connection not succeded");
}
}
protected boolean onSavePrompt() {
return true;
}
}
Update and Solution:
only modify this and this rest is working fine. As Peter Suggests, we can also put a Thread.sleep(time); in order to get the UI not blocked:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listElements.removeAllElements();
createField();
}
});
I think your problem is simply that you do not clear the _listElements Vector when you request more data. So _listElements just gets bigger.
However there is a bigger problem here and that is that your code appears to be running networking operations on the Event Thread. What your should do in your changeListener. is start a Thread that requests the data, then repopulate the ListField when this tread gets data.
As a result of this change, the UI will not be blocked, and the List updates will become asynchronous, so your user could in fact enter another character into the EditField before the first Thread response comes back. To prevent this looking silly, you could delay the Thread processing for a fraction of second to see if another character is entered, and/or you could make sure that the EditField content was still the same as the requested characters before you repopulate it.
I personally prefer this asynchronous approach, but if it bothers you, you could put a 'please wait - loading' type screen to block the user until the response comes back.
Update
Remember that if you start a background Thread, you need to get back onto the Event Thread to do Ui Processing. Typically this is done simply by including your UI code within the run method of a Runnable that is invoked later, for example:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// Ui Code in here
}
});
You should only put Ui Updating code in the runnable. Networking processing, or any other blocking action, should NOT be included.

LWUIT List works terribly slow

I've faced with the well-known problem in LWUIT. My list component with the checkbox renderer scrolls very slow. If to test my application on emulator it runs quite smoothly (nevertheless I see CPU utilization splashes up to 60% during scroll action), but if to run it on mobile phone it takes a couple of seconds between focus movements.
There's a code of renderer:
public class CheckBoxMultiselectRenderer extends CheckBox implements ListCellRenderer {
public CheckBoxMultiselectRenderer() {
super("");
}
//override
public void repaint() {
}
public Component getListCellRendererComponent(List list, Object value,
int index,boolean isSelected) {
Location loc = (Location)value;
setText(loc.getLocationName());
setFocus(isSelected);
setSelected(loc.isSelected());
return this;
}
public Component getListFocusComponent(List list) {
setText("");
setFocus(true);
getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
return this;
}
}
that's the code of my form containing the list:
protected void createMarkup() {
Form form = getForm();
form.setLayout(new BorderLayout());
form.setScrollable(false);
Label title = new Label("Choose location zone:");
title.getStyle().setMargin(5, 5, 0, 0);
title.getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
title.setAlignment(Component.CENTER);
form.addComponent(BorderLayout.NORTH, title);
list = new List(StateKeeper.getLocationsAsList());
list.setFixedSelection(List.FIXED_NONE_CYCLIC);
// list.setSmoothScrolling(true);
list.getStyle().setBgTransparency(0);
list.setListCellRenderer(new CheckBoxMultiselectRenderer());
list.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
// List l = (List)ae.getSource();
// l.requestFocus();
// l.setHandlesInput(true);
Location selItem = (Location)list.getSelectedItem();
selItem.setSelected(!selItem.isSelected());
}
});
form.addComponent(BorderLayout.CENTER, list);
}
I would be very thankful for any help!
We must be so carefull building lwuit List. If we have made something wrong they can work worse than expected. I recommend you to take a look on this
LWUIT Blog ListRender
You can also rewrite your paint method. You list's speed will be increased.

Sitecore Workflow and Pipelines

I'm trying to implement a basic Javascript confirmation box on a workflow command (e.g. "are you sure you want to edit this?"). Depending on whether a users clicks yes or no, I want to move to a different state in the workflow. Here is the code I currently have (some logic is taken out):
[Serializable]
public class ConfirmAction
{
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result != "yes")
{
args.AbortPipeline();
return;
}
}
else
{
Sitecore.Context.ClientPage.ClientResponse.Confirm("Are you sure you want to edit this?");
args.WaitForPostBack();
}
}
}
I'm new to the Pipeline model, especially in relation to Sitecore, so I'm somewhat grasping at straws. The problem that I'm having, I believe, is that I don't have a way of getting the result back to the Workflow Pipeline, from the ClientResponse pipeline, to tell it what to do.
Thank you.
EDIT:
Using Yan's information, I eventually came up with the following solution:
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
clientArgs.Parameters.Add("itemID", currentItem.ID.ToString());
clientArgs.Parameters.Add("stateID", currentItem.Fields["__Workflow state"].Value);
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result != "yes")
{
Item currentItem = Sitecore.Configuration.Factory.GetDatabase("master").GetItem(args.Parameters["itemID"]);
currentItem.Editing.BeginEdit();
currentItem.Fields["__Workflow state"].Value = args.Parameters["stateID"];
currentItem.Editing.EndEdit();
return;
}
SheerResponse.Eval("window.location.reload();");
}
else
{
Sitecore.Context.ClientPage.ClientResponse.YesNoCancel("Are you sure you want to edit this?", "200", "200");
args.WaitForPostBack();
}
}
Well, I think this is where you can take advantage from ClientPipelineArgs. Let's say you add the current item ID to the parameters to pass:
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
clientArgs.Parameters.Add("id", currentItem.ID.ToString());
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
and later on when you get positive result you get it back and move to the target workflow state (explained in comments):
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result == "yes")
{
// 1. take item ID from args.Parameters["id"];
// 2. get item by this ID
// 3. move item to target workflow state
}
}
else
{
Sitecore.Context.ClientPage.ClientResponse.Confirm("Are you sure you want to edit this?");
args.WaitForPostBack();
}
}
This might require some minor changes (I didn't run it myself before posting), but hope you get the idea.