Sitecore Workflow and Pipelines - sitecore

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.

Related

Checkbox change other checkbox statement

I need to connect some Checkboxes, so when I click one it becomes checked and other become unchecked. My code right now looks like this.
Connect in class constructor:
connect(cb_thickness1,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness1_isChecked()));
connect(cb_thickness2,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness2_isChecked()));
connect(cb_thickness3,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness3_isChecked()));
and slots
void MainWind::cb_thickness1_isChecked()
{
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
}
Code doesn't work as expected. When I click to any ChBx first time, everything is OK, but when I click to other next time it only uncheck previous and does nothing with itself. Only on second click it become chekced.
Also I found one more bug, when I check to ChBox, and then uncheck it by clicking it againg, I can check 2 ChBxes. [pic 2]
Radio button is a great idea.
But if you really want to use check box, you can explicitly set cb_thickness1 checked in cb_thickness1_isChecked(), and do the same for other two check boxes.
void MainWind::cb_thickness1_isChecked()
{
cb_thickness1->setChecked(true);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(true);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(true);
}
I suggest to derive a class from QCheckBox (lets call it CustomCheckBox) and add a signal, private slot and public slot
signal:
void enabled();
private slot:
void CustomCheckBox::checkEnable(bool state)
{
if(state)
{
emit enabled();
}
}
public slot:
void CustomCheckBox::uncheck()
{
setChecked(false);
}
In the constructor add:
connect(this,SIGNAL(toggled(bool)),this,SLOT(checkEnable(bool)));
This way you can use simple connects.
CustomCheckBox *box1 = new CustomCheckBox();
CustomCheckBox *box2 = new CustomCheckBox();
connect(box1,SIGNAL(enabled()),box2,SLOT(uncheck()));
Feel free to improve this answer. :)
Verify that the state of the button is checked in the slot and then deactivate the other checkboxes like you already did. You can use the parameter of the stateChanged method by passing it to the slots.
Here is code that works:
Variant I:
connect(ui->checkBoxA, SIGNAL(stateChanged(int)), this, SLOT(checkBoxAChanged(int)));
connect(ui->checkBoxB, SIGNAL(stateChanged(int)), this, SLOT(checkBoxBChanged(int)));
connect(ui->checkBoxC, SIGNAL(stateChanged(int)), this, SLOT(checkBoxCChanged(int)));
void MainWindow::checkBoxAChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}
Variant II:
connect(ui->checkBoxA, SIGNAL(clicked(bool)), this, SLOT(checkBoxAClicked(bool)));
connect(ui->checkBoxB, SIGNAL(clicked(bool)), this, SLOT(checkBoxBClicked(bool)));
connect(ui->checkBoxC, SIGNAL(clicked(bool)), this, SLOT(checkBoxCClicked(bool)));
void MainWindow::checkBoxAClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBClicked(bool val)
{
if (val == true) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}

JComboBox list based model

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.

Google Glass GDK CameraManager Intent

Does anyone know if when you use the GDK Cameramanager Intent to take a picture, is there a way to not show the preview or close it automatically? Capturing an image for use in app and don't want to have to tap to accept.
I probably have missed something.
Thanks,
You can try this:
Intent localIntent = new Intent("com.google.glass.action.TAKE_PICTURE_FROM_SCREEN_OFF");
localIntent.putExtra("should_finish_turn_screen_off", true);
localIntent.putExtra("should_take_picture", true);
localIntent.putExtra("screenshot_file_path", pathToFile);
startActivity(localIntent);
It will close your preview automatically after few seconds.
try this...
private void takePicture() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
String picturePath=data.getStringExtra(CameraManager.EXTRA_PICTURE_FILE_PATH);
processPictureWhenReady(picturePath);
}
super.onActivityResult(requestCode, resultCode, data);
}
private void processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it.
// Write your code here
} else {
final File parentDirectory = pictureFile.getParentFile();
FileObserver observer = new FileObserver(parentDirectory.getPath()) {
// Protect against additional pending events after CLOSE_WRITE is
// handled.
private boolean isFileWritten;
#Override
public void onEvent(int event, String path) {
if (!isFileWritten) {
// For safety, make sure that the file that was created in
// the directory is actually the one that we're expecting.
File affectedFile = new File(parentDirectory, path);
isFileWritten = (event == FileObserver.CLOSE_WRITE
&& affectedFile.equals(pictureFile));
if (isFileWritten) {
stopWatching();
// Now that the file is ready, recursively call
// processPictureWhenReady again (on the UI thread).
runOnUiThread(new Runnable() {
#Override
public void run() {
processPictureWhenReady(picturePath);
}
});
}
}
}};
observer.startWatching();
}
}

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.

Adding Row Specific context menu to an UltraWinGrid

I'm a newbie using Infragistics. I'm trying to add context menu to a specific row/column in UltraWinGrid, which I'm not able to. Looks like adding context menu to the grid is simple but adding it to a specific row/column is not straight forward. Can you please tell me how to do this?
You could add a context menu to the form or control your grid will reside in and only display it in when they right click in the grid over the rows/cells that need that menu.
Here's an example, though it's not pretty.
private void UltraGrid_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ContextMenu.Hide();
Point point = new System.Drawing.Point(e.X, e.Y);
UIElement uiElement = ((UltraGridBase) sender).DisplayLayout.UIElement.ElementFromPoint(point);
UltraGridCell cell = (UltraGridCell) uiElement.GetContext(typeof (UltraGridCell));
if (cell != null && UseThisContextMenu(cell))
{
ContextMenu.Show();
}
}
}
MouseDown does not work. Please use MouseUp.
private void UltraGrid1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
Point point = new System.Drawing.Point(e.X, e.Y);
UIElement uiElement = ((UltraGridBase)sender).DisplayLayout.UIElement.ElementFromPoint(point);
UltraGridCell cell = (UltraGridCell)uiElement.GetContext(typeof(UltraGridCell));
if (cell.Band.Index == 0)
{
if (cell.Column.Key.Equals("ColumnToShow"))
{
contextMenuStrip.Show();
}
else
{
contextMenuStrip.Hide();
}
}
}
}
}