Automatic attribute change if the document be edit.

Oxygen general issues.
larsS
Posts: 23
Joined: Mon Sep 13, 2021 10:41 am

Automatic attribute change if the document be edit.

Post by larsS »

Hello,
I need a little help.
When a document is opened and edited, the editor registers this change, Asterix to save, exactly at that moment I want a status attribute to be changed from created to edited at the same time.
I have looked in the Java API, but I can't really figure out which class is the right one at this point and whether I have to make an action out of it or can simply load it in a Java Extension Bundle.

It would be great if I could get some support. Thanks a lot.
Radu
Posts: 9473
Joined: Fri Jul 09, 2004 5:18 pm

Re: Automatic attribute change if the document be edit.

Post by Radu »

Hi,
Is this related to the DITA XML vocabulary which has a @status attribute?
If I were to implement this via an "ro.sync.ecss.extensions.api.ExtensionsBundle" API implementation provided from a framework configuration, the code could probably look something like:

Code: Select all

public class MyExtensionsBundle extends DITAExtensionsBundle {

  /**
   * @see ro.sync.ecss.extensions.dita.DITAExtensionsBundle#createAuthorExtensionStateListener()
   */
  @Override
  public AuthorExtensionStateListener createAuthorExtensionStateListener() {
    AuthorAccess[] currentAuthorAccess = new AuthorAccess[1];
    AuthorListener listener = new AuthorListenerAdapter() {
      @Override
      public void documentChanged(AuthorDocument oldDocument, AuthorDocument newDocument) {
        docModified();
      }
      
      private void docModified() {
        AuthorElement rootElement = currentAuthorAccess[0].getDocumentController().getAuthorDocumentNode().getRootElement();
        AttrValue status = rootElement.getAttribute("status");
        if(status != null 
            && ! "modified".equals(status.getValue())) {
        SwingUtilities.invokeLater(new Runnable() {
          
          @Override
          public void run() {
            currentAuthorAccess[0].getDocumentController().setAttribute("status", new AttrValue("modified"), rootElement);
          }
        });
        }
      }

      @Override
      public void doctypeChanged() {
        docModified();
      }
      
      @Override
      public void contentInserted(DocumentContentInsertedEvent e) {
        docModified();
      }
      
      @Override
      public void contentDeleted(DocumentContentDeletedEvent e) {
        docModified();
      }
      
      @Override
      public void beforeDoctypeChange() {
        docModified();
      }
      
      @Override
      public void authorNodeStructureChanged(AuthorNode node) {
        docModified();
      }
      
      @Override
      public void authorNodeNameChanged(AuthorNode node) {
        docModified();
      }
      
      @Override
      public void attributeChanged(AttributeChangedEvent e) {
        docModified();
      }
    };
    
    AuthorExtensionStateListener superListener = super.createAuthorExtensionStateListener();
    return new AuthorExtensionStateListener() {
      @Override
      public String getDescription() {
        return superListener.getDescription();
      }
      
      @Override
      public void deactivated(AuthorAccess authorAccess) {
        superListener.deactivated(authorAccess);
        authorAccess.getDocumentController().removeAuthorListener(listener);
        currentAuthorAccess[0] = null;
      }
      
      @Override
      public void activated(AuthorAccess authorAccess) {
        superListener.activated(authorAccess);
        authorAccess.getDocumentController().addAuthorListener(listener);
        currentAuthorAccess[0] = authorAccess;
      }
    };
So there is no generic ModificationListener, you can add a listener which gets notified whenever various changes occur.
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
larsS
Posts: 23
Joined: Mon Sep 13, 2021 10:41 am

Re: Automatic attribute change if the document be edit.

Post by larsS »

Hey Radu,

thanks for the reply. This looks good. I will try to add the listener to my Extension Bundle.
No it is a custom XML Schema, not a DITA XML.
larsS
Posts: 23
Joined: Mon Sep 13, 2021 10:41 am

Re: Automatic attribute change if the document be edit.

Post by larsS »

Hey Radu,

I get a NullPointerException on trying to close the document.

Code: Select all

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at de.sawleipzig.awbplus.AWBplusArticleExtensionsBundle$2.deactivated(AWBplusArticleExtensionsBundle.java:76)
        at ro.sync.ecss.extensions.api.AuthorExtensionStateListenerDelegator.fireDeactivated(Unknown Source)
        at ro.sync.ecss.extensions.api.AuthorExtensionStateListenerDelegator.deactivated(Unknown Source)
        at ro.sync.exml.editor.xmleditor.pageauthor.q.wqg(Unknown Source)
        at ro.sync.exml.editor.xmleditor.pageauthor.q.editorWillBeClosed(Unknown Source)
        at ro.sync.exml.editor.ad.close(Unknown Source)
        at ro.sync.exml.editor.validate.cb.close(Unknown Source)
        at ro.sync.exml.editor.xmleditor.yb.close(Unknown Source)
        at ro.sync.exml.editor.xmleditor.qb.close(Unknown Source)
        at ro.sync.exml.editor.xmleditor.ac.close(Unknown Source)
        at ro.sync.exml.editor.ee.uij(Unknown Source)
        at ro.sync.exml.editor.ee.closeEditor(Unknown Source)
        at ro.sync.exml.editor.ee$4.lsj(Unknown Source)
        at ro.sync.exml.editor.qg$6.actionPerformed(Unknown Source)
        at com.jidesoft.docking.FrameContainer$1.actionPerformed(Unknown Source)
        at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI$_s.actionPerformed(Unknown Source)
        at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
        at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
        at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
        at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
        at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
        at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
        at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
        at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635)
        at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
        at java.desktop/java.awt.Component.processEvent(Component.java:6400)
        at java.desktop/java.awt.Container.processEvent(Container.java:2263)
        at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
        at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
        at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
        at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
        at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
        at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
        at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
        at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
        at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
        at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
        at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
        at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
        at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
        at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
I hoped the ExtensionsBundle Class for the framework does this job, but the AuthorListenerAdapter will not be registered. currentAuthorAccess is null. I don't know why. Maybe I use the 24.1 Version?
Radu
Posts: 9473
Joined: Fri Jul 09, 2004 5:18 pm

Re: Automatic attribute change if the document be edit.

Post by Radu »

Hi,
Oxygen 24.1 is end of life so officially we no longer provide support for it:
https://www.oxygenxml.com/eol.html

Coming back to the problem, it is probably not related to you using Oxygen 24.1.
So the NullPointerException is at this line "AWBplusArticleExtensionsBundle.java:76", can you guard against it?
If you add System.err.println on the "activated" and "deactivated" callbacks and start Oxygen using the "oxygen.bat" command line script from the installation folder you can check if these callbacks are called in your code and with what parameters.
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
larsS
Posts: 23
Joined: Mon Sep 13, 2021 10:41 am

Re: Automatic attribute change if the document be edit.

Post by larsS »

I refactored the code and now the problem is solved.

Code: Select all

import ro.sync.ecss.extensions.api.*;
import ro.sync.ecss.extensions.api.node.AttrValue;
import ro.sync.ecss.extensions.api.node.AuthorDocument;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;

public class ArticleExtensionsBundle extends ExtensionsBundle {
    private AuthorAccess authorAccess;

    @Override
    public AuthorExtensionStateListener createAuthorExtensionStateListener() {
        AuthorListener listener = new AuthorListenerAdapter() {

            @Override
            public void documentChanged(AuthorDocument oldDocument, AuthorDocument newDocument) {
                docModified();
            }

            private void docModified() {
                if (authorAccess != null) {
                    AuthorElement rootElement = authorAccess.getDocumentController().getAuthorDocumentNode().getRootElement();
                    AttrValue status = rootElement.getAttribute("status");
                    if (status != null && !"modified".equals(status.getValue())) {
                        authorAccess.getDocumentController().setAttribute("status", new AttrValue("modified"), rootElement);
                    }
                } else {
                    System.err.println("authorAccess is null in docModified()");
                }
            }

            @Override
            public void doctypeChanged() {
                docModified();
            }

            @Override
            public void contentInserted(DocumentContentInsertedEvent e) {
                docModified();
            }

            @Override
            public void contentDeleted(DocumentContentDeletedEvent e) {
                docModified();
            }

            @Override
            public void beforeDoctypeChange() {
                docModified();
            }

            @Override
            public void authorNodeStructureChanged(AuthorNode node) {
                docModified();
            }

            @Override
            public void authorNodeNameChanged(AuthorNode node) {
                docModified();
            }

            @Override
            public void attributeChanged(AttributeChangedEvent e) {
                docModified();
            }
        };

        return new AuthorExtensionStateListener() {
             @Override
            public String getDescription() {
                return "Extensions State Bundle";
            }

            @Override
            public void deactivated(AuthorAccess authorAccess) {
                ArticleExtensionsBundle.this.authorAccess = authorAccess;
                if (authorAccess != null) {
                    authorAccess.getDocumentController().removeAuthorListener(listener);
                }
            }

            @Override
            public void activated(AuthorAccess authorAccess) {
                ArticleExtensionsBundle.this.authorAccess = authorAccess;
                if (authorAccess != null) {
                    authorAccess.getDocumentController().addAuthorListener(listener);
                }
            }
        };
    }

    @Override
    public String getDocumentTypeID() {
        return "id.type.document"; 
    }

    @Override
    public String getDescription() {
        return "Extensions"; 
    }
}

Radu
Posts: 9473
Joined: Fri Jul 09, 2004 5:18 pm

Re: Automatic attribute change if the document be edit.

Post by Radu »

Hi,
I would probably leave that original "SwingUtilities.invokeLater" when the actual attribute is changed, the content modified callbacks are given just as the content is being modified so the current modification should finish before another modification begins. Also you should check the behavior of "Undo", the attribute change will probably be recorded as a separate undo operation so the end user will need to undo twice to get to the original state.
If you want Undo to work by combining the two changes together (the original change + change which modified the attribute) I think we could try to use another API...
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Post Reply