// 
//     Licensed to the Apache Software Foundation (ASF) under one
//     or more contributor license agreements.  See the NOTICE file
//     distributed with this work for additional information
//     regarding copyright ownership.  The ASF licenses this file
//     to you under the Apache License, Version 2.0 (the
//     "License"); you may not use this file except in compliance
//     with the License.  You may obtain a copy of the License at
// 
//       http://www.apache.org/licenses/LICENSE-2.0
// 
//     Unless required by applicable law or agreed to in writing,
//     software distributed under the License is distributed on an
//     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//     KIND, either express or implied.  See the License for the
//     specific language governing permissions and limitations
//     under the License.
//

= How do you invoke the View/IDE Log Action programmatically?
:jbake-type: wikidev
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published
:keywords: Apache NetBeans wiki DevFaqLogActionStartup
:description: Apache NetBeans wiki DevFaqLogActionStartup
:toc: left
:toc-title:
:syntax: true
:wikidevsection: _actions_how_to_add_things_to_files_folders_menus_toolbars_and_more
:position: 36


Problem: In a NetBeans Platform application, it is conceivable that the Output window's only use could be to show logging messages to the user. In this case, since the Output TopComponent is always persisted, and the IDE log is only attached via an Action, the Action should be invoked whenever the Output window is open.

Solution: We can create an Installer class which will search for the existence of the Output window, and conditionally fire the action which attaches the IDE Log.

== Waiting for the Windows System to be ready

Installer classes (those that extend ModuleInstall) will fire their restored() methods before the Windows System is available. This is a problem, since we need to be able to interrogate the TopComponent.Registry to determine if the Output window is open.

The answer is to use the WindowManager.getDefault().invokeWhenUIReady() method.

[source,java]
----

    @Override
    public void restored()
    {
        //The TopComponent we're interested in isn't immediately available. 
        //This method allows us to delay start of our procedure until later.
        WindowManager.getDefault().invokeWhenUIReady(new Runnable()
        {
            @Override
            public void run()
            {
                 //Do something
            }
        });
    }
----

== Finding the Output TopComponent

We find the Output TopComponent by the WindowManager.getDefault().findTopComponent() method. We must know the ID of the TopComponent we are searching for. In this case, it is "output".

[source,java]
----

            @Override
            public void run()
            {
                //Locate the Output Window instance                
                final String OUTPUT_ID = "output";
                TopComponent outputWindow = WindowManager.getDefault().findTopComponent(OUTPUT_ID);
----

== Determining if the Output window is open

This is easily accomplished by using the methods of the TopComponent class.

[source,java]
----

               if (outputWindow != null &amp;&amp; outputWindow.isOpened())
----

=== Locating our Action from the System Filesystem (Layer)

We can get a Lookup for a portion of the System Filesystem using Lookups.forPath(). Browse your layer file in context to determine where the instance of the action is stored. In our case, it is in Actions/View.

[source,java]
----

                   final String FOLDER = "Actions/View/";
                   Lookup pathLookup = Lookups.forPath(FOLDER);
----

=== Getting the Instance from our Lookup

Now that we have a lookup to the appropriate folder of the System Filesystem, we need to know the instance file name of the Action we want to retrieve and invoke. We get this information from browsing our layer file in context. In our case, it is "org-netbeans-core-actions-LogAction".
We then invoke actionPerformed() to fire the action.

[source,java]
----

Action a = FileUtil.getConfigObject("Actions/org-netbeans-core-actions-LogAction.instance", Action.class);
if (a != null) {
    action.actionPerformed(null);
}
----

== Putting it all together

Here is the completed Installer class, with logging.

[source,java]
----

/**
 * This class makes it so that the action View/IDE-Logs is performed upon startup
 * whenever the Output window is open.
 */
public class ViewLogsInstaller extends ModuleInstall
{
    private static final Logger logger = Logger.getLogger(ViewLogsInstaller.class.getName(), ViewLogsInstaller.class.getPackage().getName() + ".Log");

    @Override
    public void restored()
    {
        //The TopComponent we're interested in isn't immediately available. 
        //This method allows us to delay start of our procedure until later.
        WindowManager.getDefault().invokeWhenUIReady(new Runnable()
        {
            @Override
            public void run()
            {
                //Locate the Output Window instance                
                final String OUTPUT_ID = "output";
                logger.log(Level.FINE, "LOG_FindingWindow", OUTPUT_ID);
                TopComponent outputWindow = WindowManager.getDefault().findTopComponent(OUTPUT_ID);
                
                //Determine if it is opened
                if (outputWindow != null &amp;&amp; outputWindow.isOpened())
                {
                    logger.log(Level.FINE, "LOG_WindowOpen", OUTPUT_ID);
                    final String FOLDER = "Actions/View/";
                    final String INSTANCE_FILE = "org-netbeans-core-actions-LogAction";

                    //Use Lookup to find the instance in the file system
                    logger.log(Level.FINE, "LOG_LookupAction", new Object[]{FOLDER, INSTANCE_FILE});
                    Lookup pathLookup = Lookups.forPath(FOLDER);
                    Template<Action> actionTemplate = new Template<Action>(Action.class, FOLDER + INSTANCE_FILE, null);
                    Result<Action> lookupResult = pathLookup.lookup(actionTemplate);
                    Collection<? extends Action> foundActions = lookupResult.allInstances();
                    
                    //For each instance (should ony be one) call actionPerformed()
                    for (Action action : foundActions)
                    {
                        logger.log(Level.FINE, "LOG_FoundAction", action);
                        action.actionPerformed(null);
                    } 
                }
                else
                {
                    logger.log(Level.FINE, "LOG_WindowClosed", OUTPUT_ID);
                }
            }
        });
    }
}
----

=== Log.properties file

Place this file in the root package of your installer.

[source,java]
----

LOG_FindingWindow=Attempting to locate TopComponent with ID ''{0}''
LOG_WindowOpen=TopComponent with ID ''{0}'' is open
LOG_LookupAction=Attempting to find Action instance at {0}{1}
LOG_FoundAction=Found Action ''{0}''; calling actionPerformed()
LOG_WindowClosed=TopComponent with ID ''{0}'' is closed or not instantiated
----

////
== Apache Migration Information

The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.

This page was exported from link:http://wiki.netbeans.org/DevFaqLogActionStartup[http://wiki.netbeans.org/DevFaqLogActionStartup] , 
that was last modified by NetBeans user Jglick 
on 2011-12-14T00:23:24Z.


*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-02-07, and needs to be reviewed.
////