All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.i18n.I18nManager Maven / Gradle / Ivy

/*
 * 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.
 */


package org.netbeans.modules.i18n;

import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.text.Caret;

import org.openide.cookies.EditorCookie;
import org.openide.DialogDescriptor;
import org.openide.loaders.DataObject;
import org.openide.NotifyDescriptor;
import org.openide.DialogDisplayer;
import org.netbeans.api.project.Project;
import org.openide.util.Exceptions;
import org.openide.util.RequestProcessor;
import org.openide.ErrorManager;
import org.openide.cookies.SaveCookie;


/**
 * Manages performing of i18n action -> i18n-zation of one source.
 *
 * @author   Peter Zavadsky
 */
public class I18nManager {

    static final Logger LOG = Logger.getLogger(I18nManager.class.getName());
    
    /** Singleton instance of I18nManager. */
    private static I18nManager manager;

    /** Support for this internatioanlize session. */
    private I18nSupport support;

    /** Weak reference to i18n panel. */
    private WeakReference i18nPanelWRef = new WeakReference(null);
    
    /** Weak reference to top component in which internationalizing will be provided. */
    private WeakReference dialogWRef = new WeakReference(null);
    
    /** Weak reference to caret in editor pane. */
    private WeakReference caretWRef;

    /** Found hard coded string. */
    private HardCodedString hcString;
    
    private int replaceCount = 0;

    /** Private constructor. To ge instance use getI18nMananger method instead. */
    private I18nManager() {
    }

    
    /** Gets the only instance of I18nSupport. */
    public static synchronized I18nManager getDefault() {
        if (manager == null) {
            manager = new I18nManager();
        }
        return manager;
    }
    
    /** Get i18n support. */
    private void initSupport(DataObject sourceDataObject) throws IOException {
        I18nSupport.Factory factory = FactoryRegistry.getFactory(sourceDataObject.getClass());
        
        support = factory.create(sourceDataObject);

        if(support == null && LOG.isLoggable(Level.SEVERE)) {
                LOG.logp(Level.SEVERE, getClass().getName(),
                        "initSupport(DataObject)",
                        "I18nSupport is null for " + sourceDataObject);// NOI18N
        }
    }
    
    /** The 'heart' method called by I18nAction. */
    public void internationalize(final DataObject sourceDataObject) {

        // If there is i18n action working -> cancel it.
        closeDialog();

        // Initilialize support.
        try {
            initSupport(sourceDataObject);
        } catch (IOException ioe) {
            ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe);
            return;
        }

        // initialize the component
        final EditorCookie ec = sourceDataObject.getCookie(EditorCookie.class);
        if (ec == null) {
            return;
        }

        // Add i18n panel to top component.
        getDialog(sourceDataObject);
        final I18nPanel i18nPanel = i18nPanelWRef.get();
        i18nPanel.showBundleMessage("TXT_SearchingForStrings");         //NOI18N
        i18nPanel.getCancelButton().requestFocusInWindow();
        
        final class SearchResultDisplayer implements Runnable {
            private final boolean success;
            SearchResultDisplayer(boolean success) {
                this.success = success;
            }
            public void run() {
                if (success) {
                    initCaret(ec);
                    highlightHCString();
                    fillDialogValues();                        
                    i18nPanel.getReplaceButton().requestFocusInWindow();
                } else {
                    i18nPanel.showBundleMessage("TXT_NoHardcodedString");//NOI18N
                    i18nPanel.getCancelButton().requestFocusInWindow();

                }
            }
        }

        // do the search on background
        RequestProcessor.getDefault().post(new Runnable() {
                public void run() {
                    boolean found = find();
                    EventQueue.invokeLater(new SearchResultDisplayer(found));
                }
            });


        
    }

    /** Initializes caret. */
    private void initCaret(EditorCookie ec) {
        JEditorPane[] panes = ec.getOpenedPanes();
        if (panes == null) {
            NotifyDescriptor.Message message = new NotifyDescriptor.Message(
                    I18nUtil.getBundle().getString("MSG_CouldNotOpen"), //NOI18N
                    NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(message);
            return;
        }

        // Keep only weak ref to caret, the strong one maintains editor pane itself.
        caretWRef = new WeakReference(panes[0].getCaret());
    }
    
    /** Highlights found hasrdcoded string. */
    private void highlightHCString() {
        HardCodedString hStr = hcString;
        
        if (hStr == null) {
            return;
        }
        
        // Highlight found hard coded string.
        Caret caret = caretWRef.get();
        
        if (caret != null) {
            caret.setDot(hStr.getStartPosition().getOffset());
            caret.moveDot(hStr.getEndPosition().getOffset());
        }
    }

    /** Finds hard coded string. */
    private boolean find() {
        // Actual find on finder.
        hcString = support.getFinder().findNextHardCodedString();

        if (hcString != null) {
            return true;
        } 
        
        // not found in entire source document
        return false;
    }

    /** Fills values presented in internationalize dialog. */
    private void fillDialogValues() {
        // It has to work this way, at this time the strong reference in top component have to exist.
        I18nPanel i18nPanel = i18nPanelWRef.get();

        if(support == null) {
            if(LOG.isLoggable(Level.SEVERE)) {
                LOG.logp(Level.SEVERE, getClass().getName(),
                        "fillDialogValues()",
                        "I18nSupport is null"); // NOI18N
            }
            return;
        }

        i18nPanel.setI18nString(support.getDefaultI18nString(hcString));
        
        showDialog();
    }
    
    /** Replaces current found hard coded string and continue the search for next one. */
    private void replace() {
        I18nString i18nString = null;
        
        try {
            // To call weak without check have to be save here cause strong reference in the top component have to exist.
            i18nString = i18nPanelWRef.get().getI18nString();
        } catch (IllegalStateException e) {
            NotifyDescriptor.Message nd = new NotifyDescriptor.Message(
                    I18nUtil.getBundle().getString("EXC_BadKey"),       //NOI18N
                    NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(nd);
            return;
        }

        // Try to add key to bundle.
        support.getResourceHolder().addProperty(i18nString.getKey(), i18nString.getValue(), i18nString.getComment());

        replaceCount++;
        // Provide additional changes if they are available.
        if (support.hasAdditionalCustomizer()) {
            support.performAdditionalChanges();
        }
        
        // Replace hardcoded string.
        support.getReplacer().replace(hcString, i18nString);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                skip();
            }
        });
  }
    
    /** Skips foudn hard coded string and conitnue to search for next one. */
    private void skip() {
        if (find()) {
            highlightHCString();
            fillDialogValues();
        } else {
            i18nPanelWRef.get().showBundleMessage("TXT_NoMoreStrings"); //NOI18N
            i18nPanelWRef.get().getCancelButton().requestFocusInWindow();
        }
    }

    /**
     * Appends //NOI18N to the current line
     */
    private void ignore() {
        I18nString i18nString = null;
        try {
            // To call weak without check have to be save here cause strong reference in the top component have to exist.
            i18nString = i18nPanelWRef.get().getI18nString();
        } catch (IllegalStateException e) {
            NotifyDescriptor.Message nd = new NotifyDescriptor.Message(
                    I18nUtil.getBundle().getString("EXC_BadKey"),       //NOI18N
                    NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(nd);
            return;
        }
        i18nString.setKey(null);
        support.getReplacer().replace(hcString, i18nString);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                skip();
            }
        });
    }

    /** Shows info about found hard coded string. */
    private void showInfo() {
        JPanel infoPanel = support.getInfo(hcString);

        DialogDescriptor dd = new DialogDescriptor(
                infoPanel,
                I18nUtil.getBundle().getString("CTL_InfoPanelTitle"));  //NOI18N
        
        dd.setModal(true);
        dd.setOptionType(DialogDescriptor.DEFAULT_OPTION);
        dd.setOptions(new Object[] {DialogDescriptor.OK_OPTION});
        dd.setAdditionalOptions(new Object[0]);

        
        Dialog infoDialog = DialogDisplayer.getDefault().createDialog(dd);
        infoDialog.setVisible(true);
    }
    
    /** Cancels current internationalizing session and re-layout top component to original layout. */
    public void cancel() {
        if (replaceCount>0) {
            //Need to save resource
            DataObject resource = support.getResourceHolder().getResource();
            if (resource != null) {
                SaveCookie save = resource.getCookie(SaveCookie.class);
                if (save!=null) {
                    try {
                        save.save();
                    } catch (IOException ex) {
                        Exceptions.printStackTrace(ex);
                    }
                }
            }
        }
        replaceCount = 0;
        // No memory leaks.
        support = null;

        if(LOG.isLoggable(Level.FINEST)) {
            LOG.logp(Level.FINEST, getClass().getName(), "cancel()",
                     "Sets the I18nSupport to  null"); // NOI18N
        }
        
        closeDialog();
    }
    
    /** Gets dialog. In our case it is a top component. 
     * @param name name of top component */
    private void getDialog(DataObject sourceDataObject) {
        Project project = Util.getProjectFor(sourceDataObject);

        Dialog dialog = dialogWRef.get();
        I18nPanel i18nPanel = i18nPanelWRef.get();

        // Dialog was not created yet or garbaged already.
        if (i18nPanel == null) {
            
            // Create i18n panel.
            i18nPanel = new I18nPanel(support.getPropertyPanel(),
                                      project,
                                      sourceDataObject.getPrimaryFile());

            // Helper final.
            final I18nPanel panel = i18nPanel;
            
            // Set button listeners.
            ActionListener listener = new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    final Object source = evt.getSource();
                    if (source == panel.getReplaceButton()) {
                        replace();
                    } else if (source == panel.getSkipButton()) {
                        skip();
                    } else if (source == panel.getIgnoreButton()) {
                        ignore();
                    } else if (source == panel.getInfoButton()) {
                        showInfo();
                    } else if (source == panel.getCancelButton()) {
                        cancel();
                    }
                }
            };
            
            i18nPanel.getReplaceButton().addActionListener(listener);
            i18nPanel.getSkipButton().addActionListener(listener);
            i18nPanel.getIgnoreButton().addActionListener(listener);
            i18nPanel.getInfoButton().addActionListener(listener);
            i18nPanel.getCancelButton().addActionListener(listener);
            
            // Reset weak reference.
            i18nPanelWRef = new WeakReference(i18nPanel);

        } else {
//            i18nPanel.setProject(project);
            i18nPanel.setFile(sourceDataObject.getPrimaryFile());
        }

        // Set default i18n string.
        i18nPanel.setI18nString(support.getDefaultI18nString());
        i18nPanel.setDefaultResource(sourceDataObject);


        if (dialog == null) {
            String title = Util.getString("CTL_I18nDialogTitle"); // NOI18N
            DialogDescriptor dd = new DialogDescriptor(
                    i18nPanel,
                    title,
                    false,
                    new Object[] {},
                    null,
                    DialogDescriptor.DEFAULT_ALIGN,
                    null,
                    null);
            dialog = DialogDisplayer.getDefault().createDialog(dd);
            dialog.setLocation(80, 80);
            dialogWRef = new WeakReference(dialog);
        }

        dialog.setVisible(true); 
    }
    
    /** Shows dialog. In our case opens top component if it is necessary and
     * sets caret visible in editor part. */
    private void showDialog() {
        // Open dialog if available
        Dialog dialog = dialogWRef.get();
        if (dialog != null) {
            dialog.setVisible(true);
        }

        // Set caret visible.
        Caret caret = caretWRef.get();
        if (caret != null) { 
            if (!caret.isVisible()) {
                caret.setVisible(true);
            }
        }
    }
    
    /** Closes dialog. In our case removes I18nPanel from top component
     * and 'reconstruct it' to it's original layout. */
    private void closeDialog() {
        Dialog dialog = dialogWRef.get();
        if (dialog != null) {
            dialog.setVisible(false);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy