class RecentFiles extends AbstractAction implements DynamicMenuContent {

    RecentFiles() {
        super(NbBundle.getMessage(RecentFiles.class, "CTL_OpenRecentFiles"));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // does nothing, this is a popup menu
    }

    @Override
    public JComponent[] getMenuPresenters() {
        return createMenu();
    }

    @Override
    public JComponent[] synchMenuPresenters(JComponent[] items) {
        return createMenu();
    }

    private JComponent[] createMenu() {<FILL_FUNCTION_BODY>}

    private JComponent[] createSubMenus() {
        // Projects
        List<JMenuItem> projectsItems = new ArrayList<>();
        ProjectController projectController = Lookup.getDefault().lookup(ProjectController.class);
        for (Project project : projectController.getAllProjects()) {
            if (project.hasFile()) {
                JMenuItem menuItem = new JMenuItem(new OpenProjectAction(project));
                projectsItems.add(menuItem);
            }
        }

        // Files
        MostRecentFiles mru = Lookup.getDefault().lookup(MostRecentFiles.class);
        List<JMenuItem> filesItems = mru.getMRUFileList().stream().map(File::new).filter(File::exists)
            .map(f -> new JMenuItem(new OpenFileAction(f))).collect(
                Collectors.toList());

        // Add to menu, with separator if needed
        List<JComponent> items = new ArrayList<>(projectsItems);
        if (!projectsItems.isEmpty() && !filesItems.isEmpty()) {
            items.add(new JSeparator());
        }
        items.addAll(filesItems);

        // Manage projects
        items.add(new JSeparator());
        items.add(new JMenuItem(Actions.forID("File", "org.gephi.desktop.project.actions.ManageProjects")));

        return items.toArray(new JComponent[0]);
    }

    private static class OpenFileAction extends AbstractAction {

        private final File file;

        public OpenFileAction(File file) {
            super(file.getName());
            this.file = file;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            FileObject fileObject = FileUtil.toFileObject(file);
            ImportControllerUI importController = Lookup.getDefault().lookup(ImportControllerUI.class);
            if (importController.getImportController().isFileSupported(file)) {
                importController.importFile(fileObject);
            }
        }
    }

    private static class OpenProjectAction extends AbstractAction {

        private final Project project;

        public OpenProjectAction(Project project) {
            super(getActionName(project));
            this.project = project;
        }

        private static String getActionName(Project project) {
            return project.getName() + " (" + project.getFileName() + ")";
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            File file = project.getFile();
            Actions.forID("File", "org.gephi.desktop.project.actions.OpenFile").actionPerformed(
                new ActionEvent(file, 0, null));
        }
    }
}

        JMenu menu = new JMenu(NbBundle.getMessage(RecentFiles.class, "CTL_OpenRecentFiles"));
        JComponent[] menuItems = createSubMenus();
        for (JComponent item : menuItems) {
            menu.add(item);
        }
        return new JComponent[] {menu};
    
<methods>public void <init>() ,public void <init>(java.lang.String) ,public void <init>(java.lang.String, javax.swing.Icon) ,public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener) ,public java.lang.Object[] getKeys() ,public synchronized java.beans.PropertyChangeListener[] getPropertyChangeListeners() ,public java.lang.Object getValue(java.lang.String) ,public boolean isEnabled() ,public void putValue(java.lang.String, java.lang.Object) ,public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener) ,public void setEnabled(boolean) <variables>private static java.lang.Boolean RECONFIGURE_ON_NULL,private transient javax.swing.ArrayTable arrayTable,protected javax.swing.event.SwingPropertyChangeSupport changeSupport,protected boolean enabled