|
Bugzilla – Full Text Bug Listing |
| Summary: | YaST buttons clickable but may have no immediate effect | ||
|---|---|---|---|
| Product: | [openSUSE] openSUSE 11.2 | Reporter: | Johannes Meixner <jsmeix> |
| Component: | Usability | Assignee: | Johannes Meixner <jsmeix> |
| Status: | RESOLVED WONTFIX | QA Contact: | E-mail List <qa-bugs> |
| Severity: | Enhancement | ||
| Priority: | P5 - None | CC: | benderamp, jsrain, scott |
| Version: | Factory | ||
| Target Milestone: | --- | ||
| Hardware: | All | ||
| OS: | SUSE Other | ||
| Whiteboard: | |||
| Found By: | Development | Services Priority: | |
| Business Priority: | Blocker: | --- | |
| Marketing QA Status: | --- | IT Deployment: | --- |
|
Description
Johannes Meixner
2009-03-26 09:52:13 UTC
> We might discuss if it makes sense to have an additional
> "Kill" button in the dialogs of YaST modules which does
> send a SIGTERM but do other applications have it?
Definitly not. There is enough confusion about this "Cancel"/"Abort" topic.
In some cases the user is already informed if the process takes a longer time (printer detection, scanner detection).
I would be really careful about introducing busy pop ups which might annoy people or confuse people (change graphical representation of a button).
IMHO buttons should be only shown when they are enabled and their action has an effect.
Buttons maybe shown in a disabled state if there is a possibility to enable them in the same dialog.
Sorry, I can't be of more help.
Maybe there is a more technical solution to this topic?
Jiri, do you know, whom to address?
I'm not sure, which is the right solution. Looking at suggestions above: a) is not a way to go; there are operations which can be interrupted at some point (but not immediately); graying out such button would remove the chance of interrupting such operations. If an operation cannot be interrupted at all, graying out the button is an option, but this can only be done on per-case basis. b) can be done by the maintainers of individual UIs. If there already is some change in the button representation (I have not noticed), it might be quite simple c) would work only if you know how much time an operation can take - and does not solve operations which can be interrupted at some points. Flickerking pop-ups are not a prefered way d) better feedback may be an option, but don't know how to best represent being busy Martin, you wrote that "buttons should be only shown when they are enabled and their action has an effect". This is what I suggested under (a). What exactly do you mean with "has an effect"? Is an arbitrary delay o.k. as long as an effect happens at all? Is then the behaviour in https://bugzilla.novell.com/show_bug.cgi?id=442173#c4 acceptable? I explained that currently "buttons are shown even when their action does not have an effect within a reasonable response time". Above I wrote "immediately" but actually I meant "within a reasonable response time". Martin, I think "Buttons maybe shown in a disabled state if there is a possibility to enable them in the same dialog" looks a bit nonsense. I wonder why have a button [Foo] disabled and have the possibility to enable it e.g. after [Bar] was done? Why not have [Foo] enabled in any case and if clicked show a feedback popup that e.g. first [Bar] must be done before [Foo] can have the actually desired effect? As far as I can imagine at the moment the only case when buttons are disabled is when there are mutually exclusive things like one button [paint it black] and another button [paint it white] (after clicking one it gets disabled and the other one gets enabled) but for such cases one would usually better use radio buttons. Jiri, regarding (a) "operations which can be interrupted": Obviously an [Interrupt] button (whatever it is actually called) would not be grayed out if the process can respond to it (within a reasonable response time). I meant it the other way round: If the process is doing an operation which can be interrupted usually all other buttons except the [Interrupt] button might be grayed out (as long as all other buttons have no effect). Is it possible to have a function to gray out all current active buttons in the current dialog except a list of interrupt buttons like Wizard::DisableAllButtons( [ `id(`one_interrupt_button), `id(`another_interrupt_button) ] ) and a function Wizard::RestoreAllButtons() to restore the buttons to their actual state before DisableAllButtons was called (i.e. a button which was already disabled before would stay disabled afterwards)? Currently the problem is that it is complicated to know which buttons currently exist and in which state (one would have to mainain very carefully a list of button IDs and state manually) whenever the content of a dialog is changed anywhere. I think the issue is not only regarding explicite "button" widgets.
Actually it belongs to any widget where a click has an effect
e.g. radio buttons, combo boxes, items in trees, and even
widgets like `Table( `opt(`notify, `immediate) ...)
Therefore I would like to ask for gereral UI functions like
UI::DisableAllWidgets( [ `id(`interrupt_button),
`id(`notify_immediate_table) ] )
and
UI::RestoreAllWidgets()
Is it possible with reasonable effort to implement such functions?
We have a conceptional confusion here. I) From a usabiltiy perspective, a button which is enabled, should work. Immediatly and reliably. II) From a software architecture view, user interaction (which includes buttons) only happens when the program is in its main loop (or whereever the call to XNextEvent() is done). To implement I) faithfully, the best trick is: III) Avoid anything that takes any significant amount of time in the process that controls the UI. If we cannot guarantee III) our user experience may deteriorate. Trying to work around with explicit interrupts is the wrong approach. Any button should behave as if it were an interrupt. (Having II) and III) is a polling mechanism, giving a user experience very similar to real interupts) This forces us into seperate processes, one for implementing III) and another one for all potentially longer operation. FYI: While I talked to Martin I had the idea that one single status line where status/log messages appear continuously may help so much here - at least to indicate whether or not YaST is busy or has hang up. Just like a browser (at least my Firefox) does it: At the bottom it shows whatever funny status messages full of "technical nonsense" but the actual text does usually not matter at all for the user - all what matters is whether or not the status line continuously changes which indicates that the thingy is busy. And in case of a bug (e.g. a hangup) the status line is very useful because the user can report what it shows which may help us to find the root cause much faster. Another possible idea would be to introduce a button calles "Status" or "Log" (or something) which could be located next to "Help". The user would be able to get some information about background processes and in case of problems it might help developers/support people to get saner bug reports. Martin, this is a brilliant idea. It is least intrusive for th developers and very helpful to the user. This could work like an xtail or tail -f on the logfiles. The lower part of a stack backtrace could also be helpful. Not that the exact function calls or log-lines would be meaningful to the user, but as Johannes pointed out earlier, the frequency at which these things change (or not change) is meaningful. > Therefore I would like to ask for gereral UI functions like
> UI::DisableAllWidgets( [ `id(`interrupt_button),
> `id(`notify_immediate_table) ] )
> and
> UI::RestoreAllWidgets()
>
> Is it possible with reasonable effort to implement such functions?
Technically, of course it is possible and not that complicated. But the same can be achieved the same by invoking a busy-popup dialog before the time-consuming operation and closing it afterwards, now doesn't it? The busy pop-up is a modal dialog, thus user can't click around in underlying main dialog just as well ... or am I missing something?
Regarding a "Status/Log" button: We would have here the same problem as the bug describes. How to make sure that at least this one button responds immediately in any case? We would need an interrupt/signal-like solution at least for this one button together with an interrupt/signal handler function to make sure the status/log window pops up in any case. This is the reason why I proposed a status line which exists by default e.g. in each Wizard dialog where by default simply each line is shown which goes also into /var/log/YaST2/y2log. Probably better a status line where by default only YaST2 log-lines with "[YCP]" are shown to avoid too much useless "technical nonsense"? Katarina, regarding your comment #9: The technical effect "non-clickable widgets in the dialog" is the same when there is a pop-up on top of the dialog. But I think that from the user experience point of view there is a difference whether the dialog itself adapts or if pop-up are used, see what Martin wrote in comment #1 "be really careful about introducing busy pop ups". But in the end the question how it should look like (disabled widgets directly in the dialog or pop-ups) can only be answered by the usability experts. Sorry for the intrusion here - I have been following this issue for a long while. In Software Management we have a 'Skip Refresh' button which acts immediately, why cant we use the same mechanism that the 'skip refresh' button uses and just call it terminate/abort or anything else you like to terminate the task. I am probably being very simplistic, but the 'Skip..." button will always respond in the middle of a task....I am sure technically its not that easy Regarding comment #13: I find a 'Skip Refresh' button only in yast2/library/packages/src/PackageCallbacks.ycp where the code is: ------------------------------------------------------------------ `PushButton (`id(`skip), `opt (`cancelButton), _("Skip Refresh")) ... symbol ui = (symbol) UI::UserInput(); ------------------------------------------------------------------ For documentation see http://forgeftp.novell.com/yast/doc/SL11.1/tdg/ButtonBox.html and http://forgeftp.novell.com/yast/doc/SL11.1/tdg/UserInput.html This means that whenever a 'Skip Refresh' button is shown, it explicitely waits directly afterwards for user input. I.e. whenever a 'Skip Refresh' button is shown, it is never busy with something else. In contrast the code which leads to this bug is like: -------------------------------------------------------------------- `PushButton( `id(`foo), _("Foo") ) ... DoSomethingWhichMayTakeUnexpectedlyMuchTime(); ... symbol ui = (symbol) UI::UserInput(); -------------------------------------------------------------------- As long as it is in the DoSomethingWhichMayTakeUnexpectedlyMuchTime function, it will not respond to a click on [Foo]. When the author knows it may take much time the code is: -------------------------------------------------------------------- `PushButton( `id(`foo), _("Foo") ) ... Popup::ShowFeedback( _("Doing Foo. Please wait...") ); DoSomethingWhichIsKnownThatItMayTakeMuchTime(); sleep( 1000 ); Popup::ClearFeedback(); ... symbol ui = (symbol) UI::UserInput(); -------------------------------------------------------------------- When the author knows it takes much time in any case the code is: -------------------------------------------------------------------- `PushButton( `id(`foo), _("Foo") ) ... Popup::ShowFeedback( _("Doing Foo. Please wait...") ); DoSomethingWhichIsKnownToTakeMuchTime(); Popup::ClearFeedback(); ... symbol ui = (symbol) UI::UserInput(); -------------------------------------------------------------------- But a code like -------------------------------------------------------------------- `PushButton( `id(`interrupt), _("Interrupt") ) ... DoSomethingWhichIsKnownThatItMayTakeMuchTime(); ... if( `interrupt == (symbol) UI::UserInput() ) exit; -------------------------------------------------------------------- cannot work because clicking [Interrupt] is ignored until DoSomethingWhichIsKnownThatItMayTakeMuchTime had actually finished. O.K I knew #13 - was probably not going to fly - But case in point this is what I as a user sees as possible. Thanks to Johannes as I do now have a much better technical knowledge of what you are up against with Yast. Likewise as a user I see a Cancel Button in all Yast Services and it does nothing to stop a misbehaving Yast Service. Because we make poor validity of user field entries Yast Misbehaves quite regularly. So when Yast gets stuck - we all decide to take lunch hour until it times out - AND/OR we have the ability to boot everything - unless its a NFS Server - then we re-boot the whole LAN. For a normal user - they dont care - they just want whats on the screen to work or respond - This is not a difficult concept Gentlemen!!!!!!!!!!!!!!!!!!! Another Idea - In KDE4.n Windows Manager if any NON-Yast application either misbehaves or stops running I click a few time on th X to close the Window and a POP-UP Appear immediately asking me if I want to 'Kill Or Keep Running' If I choose Kill - the app closes without issue and without affecting the stability of the Windows Manager. Back to ANY Yast Application - I can click on the 'X" to close the window till the cows come home and *NOTHING* happens. Gentlemen - ALL We work with a machine and code that does what we decide - not the other way arround so there is a way to address this issue and we just might have to become a little more inventive with our code. Perhaps a little less technical jousting and more thought would help! I am only a YCP user but no low-level YaST programmer. I cannot fix it. *** Bug 595612 has been marked as a duplicate of this bug. *** |