I want to create a Qooxdoo application that consists of a Desktop with multiple Windows. The Desktop (and not each Window) also has a (common) ToolBar.
Now I want to have a command to "save" the document of the active window. This command can be triggered by the keyboard shortcut "Ctrl+S" as well as a button on the toolbar.
To handle the "Ctrl+S" to reach the currently active window the qx.ui.command.GroupManager (as described by https://qooxdoo.org/documentation/v7.5/#/desktop/gui/interaction?id=working-with-commands and https://qooxdoo.org/qxl.demobrowser/#ui~CommandGroupManager.html) is supposed to be the best solution. And I could easily implement that in my code.
But now I'm struggling to make the toolbar save button also call the save command of the currently active window as I don't know how to bind it correctly to the GroupManager.
An example code to get started in the playground https://qooxdoo.org/qxl.playground/:
// NOTE: run this script only once. Before running it again you need to reload
// the page as it seems that the commands are accumulation and not reset.
// I guess that this is a bug in the Playground
const root = this.getRoot();
qx.Class.define('test.Application',
{
extend : qx.application.Standalone,
members: {
main: function() {
const layout = new qx.ui.layout.VBox(5);
const container = new qx.ui.container.Composite(layout);
root.add(container, {edge: 0});
const windowManager = new qx.ui.window.Manager();
const desktop = new qx.ui.window.Desktop(windowManager);
this._manager = new qx.ui.command.GroupManager();
const menuBar = new qx.ui.menubar.MenuBar();
let menu = new qx.ui.menu.Menu();
///////////////////////////
// TODO: Call _doSave() of the active window!
let saveMenuButton = new qx.ui.menu.Button('Save','#MaterialIcons/save/16');
///////////////////////////
menu.add(saveMenuButton);
var fileMenu = new qx.ui.menubar.Button('File', null, menu);
menuBar.add(fileMenu);
const toolBar = new qx.ui.toolbar.ToolBar();
///////////////////////////
// TODO: Call _doSave() of the active window!
let saveToolBarButton = new qx.ui.toolbar.Button('Save','#MaterialIcons/save/16');
///////////////////////////
toolBar.add(saveToolBarButton);
container.add(menuBar,{flex:0});
container.add(toolBar,{flex:0});
container.add(desktop,{flex:1});
this._foo1 = new test.Window('foo1', this);
desktop.add(this._foo1);
this._foo1.open();
this._foo1.moveTo(100,20);
this._foo2 = new test.Window('foo2', this);
desktop.add(this._foo2);
this._foo2.open();
this._foo2.moveTo(200,100);
this._foo3 = new test.Window('foo3', this);
desktop.add(this._foo3);
this._foo3.open();
this._foo3.moveTo(300,180);
},
getGroupManager() {
return this._manager;
}
}
});
qx.Class.define('test.Window', {
extend: qx.ui.window.Window,
construct(windowName, controller) {
this.base(arguments, windowName);
this._name = windowName;
let commandGroup = new qx.ui.command.Group();
const cmd = new qx.ui.command.Command("Ctrl+S");
cmd.addListener('execute', this._doSave, this);
commandGroup.add('save', cmd);
controller.getGroupManager().add(commandGroup);
this.addListener('changeActive', () => {
if (this.isActive()) {
controller.getGroupManager().setActive(commandGroup);
}
}, this);
},
members: {
_doSave() {
alert("save " + this._name);
}
}
});
a = new test.Application();
How should the saveMenuButton.setCommand() and saveToolBarButton.setCommand() should look like to always call the command of the active window?
You can control a current active window via Desktop class:
let saveToolBarButton = new qx.ui.toolbar.Button('Save');
saveToolBarButton.addListener("click", function(){
desktop.getActiveWindow()._doSave();
}, this);
Would be great for your solution imo is to create a separate command and add this command to buttons:
const saveActiveWindowCommand = new qx.ui.command.Command();
saveActiveWindowCommand.addListener("execute", function(){
desktop.getActiveWindow()._doSave();
}, this);
let saveMenuButton = new qx.ui.menu.Button('Save');
saveMenuButton.setCommand(saveActiveWindowCommand);
let saveToolBarButton = new qx.ui.toolbar.Button('Save');
saveToolBarButton.setCommand(saveActiveWindowCommand);
EDIT:
You could set commands dynamically for "Main Panel" menu buttons. Because there is only one instance of command pressing "Ctrl+S" will trigger only one command but maybe you would like that main bar save buttons have extra logic.
You have in application class next method which will be called from window class when changeActive event happens.
setSaveCommand(command){
this.saveMenuButton.setCommand(command);
this.saveToolBarButton.setCommand(command);
},
and in your Window class:
if (this.isActive()) {
controller.setSaveCommand(cmd);
controller.getGroupManager().setActive(commandGroup);
}
Related
I am working with standalone (not mobile) and I think it is _getScroll method for reaching it.
how to implement it here qooxdoo selectbox example
I found similar for mobile implementing virtual scrolling list console.log says container._getScroll is not a function.
The idea is to get scrollbar from a widget, the scrollbar you are needed is NativeScrollbar of the widget qx.ui.list.List. Then add event handler for a "scroll" event. In handler u have to compare current position of scroll and maximum.
Try the code below (eg copy and paste into the Qooxdoo playground).
qx.Class.define("SelectBoxWithScrollEndEvent", {
extend: qx.ui.form.SelectBox,
construct: function(){
this.base(arguments);
this.__setupScroll();
},
events: {
"scrollEndHappened": "qx.event.type.Event"
},
members: {
__setupScroll: function(){
const list = this.getChildControl("list");
const scrollbar = list.getChildControl("scrollbar-y");
scrollbar.addListener("scroll", function(e){
if (scrollbar.getMaximum() === scrollbar.getPosition()){
this.fireEvent("scrollEndHappened");
}}, this);
}
}
});
const box = new SelectBoxWithScrollEndEvent();
const data = new qx.data.Array([1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]);
const controller = new qx.data.controller.List(data, box);
box.addListener("scrollEndHappened", function(){
alert("SCROLL HAPPENED ALERT");
}, this);
this.getRoot().add(box);
From my angularjs application I open a new window:
$window.open($state.href('catalog-detalleTicketMapa', {
id: $localStorage.idRamdom
}), 'window', 'height=700,width=700');
And when I close that new window I want the parent window to know about that event, and I do the following
// controller auxiliary window
vm.onExit = function () {
$rootScope.$broadcast('ventanaCerrada');
};
$window.onbeforeunload = vm.onExit;
// controller main windows
$scope.$on('ventanaCerrada', function () {
$rootScope.ventanaAbierta = false;
});
If it enters the event $rootScope.$broadcast but not to the event scope.$on.
I have also tested with localStorage, but it is only updated in the auxiliary window, but the main one does not.
How can I share a variable between two open windows at the same time in my browser?
When you open a new window with $window.open, it won't share the scope with the calling window, so it's impossible (afaik) to broadcast anything between them with angular. But the calling window can access global variables in the opened window, so I'm using something like an observer to watch that variable.
I have the following code in a WindowService to open the new window (we only open a single window; if you need more, you need to adjust the code):
angular.module('myproject')
.service('WindowService', ['$window', '$interval', '$timeout',
function ($window, $interval, $timeout) {
var self = this;
this.myOpenWindow = null;
// opens a window and starts the wait-function
this.openWindow = function (url, callbackFn) {
// open the window
self.myOpenWindow = $window.open(url);
// Puts focus on the new window
if (window.focus) {
self.myOpenWindow.focus();
}
// check for response in opened window
self.waitForResponse(callbackFn);
};
this.waitStarted = false;
this.waitForResponse = function (callbackFn) {
if (!self.waitStarted && self.myOpenWindow) {
self.waitStarted = true;
var intervalPeriod = 1000; // check once every second
var waitHandler;
waitHandler = $interval(function (index) {
if (self.myOpenWindow.closed) {
// window was closed, commence cleaning operation
$interval.cancel(waitHandler);
waitHandler = $timeout(function () {
// re-initialize waitStarted so it can be used again
self.waitStarted = false;
// call callback-Function when the window is closed
if (callbackFn) {
callbackFn();
}
}, intervalPeriod);
} else {
// window is still open, check if the observed variable is set
if (self.myOpenWindow && self.myOpenWindow.response_message) {
var message = self.myOpenWindow.response_message;
// do what you want with the message
// ...
// afterwards close the window (or whatever)
if (self.myOpenWindow) {
self.myOpenWindow.close();
}
}
}
}, intervalPeriod);
}
};
}
]);
In the opened window you need to set that global variable somewhere, e.g. like this:
window['response_message'] = { 'result': 'Done' };
Normally you can't share storage data between two windows. If you really need that changes in data in one window reflect in another window then use socket or firebase to get real-time data.
I have this code:
qx.Class.define('my.Window', {
extend: qx.ui.window.Window,
construct: function(caption, icon) {
this.base(arguments, caption, icon);
this.setLayout(new qx.ui.layout.Basic());
this.__btn = new qx.ui.form.Button('Shortcut Test');
this.__cmd = new qx.ui.command.Command('Alt+T');
this.__cmd.addListener("execute", function() { alert('FOOBAR'); });
this.__btn.setCommand(this.__cmd);
this.add(this.__btn);
},
members: {
__btn: null,
__cmd: null
}
});
qx.Class.define('my.Compo', {
extend: qx.ui.container.Composite,
construct: function() {
this.base(arguments);
this.setLayout(new qx.ui.layout.HBox());
this.__btnShow = new qx.ui.form.Button("Show Window", "icon/22/apps/internet-web-browser.png");
this.__btnDestroy = new qx.ui.form.Button('Destroy window');
this.__btnNull = new qx.ui.form.Button('Null window');
this.__btnDestroy.addListener('execute', function(){
this.__window.destroy();
}, this);
this.__btnNull.addListener('execute', function(){
this.__window = null;
}, this);
this.__btnShow.addListener("execute", function(e){
if(this.__window) {
console.info('Window exist');
this.__window.open();
this.__window.center();
}
else {
console.info('Window do not exist!');
this.__window = new my.Window("Shortcut test window");
this.__window.setWidth(300);
this.__window.setHeight(200);
this.__window.setShowMinimize(false);
this.__window.open();
this.__window.center();
}
}, this);
this.add(this.__btnShow);
this.add(this.__btnDestroy);
this.add(this.__btnNull);
},
members: {
__btnShow: null,
__btnDestroy: null,
__window: null
}
});
var compo = new my.Compo();
this.getRoot().add(compo);
So, if you try "Alt+T" shortcut before clicking "Show Window" button, nothing happen. After show the Window, the shortcut is available and an alert is showed.
Well, the issue to me is the remaining availability of the shortcut in scenarios where that shortcut must do not exist any more:
When the window is close normally.
When Null window button is execute, and after that if you use "Alt+T" then the alert is showed twice, and so on as many time you switch between the Null and Show buttons.
Same behavior as (2) even if destroy() method of window is called explicitly.
On playground if "Run" button is clicked several times, also equal times is showed alert after use the shortcut.
Thanks no all for your time. :)
On Playground
The qx.ui.command.Command wraps the qx.bom.Shortcut that attaches 2 listeners to document element. When you close the window qx.ui.command.Command instance was not set inactive or destroyed. You'll have to handle the window close event properly.
destruct: function()
{
this.__cmd = null;
}
it does not destroy the command. If you try:
qx.core.ObjectRegistry.fromHashCode("the command object hash code").getActive()
You will find that it exists and is active. You forgot to destroy the command calling
this.__cmd.dispose()
Qooxdoo Playground App object registry is not initialized every time someone pushes "Run". So, qooxdoo object's lifetime is bound to page lifetime or a disposal event.
I'm writing a Windows Phone Mango app. I have a hyperlink that contains email addresses. I want it to show a message box on tap:
Hyperlink href = new Hyperlink();
href.Click += (s, r) =>
{
MessageBox.Show("href clicked");
};
// add href to RichTextBox
When I click on the hyperlink in the emulator, nothing happens. The click += line is hit in a debugger, but the new EmailComposeTask() line isn't.
What am I doing wrong? Is Click not the event I want?
Update: I switched EmailComposeTask to MessageBox to verify that this issue isn't related to the email compose task not running on the emulator. I've reproduced this issue on my device.
The following code works:
GestureService.GetGestureListener(href); // adding this makes it work
href.Click += (s, r) =>
{
MessageBox.Show("href clicked");
new EmailComposeTask() { To = entireLink.Value }.Show();
};
href.Inlines.Add(new Run() { Text = entireLink.Value });
GetGestureListener creates a gesture listener if it doesn't already exist.
You should use HyperlinkButton Class, Hyperlink is a class used with rich text document rendering.
Following code is runs on device. text is RichTextBox object.
var linkText = new Run() { Text = "Link text" };
var link = new Hyperlink();
link.Inlines.Add(linkText);
link.Click += (o, e) =>
{
MessageBox.Show("Link clicked");
};
var paragraph = new Paragraph();
paragraph.Inlines.Add(link);
text.Blocks.Add(paragraph);
I'm trying to open a new window via a button to the configuration page but how do you add a title (at the top of the screen) to a newly created window?
On the starting page, I have a button created to open a new page as:
var btnConfig = Ti.UI.createButton({
backgroundImage:'img/settings.png',
height:33,
width:33
});
win1.rightNavButton = btnConfig;
btnConfig.addEventListener('click',function(){
Ti.include('win_config.js');
})
Then on win_config.js :
var win_config = Titanium.UI.createWindow({
title:"Configure",
backgroundColor:'#BBB',
});
win_config.open({
transition:Ti.UI.iPhone.AnimationStyle.FLIP_FROM_LEFT
});
I thought that by just setting "title" it'll appear but apparently it doesnt.
needed to add "modal:true" in the createWindow
var win_config = Titanium.UI.createWindow({
title:"Configure",
backgroundColor:'#BBB',
modal:true
});