Eclipse RCP: как да наблюдавате състоянията на командите за изрязване/копиране/поставяне?

В момента се боря със следните RCP команди на Eclipse:

  • org.eclipse.ui.edit.cut
  • org.eclipse.ui.edit.copy
  • org.eclipse.ui.edit.paste

Използвам ги като командни приноси в лентата с инструменти, но UIElements (елементите на лентата с инструменти) не се актуализират, когато състоянието „handled“ на тези команди се промени.

За тестване използвах механизъм за анкетиране, за да проверя дали състоянието на тези команди наистина се променя в зависимост от текущо фокусирания елемент и открих, че манипулаторът остава същият, но „обработеното“ състояние на манипулатора се променя правилно, което води до „обработване“ на командите състоянието също да се промени правилно.

Единственият проблем е, че нито една от тези промени в състоянието не предизвиква известие (нито на ICommandListener на командата, нито на IHandlerListener на манипулатора), така че UIElements няма да се актуализират.

Ето някои тестови кодове за наблюдение на състоянията на дадена команда:

ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);

final String commandId="org.eclipse.ui.edit.copy";
Command command = commandService.getCommand(commandId);
command.addCommandListener(new ICommandListener() {

    public void commandChanged (CommandEvent commandEvent) {
        System.out.println(">> Command changed: " + commandId);
    }
});

Пропускам ли нещо или това е грешка в реализациите на манипулатора за изрязване/копиране/поставяне? Някакви прозрения?

РЕДАКТИРАНЕ: Командите са активирани през цялото време и манипулаторът никога не се обменя, само състоянието 'handled' на манипулатора (и по този начин също и състоянието 'handled' на командата) се променя в зависимост от това кой елемент на потребителския интерфейс е на фокус. Няма обаче известие, когато това състояние се промени. Това води до това, че бутоните на лентата с инструменти винаги са активирани и натискането им ще доведе до org.eclipse.core.commands.NotHandledException: There is no handler to execute for command.


person Peter Walser    schedule 26.05.2009    source източник


Отговори (3)


Манипулаторът, който е регистриран за командите за изрязване/копиране/поставяне, е org.eclipse.ui.internal.handlers.WidgetMethodHandler. Този манипулатор проверява дали даден метод е деклариран в управлението на фокуса на текущия дисплей. Когато се изпълни, този манипулатор ще извика метода чрез отражение.

Фрагмент от WidgetMethodHandler:

 public final boolean isHandled() {
     return getMethodToExecute() != null;
 }

getMethodToExecute() ще намери текущия контрол на фокуса с помощта на Display.getCurrent().getFocusControl() и след това ще провери дали даденият метод на задействане е деклариран върху него.

Уиджети като org.eclipse.swt.widgets.Text имат cut(), copy() и paste() методи, така че когато фокусът е върху такъв уиджет, манипулаторът ще върне 'true' за isHandled().

Този манипулатор обаче не е наясно, когато текущият контрол на фокуса се промени (мисля, че дори няма начин да наблюдавате това на дисплея) и по този начин не може да уведоми за промени в своето динамично състояние „isHandled“.

Това води до това, че командите за изрязване/копиране/поставяне са добри за изскачащи менюта, но са доста проблематични, когато се използват в ленти с инструменти, тъй като техните UI елементи не могат да бъдат актуализирани правилно, когато манипулаторът не изпраща известия.

Това ме оставя или да не използвам тези команди в лентата с инструменти, или да имам механизъм за анкетиране за актуализиране на елементите на потребителския интерфейс (което също е лошо и податливо на грешки). :-(

person Peter Walser    schedule 08.06.2009

Вашият проблем е, че трябва да регистрирате манипулатор за всичко, което не е текст, защото Eclipse трябва да знае как да копира текущо избраното „нещо“ в клипборда. Това прави манипулаторът. Тази статия в уикито на Eclipse ще ви помогне да започнете как да създадете и регистрирате манипулатор.

person Aaron Digulla    schedule 26.05.2009
comment
Това е състоянието „обработено“, което ме интересува. Когато фокусът не е върху текстово поле, и трите команди са активирани, но не се обработват (манипулаторът е зададен, но не се обработва) Когато командата се извиква чрез натискане на бутон от лентата с инструменти тогава това ще доведе до org.eclipse.core.commands.NotHandledException: Няма манипулатор за изпълнение за команда - person Peter Walser; 26.05.2009
comment
Напълно добре съм, когато дадена команда не се обработва временно (например когато фокусът се промени от текстово поле на бутон, тогава няма какво да се изрязва/копира/поставя), но в такъв случай бих искал да получа известие така че мога да деактивирам елемента от лентата с инструменти, докато командата не бъде обработена. Разбира се, бих могъл да регистрирам фиктивен манипулатор за споменатите команди, така че поне да не се хвърля изключение, когато се опитвам да ги изпълня, но бих предпочел да има деактивирани елементи от лентата с инструменти/менюто. - person Peter Walser; 26.05.2009
comment
Това е странно. В този случай командната рамка вече трябва да деактивира бутоните вместо вас (за това са условията). - person Aaron Digulla; 26.05.2009

Може да греша, но източникът на проблема е, че манипулаторът винаги е активиран.

Вижте Plug на платформата -в Ръководство за разработчици > Ръководство на програмиста > Включване в работната маса > Основни точки за разширение на работната маса с помощта на команди > Манипулатори.

Изразите <activeWhen/> в plugin.xml и програмните основни изрази се използват за определяне на обхвата на активиране на манипулатори. Например конкретен прозорец, конкретен Shell, тип активна част или активна част.

   <extension
         point="org.eclipse.ui.handlers">
      ...
      <handler
            class="org.eclipse.ui.examples.contributions.view.SwapInfoHandler"
            commandId="org.eclipse.ui.examples.contributions.view.swap">
         <activeWhen>
            <reference
                  definitionId="org.eclipse.ui.examples.contributions.view.inView">
            </reference>
         </activeWhen>
         <enabledWhen>
            <count
                  value="2">
            </count>
         </enabledWhen>
      </handler>
      ...
person Eugene Yokota    schedule 08.06.2009
comment
Валидно е манипулаторът да бъде активиран, но не и „обработен“. Условието „activeWhen“ не е задължително, когато не е указано, манипулаторът ще бъде активен през цялото време. Проблемът все още е, че промените в манипулатора не се уведомяват и конкретният манипулатор за изрязване/копиране/поставяне не може да бъде наблюдаван. - person Peter Walser; 08.06.2009