org.gjt.sp.jedit.pluginmgr.ManagePanel

public class ManagePanel extends JPanel
{
	//{{{ Private members
	private final JCheckBox hideLibraries;
	private final JTable table;
	private final JScrollPane scrollpane;
	private final PluginDetailPanel pluginDetailPanel;
	private final PluginTableModel pluginModel;
	private final PluginManager window;
	private JPopupMenu popup;
	private Set<String> selectedPlugins;
	private Set<String> jarNames;
	//}}}

	//{{{ ManagePanel constructor
	public ManagePanel(PluginManager window)
	{
		super(new BorderLayout(12,12));

		this.window = window;

		setBorder(new EmptyBorder(12,12,12,12));

		Box topBox = new Box(BoxLayout.X_AXIS);
		topBox.add(hideLibraries = new HideLibrariesButton());
		add(BorderLayout.NORTH,topBox);

		/* Create the plugin table */
		table = new JTable(pluginModel = new PluginTableModel());
		table.setShowGrid(false);
		table.setIntercellSpacing(new Dimension(0,0));
		table.setRowHeight(table.getRowHeight() + 2);
		table.setPreferredScrollableViewportSize(new Dimension(500,300));
		table.setDefaultRenderer(Object.class, new TextRenderer(
			(DefaultTableCellRenderer)table.getDefaultRenderer(Object.class)));
		table.addFocusListener(new TableFocusHandler());
		table.getSelectionModel().addListSelectionListener(new TableSelectionListener());
		InputMap tableInputMap = table.getInputMap(JComponent.WHEN_FOCUSED);
		ActionMap tableActionMap = table.getActionMap();
		tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,0),"tabOutForward");
		tableActionMap.put("tabOutForward",new KeyboardAction(KeyboardCommand.TAB_OUT_FORWARD));
		tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,InputEvent.SHIFT_MASK),"tabOutBack");
		tableActionMap.put("tabOutBack",new KeyboardAction(KeyboardCommand.TAB_OUT_BACK));
		tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"editPlugin");
		tableActionMap.put("editPlugin",new KeyboardAction(KeyboardCommand.EDIT_PLUGIN));
		tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"closePluginManager");
		tableActionMap.put("closePluginManager",new KeyboardAction(KeyboardCommand.CLOSE_PLUGIN_MANAGER));

		TableColumn col1 = table.getColumnModel().getColumn(0);
		TableColumn col2 = table.getColumnModel().getColumn(1);
		TableColumn col3 = table.getColumnModel().getColumn(2);
		TableColumn col4 = table.getColumnModel().getColumn(3);

		col1.setPreferredWidth(30);
		col1.setMinWidth(30);
		col1.setMaxWidth(30);
		col1.setResizable(false);

		col2.setPreferredWidth(300);
		col3.setPreferredWidth(100);
		col4.setPreferredWidth(100);

		JTableHeader header = table.getTableHeader();
		header.setReorderingAllowed(false);
		HeaderMouseHandler mouseHandler = new HeaderMouseHandler();
		header.addMouseListener(mouseHandler);
		table.addMouseListener(mouseHandler);
		scrollpane = new JScrollPane(table);
		scrollpane.getViewport().setBackground(table.getBackground());
		pluginDetailPanel = new PluginDetailPanel();
		scrollpane.setPreferredSize(new Dimension(400,400));
		JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
			true, scrollpane, pluginDetailPanel);
		add(BorderLayout.CENTER, split);
		split.setResizeWeight(0.75);
		/* Create button panel */
		Box buttons = new Box(BoxLayout.X_AXIS);

		buttons.add(new RemoveButton());
		buttons.add(new SaveButton());
		buttons.add(new RestoreButton());
		buttons.add(new FindOrphan());
		buttons.add(Box.createGlue());
		buttons.add(new HelpButton());

		add(BorderLayout.SOUTH,buttons);

		pluginModel.update();
	} //}}}

	//{{{ update() method
	public void update()
	{
		pluginModel.update();
	} //}}}

	// {{{ class ManagePanelRestoreHandler
	/**
	 * For handling the XML parse events of a plugin set.
	 * Selects the same plugins that are in that set.
	 * @since jEdit 4.3pre10
	 */
	private class ManagePanelRestoreHandler extends DefaultHandler
	{
		ManagePanelRestoreHandler()
		{
			selectedPlugins = new HashSet<String>();
			jarNames = new HashSet<String>();
		}

		@Override
		public void startElement(String uri, String localName,
							String qName, Attributes attrs) throws SAXException
		{
			if (localName.equals("plugin"))
			{
				String jarName = attrs.getValue("jar");
				String name = attrs.getValue("name");
				Entry e = new Entry(jarName);
				e.name=name;
				selectedPlugins.add(name);
				jarNames.add(jarName);
			}
		}
	}//}}}

	//{{{ loadPluginSet() method
	boolean loadPluginSet(String path)
	{
		VFS vfs = VFSManager.getVFSForPath(path);
		Object session = vfs.createVFSSession(path, this);
		try
		{
			InputStream is = vfs._createInputStream(session, path, false, this);
			XMLUtilities.parseXML(is, new ManagePanelRestoreHandler());
			is.close();
			int rowCount = pluginModel.getRowCount();
			for (int i=0 ; i<rowCount ; i++)
			{
				Entry ent = pluginModel.getEntry(i);
				String name = ent.name;
				if (name != null)
				{
					pluginModel.setValueAt(selectedPlugins.contains(name), i, 0);
				}
				else
				{
					String jarPath = ent.jar;
					String jarName = jarPath.substring(1 + jarPath.lastIndexOf(File.separatorChar));
					try
					{
						pluginModel.setValueAt(jarNames.contains(jarName), i, 0);
					}
					catch (Exception e)
					{
						Log.log(Log.WARNING, this, "Exception thrown loading: " + jarName);
					}
				}
			}
		}
		catch (Exception e)
		{
			Log.log(Log.ERROR, this, "Loading Pluginset Error", e);
			return false;
		}
		pluginModel.update();
		return true;
	}//}}}

	//{{{ getDeclaredJars() method
	/**
	 * Returns a collection of declared jars in the plugin.
	 * If the plugin is loaded use {@link org.gjt.sp.jedit.PluginJAR#getRequiredJars()}
	 * instead
	 *
	 * @param jarName the jar name of the plugin
	 * @return a collection containing jars path
	 * @throws IOException if jEdit cannot generate cache
	 * @since jEdit 4.3pre12
	 */
	private static Collection<String> getDeclaredJars(String jarName) throws IOException
	{
		Collection<String> jarList = new ArrayList<String>();
		PluginJAR pluginJAR = new PluginJAR(new File(jarName));
		PluginJAR.PluginCacheEntry pluginCacheEntry = PluginJAR.getPluginCache(pluginJAR);
		if (pluginCacheEntry == null)
		{
			pluginCacheEntry = pluginJAR.generateCache();
		}
		Properties cachedProperties = pluginCacheEntry.cachedProperties;

		String jars = cachedProperties.getProperty("plugin." + pluginCacheEntry.pluginClass + ".jars");

		if (jars != null)
		{
			String dir = MiscUtilities.getParentOfPath(pluginJAR.getPath());
			StringTokenizer st = new StringTokenizer(jars);
			while (st.hasMoreTokens())
			{
				String _jarPath = MiscUtilities.constructPath(dir, st.nextToken());
				if (new File(_jarPath).exists())
					jarList.add(_jarPath);
			}
		}
		jarList.add(jarName);
		return jarList;
	}//}}}

	//{{{ Inner classes

	//{{{ KeyboardCommand enum
	private enum KeyboardCommand
	{
		NONE,
		TAB_OUT_FORWARD,
		TAB_OUT_BACK,
		EDIT_PLUGIN,
		CLOSE_PLUGIN_MANAGER
	} //}}}

	//{{{ Entry class
	static class Entry
	{
		static final String ERROR = "error";
		static final String LOADED = "loaded";
		static final String NOT_LOADED = "not-loaded";

		final String status;
		/** The jar path. */
		final String jar;

		String clazz, name, version, author, docs;
		/** The description property of the plugin. */
		String description;
		EditPlugin plugin;
		/**
		 * The jars referenced in the props file of the plugin.
		 * plugin.clazz.jars property and
		 * plugin.clazz.files property
		 */
		final List<String> jars;

		/** The data size. */
		String dataSize;

		/**
		 * Constructor used for jars that aren't loaded.
		 *
		 * @param jar jar file name
		 */
		Entry(String jar)
		{
			jars = new LinkedList<String>();
			this.jar = jar;
			jars.add(this.jar);
			status = NOT_LOADED;
		}

		/**
		 * Constructor used for loaded jars.
		 *
		 * @param jar the pluginJar
		 */
		Entry(PluginJAR jar)
		{
			jars = new LinkedList<String>();
			this.jar = jar.getPath();
			jars.add(this.jar);

			plugin = jar.getPlugin();
			if(plugin != null)
			{
				status = plugin instanceof EditPlugin.Broken
					? ERROR : LOADED;
				clazz = plugin.getClassName();
				name = jEdit.getProperty("plugin."+clazz+".name");
				version = jEdit.getProperty("plugin."+clazz+".version");
				author = jEdit.getProperty("plugin."+clazz+".author");
				docs = jEdit.getProperty("plugin."+clazz+".docs");
				description = jEdit.getProperty("plugin."+clazz+".description");
				String jarsProp = jEdit.getProperty("plugin."+clazz+".jars");

				if(jarsProp != null)
				{
					String directory = MiscUtilities.getParentOfPath(this.jar);

					StringTokenizer st = new StringTokenizer(jarsProp);
					while(st.hasMoreElements())
					{
						jars.add(MiscUtilities.constructPath(
							directory,st.nextToken()));
					}
				}

				String filesProp = jEdit.getProperty("plugin."+clazz+".files");

				if(filesProp != null)
				{
					String directory = MiscUtilities.getParentOfPath(this.jar);

					StringTokenizer st = new StringTokenizer(filesProp);
					while(st.hasMoreElements())
					{
						jars.add(MiscUtilities.constructPath(
							directory,st.nextToken()));
					}
				}
			}
			else
			{
				status = LOADED;
			}
		}
	} //}}}

	//{{{ PluginTableModel class
	private class PluginTableModel extends AbstractTableModel
	{
		private final List<Entry> entries;
		private int sortType = EntryCompare.NAME;
		private ConcurrentHashMap<String, Object> unloaded;
		// private HashSet<String> unloaded;

		//{{{ Constructor
		PluginTableModel()
		{
			entries = new ArrayList<Entry>();
		} //}}}

		//{{{ getColumnCount() method
		public int getColumnCount()
		{
			return 5;
		} //}}}

		//{{{ getColumnClass() method
		@Override
		public Class getColumnClass(int columnIndex)
		{
			switch (columnIndex)
			{
				case 0: return Boolean.class;
				default: return Object.class;
			}
		} //}}}

		//{{{ getColumnName() method
		@Override
		public String getColumnName(int column)
		{
			switch (column)
			{
				case 0:
					return " ";
				case 1:
					return jEdit.getProperty("manage-plugins.info.name");
				case 2:
					return jEdit.getProperty("manage-plugins.info.version");
				case 3:
					return jEdit.getProperty("manage-plugins.info.status");
				case 4:
					return jEdit.getProperty("manage-plugins.info.data");
				default:
					throw new Error("Column out of range");
			}
		} //}}}

		//{{{ getEntry() method
		public Entry getEntry(int rowIndex)
		{
			return entries.get(rowIndex);
		} //}}}

		//{{{ getRowCount() method
		public int getRowCount()
		{
			return entries.size();
		} //}}}

		//{{{ getValueAt() method
		public Object getValueAt(int rowIndex,int columnIndex)
		{
			Entry entry = entries.get(rowIndex);
			switch (columnIndex)
			{
				case 0:
					return Boolean.valueOf(!entry.status.equals(Entry.NOT_LOADED));
				case 1:
					if(entry.name == null)
					{
						return MiscUtilities.getFileName(entry.jar);
					}
					else
					{
						return entry.name;
					}
				case 2:
					return entry.version;
				case 3:
					return jEdit.getProperty("plugin-manager.status." + entry.status);
				case 4:
					if (entry.dataSize == null && entry.plugin != null)
					{
						File pluginDirectory = entry.plugin.getPluginHome();
						if (null == pluginDirectory)
						{
							return null;
						}
						if (pluginDirectory.exists())
						{
							entry.dataSize = MiscUtilities.formatFileSize(IOUtilities.fileLength(pluginDirectory));
						}
						else
						{
							if (jEdit.getBooleanProperty("plugin." + entry.clazz + ".usePluginHome"))
							{
								entry.dataSize = MiscUtilities.formatFileSize(0);
							}
							else
							{
								entry.dataSize = jEdit.getProperty("manage-plugins.data-size.unknown");
							}

						}
					}
					return entry.dataSize;
				default:
					throw new Error("Column out of range");
			}
		} //}}}

		//{{{ isCellEditable() method
		@Override
		public boolean isCellEditable(int rowIndex, int columnIndex)
		{
			return columnIndex == 0;
		} //}}}

		//{{{ setValueAt() method
		@Override
		public void setValueAt(Object value, int rowIndex,
			int columnIndex)
		{
			Entry entry = entries.get(rowIndex);
			if(columnIndex == 0)
			{
				PluginJAR jar = jEdit.getPluginJAR(entry.jar);
				if(jar == null)
				{
					if(value.equals(Boolean.FALSE))
						return;

					PluginJAR.load(entry.jar, true);
				}
				else
				{
					if(value.equals(Boolean.TRUE))
						return;

					unloadPluginJARWithDialog(jar);
				}
			}

			update();
		} //}}}

		//{{{ setSortType() method
		public void setSortType(int type)
		{
			sortType = type;
			sort(type);
		} //}}}

		//{{{ sort() method
		public void sort(int type)
		{
			List<String> savedSelection = new ArrayList<String>();
			saveSelection(savedSelection);
			Collections.sort(entries,new EntryCompare(type));
			fireTableChanged(new TableModelEvent(this));
			restoreSelection(savedSelection);
		}
		//}}}

		//{{{ update() method
		public void update()
		{
			List<String> savedSelection = new ArrayList<String>();
			saveSelection(savedSelection);
			entries.clear();

			String systemJarDir = MiscUtilities.constructPath(
				jEdit.getJEditHome(),"jars");
			String userJarDir;
			String settingsDirectory = jEdit.getSettingsDirectory();
			if(settingsDirectory == null)
				userJarDir = null;
			else
			{
				userJarDir = MiscUtilities.constructPath(
					settingsDirectory,"jars");
			}

			PluginJAR[] plugins = jEdit.getPluginJARs();
			for(int i = 0; i < plugins.length; i++)
			{
				String path = plugins[i].getPath();
				if(path.startsWith(systemJarDir)
					|| (userJarDir != null
					&& path.startsWith(userJarDir)))
				{
					Entry e = new Entry(plugins[i]);
					if(!hideLibraries.isSelected()
						|| e.clazz != null)
					{
						entries.add(e);
					}
				}
			}

			String[] newPlugins = jEdit.getNotLoadedPluginJARs();
			for(int i = 0; i < newPlugins.length; i++)
			{
				Entry e = new Entry(newPlugins[i]);
				entries.add(e);
			}

			sort(sortType);
			restoreSelection(savedSelection);
		} //}}}

		//{{{ unloadPluginJARWithDialog() method
		// Perhaps this should also be moved to PluginJAR class?
		private void unloadPluginJARWithDialog(PluginJAR jar)
		{
			// unloaded = new HashSet<String>();
			unloaded = new ConcurrentHashMap<String, Object>();
			String[] dependents = jar.getDependentPlugins();
			if(dependents.length == 0)
				unloadPluginJAR(jar);
			else
			{
				List<String> closureSet = new LinkedList<String>();
				PluginJAR.transitiveClosure(dependents, closureSet);
				List<String> listModel = new ArrayList<String>();
				listModel.addAll(closureSet);
				Collections.sort(listModel, new StandardUtilities.StringCompare<String>(true));

				int button = GUIUtilities.listConfirm(window,"plugin-manager.dependency",
					new String[] { jar.getFile().getName() }, listModel.toArray());
				if(button == JOptionPane.YES_OPTION)
					unloadPluginJAR(jar);
			}
		} //}}}

		//{{{ unloadPluginJAR() method
		private void unloadPluginJAR(PluginJAR jar)
		{
			String[] dependents = jar.getDependentPlugins();
			for (String dependent : dependents)
			{
				if (!unloaded.containsKey(dependent))
				{
					unloaded.put(dependent, Boolean.TRUE);
					PluginJAR _jar = jEdit.getPluginJAR(dependent);
					if(_jar != null)
						unloadPluginJAR(_jar);
				}
			}
			jEdit.removePluginJAR(jar,false);
			jEdit.setBooleanProperty("plugin-blacklist."+MiscUtilities.getFileName(jar.getPath()),true);
		} //}}}

		//{{{ saveSelection() method
		/**
		 * Save the selection in the given list.
		 * The list will be filled with the jar names of the selected entries
		 *
		 * @param savedSelection the list where to save the selection
		 */
		public void saveSelection(List<String> savedSelection)
		{
			if (table != null)
			{
				int[] rows = table.getSelectedRows();
				for (int i=0 ; i<rows.length ; i++)
				{
					savedSelection.add(entries.get(rows[i]).jar);
				}
			}
		} //}}}

		//{{{ restoreSelection() method
		/**
		 * Restore the selection.
		 *
		 * @param savedSelection the selection list that contains the jar names of the selected items
		 */
		public void restoreSelection(List<String> savedSelection)
		{
			if (null != table)
			{
				table.setColumnSelectionInterval(0,0);
				if (!savedSelection.isEmpty())
				{
					int i = 0;
					int rowCount = getRowCount();
					for ( ; i<rowCount ; i++)
					{
						if (savedSelection.contains(entries.get(i).jar))
						{
							table.setRowSelectionInterval(i,i);
							break;
						}
					}
					ListSelectionModel lsm = table.getSelectionModel();
					for ( ; i<rowCount ; i++)
					{
						if (savedSelection.contains(entries.get(i).jar))
						{
							lsm.addSelectionInterval(i,i);
						}
					}
				}
				else
				{
					if (table.getRowCount() != 0)
						table.setRowSelectionInterval(0,0);
					JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
					scrollbar.setValue(scrollbar.getMinimum());
				}
			}
		} //}}}
	} //}}}

	//{{{ TextRenderer class
	private class TextRenderer extends DefaultTableCellRenderer
	{
		private final DefaultTableCellRenderer tcr;

		TextRenderer(DefaultTableCellRenderer tcr)
		{
			this.tcr = tcr;
		}

		@Override
		public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column)
		{
			Entry entry = pluginModel.getEntry(row);
			if (entry.status.equals(Entry.ERROR))
				tcr.setForeground(Color.red);
			else
				tcr.setForeground(UIManager.getColor("Table.foreground"));
			return tcr.getTableCellRendererComponent(table,value,isSelected,false,row,column);
		}
	} //}}}

	//{{{ HideLibrariesButton class
	private class HideLibrariesButton extends JCheckBox implements ActionListener
	{
		HideLibrariesButton()
		{
			super(jEdit.getProperty("plugin-manager.hide-libraries"));
			setSelected(jEdit.getBooleanProperty(
				"plugin-manager.hide-libraries.toggle"));
			addActionListener(this);
		}

		public void actionPerformed(ActionEvent evt)
		{
			jEdit.setBooleanProperty(
				"plugin-manager.hide-libraries.toggle",
				isSelected());
			ManagePanel.this.update();
		}
	} //}}}

	//{{{ RestoreButton class
	/**
	 * Permits the user to restore the state of the ManagePanel
	 * based on a PluginSet.
	 *
	 * Selects all loaded plugins that appear in an .XML file, and deselects
	 * all others, and also sets the pluginset to that .XML file. Does not install any plugins
	 * that were not previously installed.
	 *
	 * @since jEdit 4.3pre10
	 * @author Alan Ezust
	 */
	private class RestoreButton extends RolloverButton implements ActionListener
	{
		RestoreButton()
		{
			setIcon(GUIUtilities.loadIcon(jEdit.getProperty("manage-plugins.restore.icon")));
			addActionListener(this);
			setToolTipText("Choose a PluginSet, select/deselect plugins based on set.");
		}

		public void actionPerformed(ActionEvent e)
		{
			String path = jEdit.getProperty(PluginManager.PROPERTY_PLUGINSET,
				jEdit.getSettingsDirectory() + File.separator);
			String[] selectedFiles = GUIUtilities.showVFSFileDialog(ManagePanel.this.window,
				jEdit.getActiveView(), path, VFSBrowser.OPEN_DIALOG, false);
			if (selectedFiles == null || selectedFiles.length != 1) return;
			path = selectedFiles[0];
			boolean success = loadPluginSet(path);
			if (success)
			{
				jEdit.setProperty(PluginManager.PROPERTY_PLUGINSET, path);
				EditBus.send(new PropertiesChanged(PluginManager.getInstance()));
			}

		}
	}//}}}

	//{{{ SaveButton class
	/**
	 * Permits the user to save the state of the ManagePanel,
	 * which in this case, is nothing more than a list of
	 * all plugins currently loaded.
	 * @since jEdit 4.3pre10
	 * @author Alan Ezust
	 */
	private class SaveButton extends RolloverButton implements ActionListener
	{
		SaveButton()
		{
			setIcon(GUIUtilities.loadIcon(jEdit.getProperty("manage-plugins.save.icon")));
			setToolTipText("Save Currently Checked Plugins Set");
			addActionListener(this);
			setEnabled(true);
		}

		void saveState(String vfsURL, List<Entry> pluginList)
		{
			StringBuilder sb = new StringBuilder("<pluginset>\n ");

			for (Entry entry: pluginList)
			{
				String jarName = entry.jar.substring(1+entry.jar.lastIndexOf(File.separatorChar));
				sb.append("   <plugin name=\"").append(entry.name).append("\" jar=\"");
				sb.append(jarName).append("\" />\n ");
			}
			sb.append("</pluginset>\n");

			VFS vfs = VFSManager.getVFSForPath(vfsURL);
			Object session = vfs.createVFSSession(vfsURL, ManagePanel.this);
			Writer writer = null;
			try
			{
				OutputStream os = vfs._createOutputStream(session, vfsURL, ManagePanel.this);
				writer = new BufferedWriter(new OutputStreamWriter(os));
				writer.write(sb.toString());
			}
			catch (Exception e)
			{
				Log.log(Log.ERROR, this, "Saving State Error", e);
			}
			finally
			{
				IOUtilities.closeQuietly(writer);
			}

		}

		public void actionPerformed(ActionEvent e)
		{
			String path = jEdit.getProperty("plugin-manager.pluginset.path", jEdit.getSettingsDirectory() + File.separator);
			VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
				ManagePanel.this.window, jEdit.getActiveView(),
				path, VFSBrowser.SAVE_DIALOG, false , true);
			String[] fileselections = fileChooser.getSelectedFiles();
			List<Entry> pluginSelections = new ArrayList<Entry>();
			if (fileselections == null || fileselections.length != 1) return;

			PluginJAR[] jars = jEdit.getPluginJARs();
			for (PluginJAR jar : jars)
			{
				if (jar.getPlugin() != null)
				{
					Entry entry = new Entry (jar);
					pluginSelections.add(entry);
				}
			}
			saveState(fileselections[0], pluginSelections);
			jEdit.setProperty("plugin-manager.pluginset.path", fileselections[0]);
			EditBus.send(new PropertiesChanged(PluginManager.getInstance()));
		}
	}//}}}

	//{{{ RemoveButton class
	/**
	 * The Remove button is the button pressed to remove the selected
	 * plugin.
	 */
	private class RemoveButton extends JButton implements ListSelectionListener, ActionListener
	{
		RemoveButton()
		{
			super(jEdit.getProperty("manage-plugins.remove"));
			table.getSelectionModel().addListSelectionListener(this);
			addActionListener(this);
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent evt)
		{
			int[] selected = table.getSelectedRows();

			List<String> listModel = new LinkedList<String>();
			Roster roster = new Roster();
			Set<String> jarsToRemove = new HashSet<String>();
			// this one will contains the loaded jars to remove. They
			// are the only one we need to check to unload plugins
			// that depends on them
			Set<String> loadedJarsToRemove = new HashSet<String>();
			for(int i = 0; i < selected.length; i++)
			{
				Entry entry = pluginModel.getEntry(selected[i]);
				if (entry.status.equals(Entry.NOT_LOADED))
				{
					if (entry.jar != null)
					{
						try
						{
							Collection<String> jarList = getDeclaredJars(entry.jar);
							jarsToRemove.addAll(jarList);
						}
						catch (IOException e)
						{
							Log.log(Log.ERROR, this, e);
						}
					}
				}
				else
				{
					jarsToRemove.addAll(entry.jars);
					loadedJarsToRemove.addAll(entry.jars);
				}
				table.getSelectionModel().removeSelectionInterval(selected[i], selected[i]);
			}

			for (String jar : jarsToRemove)
			{
				listModel.add(jar);
				roster.addRemove(jar);
			}

			int button = GUIUtilities.listConfirm(window,
				"plugin-manager.remove-confirm",
				null,listModel.toArray());
			if(button == JOptionPane.YES_OPTION)
			{

				List<String> closureSet = new ArrayList<String>();
				PluginJAR.transitiveClosure(loadedJarsToRemove.toArray(new String[loadedJarsToRemove.size()]), closureSet);
				closureSet.removeAll(listModel);
				if (closureSet.isEmpty())
				{
					button = JOptionPane.YES_OPTION;
				}
				else
				{
					button = GUIUtilities.listConfirm(window,"plugin-manager.remove-dependencies",
						null, closureSet.toArray());
					Collections.sort(closureSet, new StandardUtilities.StringCompare<String>(true));
				}
				if(button == JOptionPane.YES_OPTION)
				{
					for (String jarName:closureSet)
					{
						PluginJAR pluginJAR = jEdit.getPluginJAR(jarName);
						jEdit.removePluginJAR(pluginJAR, false);
					}
					roster.performOperationsInAWTThread(window);
					pluginModel.update();
					if (table.getRowCount() != 0)
					{
						table.setRowSelectionInterval(0,0);
					}
					table.setColumnSelectionInterval(0,0);
					JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
					scrollbar.setValue(scrollbar.getMinimum());
				}
			}
		}

		public void valueChanged(ListSelectionEvent e)
		{
			if (table.getSelectedRowCount() == 0)
				setEnabled(false);
			else
				setEnabled(true);
		}
	} //}}}

	//{{{ FindOrphanActionListener class
	private class FindOrphan extends JButton implements ActionListener
	{
		private FindOrphan()
		{
			super(jEdit.getProperty("plugin-manager.findOrphan.label"));
			addActionListener(this);
		}

		public void actionPerformed(ActionEvent e)
		{
			PluginJAR[] pluginJARs = jEdit.getPluginJARs();
			Set<String> neededJars = new HashSet<String>();

			Map<String, String> jarlibs = new HashMap<String, String>();
			for (PluginJAR pluginJAR : pluginJARs)
			{
				EditPlugin plugin = pluginJAR.getPlugin();
				if (plugin == null)
				{
					jarlibs.put(new File(pluginJAR.getPath()).getName(), pluginJAR.getPath());
				}
				else
				{
					Set<String> strings = plugin.getPluginJAR().getRequiredJars();
					for (String string : strings)
					{
						neededJars.add(new File(string).getName());
					}
				}
			}

			String[] notLoadedJars = jEdit.getNotLoadedPluginJARs();
			for (int i = 0; i < notLoadedJars.length; i++)
			{
				PluginJAR pluginJAR = new PluginJAR(new File(notLoadedJars[i]));
				PluginJAR.PluginCacheEntry pluginCacheEntry = PluginJAR.getPluginCache(pluginJAR);
				try
				{
					if (pluginCacheEntry == null)
					{
						pluginCacheEntry = pluginJAR.generateCache();
					}
					if (pluginCacheEntry.pluginClass == null)
					{
						// Not a plugin
						jarlibs.put(new File(notLoadedJars[i]).getName(), notLoadedJars[i]);
						continue;
					}

					Properties cachedProperties = pluginCacheEntry.cachedProperties;

					String jars = cachedProperties.getProperty("plugin." + pluginCacheEntry.pluginClass + ".jars");

					if (jars != null)
					{
						StringTokenizer st = new StringTokenizer(jars);
						while (st.hasMoreTokens())
						{
							neededJars.add(st.nextToken());
						}
					}
				}
				catch (IOException e1)
				{
					Log.log(Log.ERROR, this, e);
				}
			}

			List<String> removingJars = new ArrayList<String>();
			Set<String> jarlibsKeys = jarlibs.keySet();
			for (String jar : jarlibsKeys)
			{
				if (!neededJars.contains(jar))
				{
					removingJars.add(jar);
					Log.log(Log.MESSAGE, this, "It seems that this jar do not belong to any plugin " +jar);
				}
			}
			if(removingJars.isEmpty())
			{
				GUIUtilities.message(ManagePanel.this, "plugin-manager.noOrphan", null);
				return;
			}

			String[] strings = removingJars.toArray(new String[removingJars.size()]);
			List<String> mustRemove = new ArrayList<String>();
			int ret = GUIUtilities.listConfirm(ManagePanel.this,
							   "plugin-manager.findOrphan",
							   null,
							   strings,
							   mustRemove);
			if (ret != JOptionPane.OK_OPTION || mustRemove.isEmpty())
				return;

			Roster roster = new Roster();
			for (int i = 0; i < mustRemove.size(); i++)
			{
				String entry = mustRemove.get(i);
				roster.addRemove(jarlibs.get(entry));
			}

			roster.performOperationsInAWTThread(window);
			pluginModel.update();
			if (table.getRowCount() != 0)
			{
				table.setRowSelectionInterval(0,0);
			}
			table.setColumnSelectionInterval(0,0);
			JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
			scrollbar.setValue(scrollbar.getMinimum());
			table.repaint();
		}
	} //}}}

	//{{{ HelpButton class
	private class HelpButton extends JButton implements ListSelectionListener, ActionListener
	{
		private URL docURL;

		HelpButton()
		{
			super(jEdit.getProperty("manage-plugins.help"));
			table.getSelectionModel().addListSelectionListener(this);
			addActionListener(this);
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent evt)
		{
			new HelpViewer(docURL);
		}

		public void valueChanged(ListSelectionEvent e)
		{
			if (table.getSelectedRowCount() == 1)
			{
				try
				{
					Entry entry = pluginModel.getEntry(table.getSelectedRow());
					String label = entry.clazz;
					String docs = entry.docs;
					if (label != null)
					{
						EditPlugin plug = jEdit.getPlugin(label, false);
						PluginJAR jar = null;
						if (plug != null) jar = plug.getPluginJAR();
						if(jar != null && docs != null)
						{
							URL url = jar.getClassLoader().getResource(docs);
							if(url != null)
							{
								docURL = url;
								setEnabled(true);
								return;
							}
						}
					}
				}
				catch (Exception ex)
				{
					Log.log(Log.ERROR, this, "ManagePanel HelpButton Update", ex);
				}
			}
			setEnabled(false);
		}
	} //}}}

	//{{{ EntryCompare class
	private static class EntryCompare implements Comparator<Entry>
	{
		public static final int NAME = 1;
		public static final int STATUS = 2;

		private final int type;

		EntryCompare(int type)
		{
			this.type = type;
		}

		public int compare(Entry e1, Entry e2)
		{
			if (type == NAME)
				return compareNames(e1,e2);
			else
			{
				int result;
				if ((result = e1.status.compareToIgnoreCase(e2.status)) == 0)
					return compareNames(e1,e2);
				return result;
			}
		}

		private static int compareNames(Entry e1, Entry e2)
		{
			String s1;
			if(e1.name == null)
				s1 = MiscUtilities.getFileName(e1.jar);
			else
				s1 = e1.name;
			String s2;
			if(e2.name == null)
				s2 = MiscUtilities.getFileName(e2.jar);
			else
				s2 = e2.name;

			return s1.compareToIgnoreCase(s2);
		}
	} //}}}

	//{{{ HeaderMouseHandler class
	private class HeaderMouseHandler extends MouseAdapter
	{
		@Override
		public void mouseClicked(MouseEvent evt)
		{
			if (evt.getSource() == table.getTableHeader())
			{
				switch(table.getTableHeader().columnAtPoint(evt.getPoint()))
				{
					case 1:
						pluginModel.setSortType(EntryCompare.NAME);
						break;
					case 3:
						pluginModel.setSortType(EntryCompare.STATUS);
						break;
					default:
						break;
				}
			}
			else
			{
				if (GUIUtilities.isPopupTrigger(evt))
				{
					int row = table.rowAtPoint(evt.getPoint());
					if (row != -1 &&
					    !table.isRowSelected(row))
					{
						table.setRowSelectionInterval(row,row);
					}
					if (popup == null)
					{
						popup = new JPopupMenu();
						JMenuItem item = GUIUtilities.loadMenuItem("plugin-manager.cleanup");
						item.addActionListener(new CleanupActionListener());
						popup.add(item);
					}
					GUIUtilities.showPopupMenu(popup, table, evt.getX(), evt.getY());
				}
			}
		}

		//{{{ CleanupActionListener class
		private class CleanupActionListener implements ActionListener
		{
			public void actionPerformed(ActionEvent e)
			{

				int[] ints = table.getSelectedRows();
				List<String> list = new ArrayList<String>(ints.length);
				List<Entry> entries = new ArrayList<Entry>(ints.length);
				for (int i = 0; i < ints.length; i++)
				{
					Entry entry = pluginModel.getEntry(ints[i]);
					if (entry.plugin != null)
					{
						list.add(entry.name);
						entries.add(entry);
					}
				}

				String[] strings = list.toArray(new String[list.size()]);
				int ret = GUIUtilities.listConfirm(ManagePanel.this,
								   "plugin-manager.cleanup",
								   null,
								   strings);
				if (ret != JOptionPane.OK_OPTION)
					return;

				for (int i = 0; i < entries.size(); i++)
				{
					Entry entry = entries.get(i);
					File path = entry.plugin.getPluginHome();
					Log.log(Log.NOTICE, this, "Removing data of plugin " + entry.name + " home="+path);
					FileVFS.recursiveDelete(path);
					entry.dataSize = null;
				}
				table.repaint();
			}
		} //}}}
	} //}}}

	//{{{ KeyboardAction class
	private class KeyboardAction extends AbstractAction
	{
		private KeyboardCommand command = KeyboardCommand.NONE;

		KeyboardAction(KeyboardCommand command)
		{
			this.command = command;
		}

		public void actionPerformed(ActionEvent evt)
		{
			switch (command)
			{
			case TAB_OUT_FORWARD:
				KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
				break;
			case TAB_OUT_BACK:
				KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
				break;
			case EDIT_PLUGIN:
				int[] rows = table.getSelectedRows();
				for (int i = 0; i < rows.length; i++)
				{
					Object st = pluginModel.getValueAt(rows[i], 0);
					pluginModel.setValueAt(st.equals(Boolean.FALSE), rows[i], 0);
				}
				break;
			case CLOSE_PLUGIN_MANAGER:
				window.ok();
				break;
			default:
				throw new InternalError();
			}
		}
	} //}}}

	//{{{ TableFocusHandler class
	private class TableFocusHandler extends FocusAdapter
	{
		@Override
		public void focusGained(FocusEvent fe)
		{
			if (table.getSelectedRow() == -1)
			{
				table.setRowSelectionInterval(0,0);
				JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
				scrollbar.setValue(scrollbar.getMinimum());
			}
			if (table.getSelectedColumn() == -1)
			{
				table.setColumnSelectionInterval(0,0);
			}
		}
	} //}}}

	//{{{ TableSelectionListener class
	private class TableSelectionListener implements ListSelectionListener
	{
		public void valueChanged(ListSelectionEvent e)
		{
			int row = table.getSelectedRow();
			if (row != -1)
			{
				Entry entry = pluginModel.getEntry(row);
				pluginDetailPanel.setPlugin(entry);


public abstract class MatchingTask extends Task {

    protected boolean useDefaultExcludes = true;
    protected FileSet fileset = new FileSet();

    /**
     * add a name entry on the include list
     */
    public PatternSet.NameEntry createInclude() {
        return fileset.createInclude();
    }

    /**
     * add a name entry on the exclude list
     */
    public PatternSet.NameEntry createExclude() {
        return fileset.createExclude();
    }

    /**
     * add a set of patterns
     */
    public PatternSet createPatternSet() {
        return fileset.createPatternSet();
    }

    /**
     * Sets the set of include patterns. Patterns may be separated by a comma
     * or a space.
     *
     * @param includes the string containing the include patterns
     */
    public void setIncludes(String includes) {
        fileset.setIncludes(includes);
    }

    /**
     * Set this to be the items in the base directory that you want to be
     * included. You can also specify "*" for the items (ie: items="*")
     * and it will include all the items in the base directory.
     *
     * @param itemString the string containing the files to include.
     */
    public void XsetItems(String itemString) {
        log("The items attribute is deprecated. " +
            "Please use the includes attribute.",
            Project.MSG_WARN);
        if (itemString == null || itemString.equals("*")
            || itemString.equals(".")) {
            createInclude().setName("**");
        } else {
            StringTokenizer tok = new StringTokenizer(itemString, ", ");
            while (tok.hasMoreTokens()) {
                String pattern = tok.nextToken().trim();
                if (pattern.length() > 0) {
                    createInclude().setName(pattern+"/**");
                }
            }
        }
    }

    /**
     * Sets the set of exclude patterns. Patterns may be separated by a comma
     * or a space.
     *
     * @param excludes the string containing the exclude patterns
     */
    public void setExcludes(String excludes) {
        fileset.setExcludes(excludes);
    }

    /**
     * List of filenames and directory names to not include. They should be
     * either , or " " (space) separated. The ignored files will be logged.
     *
     * @param ignoreString the string containing the files to ignore.
     */
    public void XsetIgnore(String ignoreString) {
        log("The ignore attribute is deprecated." +
            "Please use the excludes attribute.",
            Project.MSG_WARN);
        if (ignoreString != null && ignoreString.length() > 0) {
            Vector tmpExcludes = new Vector();
            StringTokenizer tok = new StringTokenizer(ignoreString, ", ", false);
            while (tok.hasMoreTokens()) {
                createExclude().setName("**/"+tok.nextToken().trim()+"/**");
            }
        }
    }

    /**
     * Sets whether default exclusions should be used or not.
     *
     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
     *                           should be used, "false"|"off"|"no" when they
     *                           shouldn't be used.
     */
    public void setDefaultexcludes(boolean useDefaultExcludes) {
        this.useDefaultExcludes = useDefaultExcludes;
    }

    /**
     * Returns the directory scanner needed to access the files to process.
     */
    protected DirectoryScanner getDirectoryScanner(File baseDir) {
        fileset.setDir(baseDir);
        fileset.setDefaultexcludes(useDefaultExcludes);
        return fileset.getDirectoryScanner(project);
    }

    /**
     * Sets the name of the file containing the includes patterns.
     *
     * @param includesfile A string containing the filename to fetch
     * the include patterns from.
     */
     public void setIncludesfile(File includesfile) {
         fileset.setIncludesfile(includesfile);
     }

    /**
     * Sets the name of the file containing the includes patterns.
     *
     * @param excludesfile A string containing the filename to fetch
     * the include patterns from.
     */
     public void setExcludesfile(File excludesfile) {
         fileset.setExcludesfile(excludesfile);


org.apache.tools.ant.types.PatternSet

public class PatternSet extends DataType {
    private Vector includeList = new Vector();
    private Vector excludeList = new Vector();
    private Vector includesFileList = new Vector();
    private Vector excludesFileList = new Vector();

    /**
     * inner class to hold a name on list.  "If" and "Unless" attributes
     * may be used to invalidate the entry based on the existence of a
     * property (typically set thru the use of the Available task).
     */
    public class NameEntry {
        private String name;
        private String ifCond;
        private String unlessCond;

        public void setName(String name) {
            this.name = name;
        }

        public void setIf(String cond) {
            ifCond = cond;
        }

        public void setUnless(String cond) {
            unlessCond = cond;
        }

        public String getName() {
            return name;
        }

        public String evalName(Project p) {
            return valid(p) ? name : null;
        }

        private boolean valid(Project p) {
            if (ifCond != null && p.getProperty(ifCond) == null) {
                return false;
            } else if (unlessCond != null && p.getProperty(unlessCond) != null) {
                return false;
            }
            return true;
        }

        public String toString() {
            StringBuffer buf = new StringBuffer(name);
            if ((ifCond != null) || (unlessCond != null)) {
                buf.append(":");
                String connector = "";

                if (ifCond != null) {
                    buf.append("if->");
                    buf.append(ifCond);
                    connector = ";";
                }
                if (unlessCond != null) {
                    buf.append(connector);
                    buf.append("unless->");
                    buf.append(unlessCond);
                }
            }

            return buf.toString();
        }
    }

    public PatternSet() {
        super();
    }

    /**
     * Makes this instance in effect a reference to another PatternSet
     * instance.
     *
     *
You must not set another attribute or nest elements inside
     * this element if you make it a reference.

     */
    public void setRefid(Reference r) throws BuildException {
        if (!includeList.isEmpty() || !excludeList.isEmpty()) {
            throw tooManyAttributes();
        }
        super.setRefid(r);
    }

    /**
     * add a name entry on the include list
     */
    public NameEntry createInclude() {
        if (isReference()) {
            throw noChildrenAllowed();
        }
        return addPatternToList(includeList);
    }

    /**
     * add a name entry on the include files list
     */
    public NameEntry createIncludesFile() {
        if (isReference()) {
            throw noChildrenAllowed();
        }
        return addPatternToList(includesFileList);
    }

    /**
     * add a name entry on the exclude list
     */
    public NameEntry createExclude() {
        if (isReference()) {
            throw noChildrenAllowed();
        }
        return addPatternToList(excludeList);
    }

    /**
     * add a name entry on the exclude files list
     */
    public NameEntry createExcludesFile() {
        if (isReference()) {
            throw noChildrenAllowed();
        }
        return addPatternToList(excludesFileList);
    }

    /**
     * Sets the set of include patterns. Patterns may be separated by a comma
     * or a space.
     *
     * @param includes the string containing the include patterns
     */
    public void setIncludes(String includes) {
        if (isReference()) {
            throw tooManyAttributes();
        }
        if (includes != null && includes.length() > 0) {
            StringTokenizer tok = new StringTokenizer(includes, ", ", false);
            while (tok.hasMoreTokens()) {
                createInclude().setName(tok.nextToken());
            }
        }
    }

    /**
     * Sets the set of exclude patterns. Patterns may be separated by a comma
     * or a space.
     *
     * @param excludes the string containing the exclude patterns
     */
    public void setExcludes(String excludes) {
        if (isReference()) {
            throw tooManyAttributes();
        }
        if (excludes != null && excludes.length() > 0) {
            StringTokenizer tok = new StringTokenizer(excludes, ", ", false);
            while (tok.hasMoreTokens()) {
                createExclude().setName(tok.nextToken());
            }
        }
    }

    /**
     * add a name entry to the given list
     */
    private NameEntry addPatternToList(Vector list) {
        NameEntry result = new NameEntry();
        list.addElement(result);
        return result;
    }

    /**
     * Sets the name of the file containing the includes patterns.
     *
     * @param includesFile The file to fetch the include patterns from.
     */
     public void setIncludesfile(File includesFile) throws BuildException {
         if (isReference()) {
             throw tooManyAttributes();
         }
         createIncludesFile().setName(includesFile.getAbsolutePath());
     }

    /**
     * Sets the name of the file containing the excludes patterns.
     *
     * @param excludesFile The file to fetch the exclude patterns from.
     */
     public void setExcludesfile(File excludesFile) throws BuildException {
         if (isReference()) {
             throw tooManyAttributes();
         }
         createExcludesFile().setName(excludesFile.getAbsolutePath());
     }

    /**
     *  Reads path matching patterns from a file and adds them to the
     *  includes or excludes list (as appropriate).
     */
    private void readPatterns(File patternfile, Vector patternlist, Project p)
        throws BuildException {

        try {
            BufferedReader patternReader =
                new BufferedReader(new FileReader(patternfile));

            String line = patternReader.readLine();
            while (line != null) {
                if (line.length() > 0) {
                    line = ProjectHelper.replaceProperties(p, line,
                                                           p.getProperties());
                    addPatternToList(patternlist).setName(line);
                }
                line = patternReader.readLine();
            }
        } catch(IOException ioe)  {
            String msg = "An error occured while reading from pattern file: "
                + patternfile;
            throw new BuildException(msg, ioe);
        }
    }

    /**
     * Adds the patterns of the other instance to this set.
     */
    public void append(PatternSet other, Project p) {
        if (isReference()) {
            throw new BuildException("Cannot append to a reference");
        }

        String[] incl = other.getIncludePatterns(p);
        if (incl != null) {
            for (int i=0; i<incl.length; i++) {
                createInclude().setName(incl[i]);
            }
        }

        String[] excl = other.getExcludePatterns(p);
        if (excl != null) {
            for (int i=0; i<excl.length; i++) {
                createExclude().setName(excl[i]);
            }
        }
    }

    /**
     * Returns the filtered include patterns.
     */
    public String[] getIncludePatterns(Project p) {
        if (isReference()) {
            return getRef(p).getIncludePatterns(p);
        } else {
            readFiles(p);
            return makeArray(includeList, p);
        }
    }

    /**
     * Returns the filtered include patterns.
     */
    public String[] getExcludePatterns(Project p) {
        if (isReference()) {
            return getRef(p).getExcludePatterns(p);
        } else {
            readFiles(p);
            return makeArray(excludeList, p);
        }
    }

    /**
     * helper for FileSet.
     */
    boolean hasPatterns() {
        return includesFileList.size() > 0 || excludesFileList.size() > 0
            || includeList.size() > 0 || excludeList.size() > 0;
    }

    /**
     * Performs the check for circular references and returns the
     * referenced PatternSet.
     */
    private PatternSet getRef(Project p) {
        if (!checked) {
            Stack stk = new Stack();
            stk.push(this);
            dieOnCircularReference(stk, p);
        }

        Object o = ref.getReferencedObject(p);
        if (!(o instanceof PatternSet)) {
            String msg = ref.getRefId()+" doesn\'t denote a patternset";
            throw new BuildException(msg);
        } else {
            return (PatternSet) o;
        }
    }

    /**
     * Convert a vector of NameEntry elements into an array of Strings.
     */
    private String[] makeArray(Vector list, Project p) {
        if (list.size() == 0) return null;

        Vector tmpNames = new Vector();
        for (Enumeration e = list.elements() ; e.hasMoreElements() ;) {
            NameEntry ne = (NameEntry)e.nextElement();
            String pattern = ne.evalName(p);
            if (pattern != null && pattern.length() > 0) {
                tmpNames.addElement(pattern);
            }
        }

        String result[] = new String[tmpNames.size()];
        tmpNames.copyInto(result);
        return result;
    }

    /**
     * Read includesfile ot excludesfile if not already done so.
     */
    private void readFiles(Project p) {
        if (includesFileList.size() > 0) {
            Enumeration e = includesFileList.elements();
            while (e.hasMoreElements()) {
                NameEntry ne = (NameEntry)e.nextElement();
                String fileName = ne.evalName(p);
                if (fileName != null) {
                    File inclFile = p.resolveFile(fileName);
                    if (!inclFile.exists())
                        throw new BuildException("Includesfile "
                                                 + inclFile.getAbsolutePath()
                                                 + " not found.");
                    readPatterns(inclFile, includeList, p);
                }
            }
            includesFileList.removeAllElements();
        }

        if (excludesFileList.size() > 0) {
            Enumeration e = excludesFileList.elements();
            while (e.hasMoreElements()) {
                NameEntry ne = (NameEntry)e.nextElement();
                String fileName = ne.evalName(p);
                if (fileName != null) {
                    File exclFile = p.resolveFile(fileName);
                    if (!exclFile.exists())
                        throw new BuildException("Excludesfile "
                                                 + exclFile.getAbsolutePath()
                                                 + " not found.");
                    readPatterns(exclFile, excludeList, p);
                }
            }
            excludesFileList.removeAllElements();
        }
    }

    public String toString()
    {
        return "patternSet{ includes: " + includeList +
            " excludes: " + excludeList + " }";

FUNC_DECL RETURN IF CALL CALL THROW_RAISE CALL

FUNC_DECL RETURN VAR_DECL PARAM CALL CALL

FUNC_DECL IF PARAM CALL CALL CALL THROW_RAISE CALL CALL

FUNC_DECL IF PARAM CALL RETURN RETURN CALL CALL CALL CALL

    public PatternSet() {
        super();


public final class Template extends TopLevelElement {

    private boolean _disabled = false;
    private boolean _hasParams = false;
    private boolean _simplified = false;

    public boolean hasParams() {
	return _hasParams;
    }

    public void hasParams(boolean hasParams) {
	_hasParams = hasParams;
    }

    public boolean isSimplified() {
	return(_simplified);
    }

    public void setSimplified() {
	_simplified = true;
    }

    public void disable() {
	_disabled = true;
    }

    public boolean disabled() {
	return(_disabled);
    }

    public double getPriority() {
	return _priority;
    }

    public int getPosition() {
	return(_position);
    }

    public boolean isNamed() {
	return _name != null;
    }

    public Pattern getPattern() {
	return _pattern;
    }

    public QName getName() {
	return _name;
    }

    public void setName(QName qname) {
	if (_name == null) _name = qname;
    }

    public QName getModeName() {
	return _mode;
    }

    /**
     * Compare this template to another. First checks priority, then position.
     */
    public int compareTo(Object template) {
	Template other = (Template)template;
	if (_priority > other._priority)
	    return 1;
	else if (_priority < other._priority)
	    return -1;
	else if (_position > other._position)
	    return 1;
	else if (_position < other._position)
	    return -1;
	else
	    return 0;
    }

    public void display(int indent) {
	Util.println('\n');
	indent(indent);
	if (_name != null) {
	    indent(indent);
	    Util.println("name = " + _name);
	}
	else if (_pattern != null) {
	    indent(indent);
	    Util.println("match = " + _pattern.toString());
	}
	if (_mode != null) {
	    indent(indent);
	    Util.println("mode = " + _mode);
	}
	displayContents(indent + IndentIncrement);
    }

    private boolean resolveNamedTemplates(Template other, Parser parser) {

	if (other == null) return true;

	SymbolTable stable = parser.getSymbolTable();

	final int us = this.getImportPrecedence();
	final int them = other.getImportPrecedence();

	if (us > them) {
	    other.disable();
	    return true;
	}
	else if (us < them) {
	    stable.addTemplate(other);
	    this.disable();
	    return true;
	}
	else {
	    return false;
	}
    }

    private Stylesheet _stylesheet = null;

    public Stylesheet getStylesheet() {
	return _stylesheet;
    }

    public void parseContents(Parser parser) {

	final String name     = getAttribute("name");
	final String mode     = getAttribute("mode");
	final String match    = getAttribute("match");
	final String priority = getAttribute("priority");

	_stylesheet = super.getStylesheet();

	if (name.length() > 0) {
	    _name = parser.getQNameIgnoreDefaultNs(name);
	}

	if (mode.length() > 0) {
	    _mode = parser.getQNameIgnoreDefaultNs(mode);
	}

	if (match.length() > 0) {
	    _pattern = parser.parsePattern(this, "match", null);
	}

	if (priority.length() > 0) {
	    _priority = Double.parseDouble(priority);
	}
	else {
	    if (_pattern != null)
		_priority = _pattern.getPriority();
	    else
		_priority = Double.NaN;
	}

	_position = parser.getTemplateIndex();

	if (_name != null) {
	    Template other = parser.getSymbolTable().addTemplate(this);
	    if (!resolveNamedTemplates(other, parser)) {
		ErrorMsg err =
		    new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this);
		parser.reportError(Constants.ERROR, err);
	    }
	}

	parseChildren(parser);
    }

    /**
     * When the parser realises that it is dealign with a simplified stylesheet
     * it will create an empty Stylesheet object with the root element of the
     * stylesheet (a LiteralElement object) as its only child. The Stylesheet
     * object will then create this Template object and invoke this method to
     * force some specific behaviour. What we need to do is:
     *  o) create a pattern matching on the root node
     *  o) add the LRE root node (the only child of the Stylesheet) as our
     *     only child node
     *  o) set the empty Stylesheet as our parent
     *  o) set this template as the Stylesheet's only child
     */
    public void parseSimplified(Stylesheet stylesheet, Parser parser) {

	_stylesheet = stylesheet;
	setParent(stylesheet);

	_name = null;
	_mode = null;
	_priority = Double.NaN;
	_pattern = parser.parsePattern(this, "/");

	final Vector contents = _stylesheet.getContents();
	final SyntaxTreeNode root = (SyntaxTreeNode)contents.elementAt(0);

	if (root instanceof LiteralElement) {
	    addElement(root);
	    root.setParent(this);
	    contents.set(0, this);
	    parser.setTemplate(this);
	    root.parseContents(parser);
	    parser.setTemplate(null);
	}
    }

    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
	if (_pattern != null) {
	    _pattern.typeCheck(stable);
	}

	return typeCheckContents(stable);
    }

    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	if (_disabled) return;
	String className = classGen.getClassName();

	if (_compiled && isNamed()){
	    String methodName = Util.escape(_name.toString());
	    il.append(classGen.loadTranslet());
	    il.append(methodGen.loadDOM());
	    il.append(methodGen.loadIterator());
	    il.append(methodGen.loadHandler());
	    il.append(methodGen.loadCurrentNode());
	    il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
							 methodName,
							 "("
							 + DOM_INTF_SIG
							 + NODE_ITERATOR_SIG
							 + TRANSLET_OUTPUT_SIG
							 + "I)V")));
	    return;
	}

	if (_compiled) return;
	_compiled = true;

	final InstructionHandle start = il.getEnd();
	translateContents(classGen, methodGen);
	final InstructionHandle end = il.getEnd();
	il.setPositions(true);

    public QName getName() {
	return _name;

FUNC_DECL VAR_DECL VAR_DECL IF IF VAR_DECL IF VAR_DECL VAR_DECL PARAM PARAM CALL CALL ASSIGN RETURN BINARY_OP RETURN LITERAL_ANCHOR CALL CALL LITERAL_ANCHOR RETURN VAR_DECL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL BINARY_OP LITERAL_ANCHOR BINARY_OP BINARY_OP BINARY_OP LITERAL_ANCHOR


public class StickyLoadBalancer extends QueueLoadBalancer {
    private Expression<Exchange> correlationExpression;
    private QueueLoadBalancer loadBalancer;
    private int numberOfHashGroups = 64 * 1024;
    private Map<Object, Processor> stickyMap = new HashMap<Object, Processor>();

    public StickyLoadBalancer(Expression<Exchange> correlationExpression) {
        this(correlationExpression, new RoundRobinLoadBalancer());
    }

    public StickyLoadBalancer(Expression<Exchange> correlationExpression, QueueLoadBalancer loadBalancer) {
        this.correlationExpression = correlationExpression;
        this.loadBalancer = loadBalancer;
    }

    protected synchronized Processor chooseProcessor(List<Processor> processors, Exchange exchange) {
        Object value = correlationExpression.evaluate(exchange);
        Object key = getStickyKey(value);

        Processor processor;
        synchronized (stickyMap) {
            processor = stickyMap.get(key);
            if (processor == null) {
                processor = loadBalancer.chooseProcessor(processors, exchange);
                stickyMap.put(key, processor);
            }
        }
        return processor;
    }

    @Override
    public void removeProcessor(Processor processor) {
        synchronized (stickyMap) {
            Iterator<Map.Entry<Object, Processor>> iter = stickyMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<Object, Processor> entry = iter.next();
                if (processor.equals(entry.getValue())) {
                    iter.remove();
                }
            }
        }
        super.removeProcessor(processor);
    }

    public int getNumberOfHashGroups() {
        return numberOfHashGroups;
    }

    public void setNumberOfHashGroups(int numberOfHashGroups) {
        this.numberOfHashGroups = numberOfHashGroups;
    }

    /**
     * A strategy to create the key for the sticky load balancing map.
     * The default implementation uses the hash code of the value
     * then modulos by the numberOfHashGroups to avoid the sticky map getting too big
     *
     * @param value the correlation value
     * @return the key to be used in the sticky map
     */
    protected Object getStickyKey(Object value) {
        int hashCode = 37;
        if (value != null) {
            hashCode = value.hashCode();
        }
        if (numberOfHashGroups > 0) {
            hashCode = hashCode % numberOfHashGroups;
        }
        return hashCode;

FUNC_DECL PARAM LOOP VAR_DECL CALL IF VAR_DECL CALL CALL CALL CALL CALL CALL


public class POIFSFileSystem
    implements POIFSViewable
{
    private PropertyTable _property_table;
    private List          _documents;
    private DirectoryNode _root;

    /**
     * Constructor, intended for writing
     */

    public POIFSFileSystem()
    {
        _property_table = new PropertyTable();
        _documents      = new ArrayList();
        _root           = null;
    }

    /**
     * Create a POIFSFileSystem from an InputStream
     *
     * @param stream the InputStream from which to read the data
     *
     * @exception IOException on errors reading, or on invalid data
     */

    public POIFSFileSystem(final InputStream stream)
        throws IOException
    {
        this();

        HeaderBlockReader header_block_reader = new HeaderBlockReader(stream);

        RawDataBlockList  data_blocks         = new RawDataBlockList(stream);

        new BlockAllocationTableReader(header_block_reader.getBATCount(),
                                       header_block_reader.getBATArray(),
                                       header_block_reader.getXBATCount(),
                                       header_block_reader.getXBATIndex(),
                                       data_blocks);

        PropertyTable properties =
            new PropertyTable(header_block_reader.getPropertyStart(),
                              data_blocks);

        processProperties(SmallBlockTableReader
            .getSmallDocumentBlocks(data_blocks, properties
                .getRoot(), header_block_reader
                    .getSBATStart()), data_blocks, properties.getRoot()
                        .getChildren(), null);
    }

    /**
     * Create a new document to be added to the root directory
     *
     * @param stream the InputStream from which the document's data
     *               will be obtained
     * @param name the name of the new POIFSDocument
     *
     * @return the new DocumentEntry
     *
     * @exception IOException on error creating the new POIFSDocument
     */

    public DocumentEntry createDocument(final InputStream stream,
                                        final String name)
        throws IOException
    {
        return getRoot().createDocument(name, stream);
    }

    /**
     * create a new DocumentEntry in the root entry; the data will be
     * provided later
     *
     * @param name the name of the new DocumentEntry
     * @param size the size of the new DocumentEntry
     * @param writer the writer of the new DocumentEntry
     *
     * @return the new DocumentEntry
     *
     * @exception IOException
     */

    public DocumentEntry createDocument(final String name, final int size,
                                        final POIFSWriterListener writer)
        throws IOException
    {
        return getRoot().createDocument(name, size, writer);
    }

    /**
     * create a new DirectoryEntry in the root directory
     *
     * @param name the name of the new DirectoryEntry
     *
     * @return the new DirectoryEntry
     *
     * @exception IOException on name duplication
     */

    public DirectoryEntry createDirectory(final String name)
        throws IOException
    {
        return getRoot().createDirectory(name);
    }

    /**
     * Write the filesystem out
     *
     * @param stream the OutputStream to which the filesystem will be
     *               written
     *
     * @exception IOException thrown on errors writing to the stream
     */

    public void writeFilesystem(final OutputStream stream)
        throws IOException
    {

        _property_table.preWrite();

        SmallBlockTableWriter      sbtw       =
            new SmallBlockTableWriter(_documents, _property_table.getRoot());

        BlockAllocationTableWriter bat        =
            new BlockAllocationTableWriter();

        List                       bm_objects = new ArrayList();

        bm_objects.addAll(_documents);
        bm_objects.add(_property_table);
        bm_objects.add(sbtw);
        bm_objects.add(sbtw.getSBAT());

        Iterator iter = bm_objects.iterator();

        while (iter.hasNext())
        {
            BATManaged bmo         = ( BATManaged ) iter.next();
            int        block_count = bmo.countBlocks();

            if (block_count != 0)
            {
                bmo.setStartBlock(bat.allocateSpace(block_count));
            }
            else
            {

            }
        }

        int               batStartBlock       = bat.createBlocks();

        HeaderBlockWriter header_block_writer = new HeaderBlockWriter();
        BATBlock[]        xbat_blocks         =
            header_block_writer.setBATBlocks(bat.countBlocks(),
                                             batStartBlock);

        header_block_writer.setPropertyStart(_property_table.getStartBlock());

        header_block_writer.setSBATStart(sbtw.getSBAT().getStartBlock());

        header_block_writer.setSBATBlockCount(sbtw.getSBATBlockCount());

        List writers = new ArrayList();

        writers.add(header_block_writer);
        writers.addAll(_documents);
        writers.add(_property_table);
        writers.add(sbtw);
        writers.add(sbtw.getSBAT());
        writers.add(bat);
        for (int j = 0; j < xbat_blocks.length; j++)
        {
            writers.add(xbat_blocks[ j ]);
        }

        iter = writers.iterator();
        while (iter.hasNext())
        {
            BlockWritable writer = ( BlockWritable ) iter.next();

            writer.writeBlocks(stream);
        }
    }

    /**
     * read in a file and write it back out again
     *
     * @param args names of the files; arg[ 0 ] is the input file,
     *             arg[ 1 ] is the output file
     *
     * @exception IOException
     */

    public static void main(String args[])
        throws IOException
    {
        if (args.length != 2)
        {
            System.err.println(
                "two arguments required: input filename and output filename");
            System.exit(1);
        }
        FileInputStream  istream = new FileInputStream(args[ 0 ]);
        FileOutputStream ostream = new FileOutputStream(args[ 1 ]);

        new POIFSFileSystem(istream).writeFilesystem(ostream);
        istream.close();
        ostream.close();
    }

    /**
     * get the root entry
     *
     * @return the root entry
     */

    public DirectoryEntry getRoot()
    {
        if (_root == null)
        {
            _root = new DirectoryNode(_property_table.getRoot(), this, null);
        }
        return _root;
    }

    /**
     * open a document in the root entry's list of entries
     *
     * @param documentName the name of the document to be opened
     *
     * @return a newly opened DocumentInputStream
     *
     * @exception IOException if the document does not exist or the
     *            name is that of a DirectoryEntry
     */

    public DocumentInputStream createDocumentInputStream(
            final String documentName)
        throws IOException
    {
        Entry document = getRoot().getEntry(documentName);

        if (!document.isDocumentEntry())
        {
            throw new IOException("Entry '" + documentName
                                  + "' is not a DocumentEntry");
        }
        return new DocumentInputStream(( DocumentEntry ) document);
    }

    /**
     * add a new POIFSDocument
     *
     * @param document the POIFSDocument being added
     */

    void addDocument(final POIFSDocument document)
    {
        _documents.add(document);
        _property_table.addProperty(document.getDocumentProperty());
    }

    /**
     * add a new DirectoryProperty
     *
     * @param directory the DirectoryProperty being added
     */

    void addDirectory(final DirectoryProperty directory)
    {
        _property_table.addProperty(directory);
    }

    /**
     * remove an entry
     *
     * @param entry to be removed
     */

    void remove(EntryNode entry)
    {
        _property_table.removeProperty(entry.getProperty());
        if (entry.isDocumentEntry())
        {
            _documents.remove((( DocumentNode ) entry).getDocument());
        }
    }

    private void processProperties(final BlockList small_blocks,
                                   final BlockList big_blocks,
                                   final Iterator properties,
                                   final DirectoryNode dir)
        throws IOException
    {
        while (properties.hasNext())
        {
            Property      property = ( Property ) properties.next();
            String        name     = property.getName();
            DirectoryNode parent   = (dir == null)
                                     ? (( DirectoryNode ) getRoot())
                                     : dir;

            if (property.isDirectory())
            {
                DirectoryNode new_dir =
                    ( DirectoryNode ) parent.createDirectory(name);

                new_dir.setStorageClsid( property.getStorageClsid() );

                processProperties(
                    small_blocks, big_blocks,
                    (( DirectoryProperty ) property).getChildren(), new_dir);
            }
            else
            {
                int           startBlock = property.getStartBlock();
                int           size       = property.getSize();
                POIFSDocument document   = null;

                if (property.shouldUseSmallBlocks())
                {
                    document =
                        new POIFSDocument(name, small_blocks
                            .fetchBlocks(startBlock), size);
                }
                else
                {
                    document =
                        new POIFSDocument(name,
                                          big_blocks.fetchBlocks(startBlock),
                                          size);
                }
                parent.createDocument(document);
            }
        }
    }

    /* ********** START begin implementation of POIFSViewable ********** */

    /**
     * Get an array of objects, some of which may implement
     * POIFSViewable
     *
     * @return an array of Object; may not be null, but may be empty
     */

    public Object [] getViewableArray()
    {
        if (preferArray())
        {
            return (( POIFSViewable ) getRoot()).getViewableArray();
        }
        else
        {
            return new Object[ 0 ];
        }
    }

    /**
     * Get an Iterator of objects, some of which may implement
     * POIFSViewable
     *
     * @return an Iterator; may not be null, but may have an empty
     * back end store
     */

    public Iterator getViewableIterator()
    {
        if (!preferArray())
        {
            return (( POIFSViewable ) getRoot()).getViewableIterator();
        }
        else
        {
            return Collections.EMPTY_LIST.iterator();
        }
    }

    /**
     * Give viewers a hint as to whether to call getViewableArray or
     * getViewableIterator
     *
     * @return true if a viewer should call getViewableArray, false if
     *         a viewer should call getViewableIterator
     */

    public boolean preferArray()
    {
        return (( POIFSViewable ) getRoot()).preferArray();
    }

    /**
     * Provides a short description of the object, to be used when a
     * POIFSViewable object has not provided its contents.
     *
     * @return short description
     */

    public String getShortDescription()
    {
        return "POIFS FileSystem";

FUNC_DECL RETURN PARAM PARAM PARAM CALL CALL

FUNC_DECL LOOP LOOP VAR_DECL VAR_DECL VAR_DECL VAR_DECL LOOP VAR_DECL VAR_DECL VAR_DECL VAR_DECL PARAM CALL ASSIGN BINARY_OP CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL VAR_DECL CALL CALL CALL CALL CALL CALL CALL CALL CALL IF VAR_DECL VAR_DECL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL BINARY_OP CALL LITERAL_ANCHOR CALL CALL CALL CALL CALL

FUNC_DECL LOOP PARAM PARAM PARAM PARAM CALL IF VAR_DECL VAR_DECL VAR_DECL CALL IF VAR_DECL VAR_DECL VAR_DECL VAR_DECL COND_EXPR CALL CALL CALL CALL CALL BINARY_OP CALL LITERAL_ANCHOR CALL CALL CALL CALL LITERAL_ANCHOR ASSIGN ASSIGN CALL CALL CALL CALL CALL

FUNC_DECL IF CALL RETURN RETURN LITERAL_ANCHOR CALL

FUNC_DECL IF CALL RETURN RETURN CALL CALL

FUNC_DECL ASSIGN ASSIGN ASSIGN LITERAL_ANCHOR CALL CALL

FUNC_DECL VAR_DECL VAR_DECL VAR_DECL PARAM CALL CALL LITERAL_ANCHOR CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL


org.gjt.sp.jedit.buffer.KillRing

public class KillRing implements MutableListModel
{
	//{{{ getInstance() method
	public static KillRing getInstance()
	{
		return killRing;
	} //}}}

	//{{{ setInstance() method
	public static void setInstance(KillRing killRing)
	{
		KillRing.killRing = killRing;
	} //}}}

	//{{{ propertiesChanged() method
	public void propertiesChanged(int historySize)
	{
		int newSize = Math.max(1, historySize);
		if(ring == null)
			ring = new UndoManager.RemovedContent[newSize];
		else if(newSize != ring.length)
		{
			UndoManager.RemovedContent[] newRing = new UndoManager.RemovedContent[
				newSize];
			int newCount = Math.min(getSize(),newSize);
			for(int i = 0; i < newCount; i++)
			{
				newRing[i] = (UndoManager.RemovedContent)getElementAt(i);
			}
			ring = newRing;
			count = newCount;
			wrap = false;
		}

		if(count == ring.length)
		{
			count = 0;
			wrap = true;
		}
	} //}}}

	public void load() {}

	public void save() {}

	//{{{ reset() method
	/**
	 * This method is made to be used by implementation of load()
	 * method to initialize (or reset) the killring by a loaded
	 * sequence of objects.
	 *
	 * Each element is converted to an element of the killring as
	 * followings:
	 *   - If it is a String, it is converted as if it is a result of
	 *     getElementAt(n).toString().
	 *   - Otherwise, it is converted as if it is a Object which was
	 *     obtained by getElementAt(n).
	 *
	 * @since jEdit 4.3pre12
	 */
	protected void reset(List source)
	{
		UndoManager.RemovedContent[] newRing
			= new UndoManager.RemovedContent[source.size()];
		int i = 0;
		for(Object x: source)
		{
			UndoManager.RemovedContent element;
			if(x instanceof String)
			{
				element = new UndoManager.RemovedContent(
					(String)x);
			}
			else
			{
				element = (UndoManager.RemovedContent)x;
			}
			newRing[i++] = element;
		}
		ring = newRing;
		count = 0;
		wrap = true;
	} //}}}

	//{{{ MutableListModel implementation
	public void addListDataListener(ListDataListener listener) {}

	public void removeListDataListener(ListDataListener listener) {}

	//{{{ getElementAt() method
	public Object getElementAt(int index)
	{
		return ring[virtualToPhysicalIndex(index)];
	} //}}}

	//{{{ getSize() method
	public int getSize()
	{
		if(wrap)
			return ring.length;
		else
			return count;
	} //}}}

	//{{{ removeElement() method
	public boolean removeElement(Object value)
	{
		for(int i = 0; i < getSize(); i++)
		{
			if(ring[i].equals(value))
			{
				remove(i);
				return true;
			}
		}
		return false;
	} //}}}

	//{{{ insertElementAt() method
	public void insertElementAt(Object value, int index)
	{
		/* This is not terribly efficient, but this method is only
		called by the 'Paste Deleted' dialog where the performance
		is not exactly vital */
		remove(index);
		add((UndoManager.RemovedContent)value);
	} //}}}

	//}}}

	//{{{ Package-private members

	//{{{ changed() method
	void changed(UndoManager.RemovedContent rem)
	{
		if(rem.inKillRing)
		{
			// compare existing entries' hashcode with this
			int length = (wrap ? ring.length : count);
			int kill = -1;

			for(int i = 0; i < length; i++)
			{
				if(ring[i] != rem
					&& ring[i].hashcode == rem.hashcode
					&& ring[i].str.equals(rem.str))
				{
					// we don't want duplicate
					// entries in the kill ring
					kill = i;
					break;
				}
			}

			if(kill != -1)
				remove(kill);
		}
		else
			add(rem);
	} //}}}

	//{{{ add() method
	void add(UndoManager.RemovedContent rem)
	{
		// compare existing entries' hashcode with this
		int length = (wrap ? ring.length : count);
		for(int i = 0; i < length; i++)
		{
			if(ring[i].hashcode == rem.hashcode)
			{
				// strings might be equal!
				if(ring[i].str.equals(rem.str))
				{
					// we don't want duplicate entries
					// in the kill ring
					return;
				}
			}
		}

		// no duplicates, check for all-whitespace string
		boolean allWhitespace = true;
		for(int i = 0; i < rem.str.length(); i++)
		{
			if(!Character.isWhitespace(rem.str.charAt(i)))
			{
				allWhitespace = false;
				break;
			}
		}

		if(allWhitespace)
			return;

		rem.inKillRing = true;

		if(ring[count] != null)
			ring[count].inKillRing = false;

		ring[count] = rem;
		if(++count >= ring.length)
		{
			wrap = true;
			count = 0;
		}
	} //}}}

	//{{{ remove() method
	void remove(int i)
	{
		if(wrap)
		{
			UndoManager.RemovedContent[] newRing = new UndoManager.RemovedContent[
				ring.length];
			int newCount = 0;
			for(int j = 0; j < ring.length; j++)
			{
				int index = virtualToPhysicalIndex(j);

				if(i == index)
				{
					ring[index].inKillRing = false;
					continue;
				}

				newRing[newCount++] = ring[index];
			}
			ring = newRing;
			count = newCount;
			wrap = false;
		}
		else
		{
			System.arraycopy(ring,i + 1,ring,i,count - i - 1);
			count--;
		}
	} //}}}

	//}}}

	//{{{ Private members
	private UndoManager.RemovedContent[] ring;
	private int count;
	private boolean wrap;
	private static KillRing killRing = new KillRing();

	//{{{ virtualToPhysicalIndex() method
	/**
	 * Since the kill ring has a wrap-around representation, we need to
	 * convert user-visible indices to actual indices in the array.
	 */
	private int virtualToPhysicalIndex(int index)
	{
		if(wrap)
		{
			if(index < count)
				return count - index - 1;
			else
				return count + ring.length - index - 1;
		}
		else
			return count - index - 1;


org.apache.poi.ddf.UnknownEscherRecord

public class UnknownEscherRecord extends EscherRecord
{
    private static final byte[] NO_BYTES = new byte[0];

    /** The data for this record not including the the 8 byte header */
    private byte[] thedata = NO_BYTES;
    private List childRecords = new ArrayList();

    public UnknownEscherRecord()
    {
    }

    /**
     * This method deserializes the record from a byte array.
     *
     * @param data          The byte array containing the escher record information
     * @param offset        The starting offset into data.
     * @param recordFactory May be null since this is not a container record.
     * @return The number of bytes read from the byte array.
     */
    public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory )
    {
        int bytesRemaining = readHeader( data, offset );
        if ( isContainerRecord() )
        {
            int bytesWritten = 0;
            thedata = new byte[0];
            offset += 8;
            bytesWritten += 8;
            while ( bytesRemaining > 0 )
            {
                EscherRecord child = recordFactory.createRecord( data, offset );
                int childBytesWritten = child.fillFields( data, offset, recordFactory );
                bytesWritten += childBytesWritten;
                offset += childBytesWritten;
                bytesRemaining -= childBytesWritten;
                getChildRecords().add( child );
            }
            return bytesWritten;
        }
        else
        {
            thedata = new byte[bytesRemaining];
            System.arraycopy( data, offset + 8, thedata, 0, bytesRemaining );
            return bytesRemaining + 8;
        }
    }

    /**
     * Writes this record and any contained records to the supplied byte
     * array.
     *
     * @return  the number of bytes written.
     */
    public int serialize( int offset, byte[] data, EscherSerializationListener listener )
    {
        listener.beforeRecordSerialize( offset, getRecordId(), this );

        LittleEndian.putShort(data, offset, getOptions());
        LittleEndian.putShort(data, offset+2, getRecordId());
        int remainingBytes = thedata.length;
        for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
        {
            EscherRecord r = (EscherRecord) iterator.next();
            remainingBytes += r.getRecordSize();
        }
        LittleEndian.putInt(data, offset+4, remainingBytes);
        System.arraycopy(thedata, 0, data, offset+8, thedata.length);
        int pos = offset+8+thedata.length;
        for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
        {
            EscherRecord r = (EscherRecord) iterator.next();
            pos += r.serialize(pos, data, listener );
        }

        listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
        return pos - offset;
    }

    public byte[] getData()
    {
        return thedata;
    }

    /**
     * Returns the number of bytes that are required to serialize this record.
     *
     * @return Number of bytes
     */
    public int getRecordSize()
    {
        return 8 + thedata.length;
    }

    public List getChildRecords()
    {
        return childRecords;
    }

    public void setChildRecords( List childRecords )
    {
        this.childRecords = childRecords;
    }

    public Object clone()
    {
        return super.clone();
    }

    /**
     * The short name for this record
     */
    public String getRecordName()
    {
        return "Unknown 0x" + HexDump.toHex(getRecordId());
    }

    public String toString()
    {
        String nl = System.getProperty( "line.separator" );

        StringBuffer children = new StringBuffer();
        if ( getChildRecords().size() > 0 )
        {
            children.append( "  children: " + nl );
            for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
            {
                EscherRecord record = (EscherRecord) iterator.next();
                children.append( record.toString() );
                children.append( nl );
            }
        }

        String theDumpHex = "";
        try
        {
            if (thedata.length != 0)
            {
                theDumpHex = "  Extra Data:" + nl;
                theDumpHex += HexDump.dump(thedata, 0, 0);
            }
        }
        catch ( Exception e )
        {
            theDumpHex = "Error!!";
        }

        return getClass().getName() + ":" + nl +
                "  isContainer: " + isContainerRecord() + nl +
                "  options: 0x" + HexDump.toHex( getOptions() ) + nl +
                "  recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
                "  numchildren: " + getChildRecords().size() + nl +
                theDumpHex +
                children.toString();
    }

    public void addChildRecord( EscherRecord childRecord )
    {
        getChildRecords().add( childRecord );


org.apache.poi.hpsf.Property

public class Property
{

    /* Codepage 1200 denotes Unicode. */
    private static int CP_UNICODE = 1200;

    private int id;

    /**
     *
Returns the property's ID.

     *
     * @return The ID value
     */
    public int getID()
    {
        return id;
    }

    private long type;

    /**
     *
Returns the property's type.

     *
     * @return The type value
     */
    public long getType()
    {
        return type;
    }

    private Object value;

    /**
     *
Returns the property's value.

     *
     * @return The property's value
     */
    public Object getValue()
    {
        return value;
    }

    /**
     *
Creates a {@link Property} instance by reading its bytes
     * from the property set stream.

     *
     * @param id The property's ID.
     * @param src The bytes the property set stream consists of.
     * @param offset The property's type/value pair's offset in the
     * section.
     * @param length The property's type/value pair's length in bytes.
     * @param codepage The section's and thus the property's
     * codepage. It is needed only when reading string values.
     */
    public Property(final int id, final byte[] src, final long offset,
		    int length, int codepage)
    {
        this.id = id;

        /*
         * ID 0 is a special case since it specifies a dictionary of
         * property IDs and property names.
         */
        if (id == 0)
	{
            value = readDictionary(src, offset, length, codepage);
            return;
        }

        int o = (int) offset;
        type = LittleEndian.getUInt(src, o);
        o += LittleEndian.INT_SIZE;

	try
	{
	    value = TypeReader.read(src, o, length, (int) type);
	}
	catch (Throwable t)
	{
	    t.printStackTrace();
	    value = "*** null ***";
	}
    }

    /**
     *
Reads a dictionary.

     *
     * @param src The byte array containing the bytes making out the
     * dictionary.
     * @param offset At this offset within <var>src</var> the
     * dictionary starts.
     * @param length The dictionary contains at most this many bytes.
     * @param codepage The codepage of the string values.
     * @return The dictonary
     */
    protected Map readDictionary(final byte[] src, final long offset,
				 final int length, final int codepage)
    {
	/* Check whether "offset" points into the "src" array". */
	if (offset < 0 || offset > src.length)
	    throw new HPSFRuntimeException
		("Illegal offset " + offset + " while HPSF stream contains " +
		 length + " bytes.");
        int o = (int) offset;

        /*
         * Read the number of dictionary entries.
         */
        final long nrEntries = LittleEndian.getUInt(src, o);
        o += LittleEndian.INT_SIZE;

        final Map m = new HashMap((int) nrEntries, (float) 1.0);
        for (int i = 0; i < nrEntries; i++)
	{
            /* The key. */
            final Long id = new Long(LittleEndian.getUInt(src, o));
            o += LittleEndian.INT_SIZE;

            /* The value (a string). The length is the either the
             * number of characters if the character set is Unicode or
             * else the number of bytes. The length includes
             * terminating 0x00 bytes which we have to strip off to
             * create a Java string. */
            long sLength = LittleEndian.getUInt(src, o);
            o += LittleEndian.INT_SIZE;

            /* Read the bytes or characters depending on whether the
             * character set is Unicode or not. */
	    StringBuffer b = new StringBuffer((int) sLength);
	    for (int j = 0; j < sLength; j++)
		if (codepage == CP_UNICODE)
		{
		    final int i1 = o + (j * 2);
		    final int i2 = i1 + 1;
		    b.append((char) ((src[i2] << 8) + src[i1]));
		}
		else
		    b.append((char) src[o + j]);

	    /* Strip 0x00 characters from the end of the string: */
	    while (b.charAt(b.length() - 1) == 0x00)
		b.setLength(b.length() - 1);
	    if (codepage == CP_UNICODE)
	    {
		if (sLength % 2 == 1)
		    sLength++;
		o += (sLength + sLength);
	    }
	    else
		o += sLength;
            m.put(id, b.toString());
        }
        return m;

    public int getID()
    {
        return id;

    public long getType()
    {
        return type;

FUNC_DECL TRY VAR_DECL IF PARAM PARAM PARAM PARAM PARAM CATCH ASSIGN ASSIGN BINARY_OP ASSIGN ASSIGN CALL RETURN LITERAL_ANCHOR ASSIGN CALL CALL ASSIGN LITERAL_ANCHOR CALL


org.apache.camel.model.SetOutHeaderType

@XmlRootElement(name = "setOutHeader")
@XmlAccessorType(XmlAccessType.FIELD)
public class SetOutHeaderType extends ExpressionNode {
    @XmlAttribute(required = true)
    private String headerName;

    public SetOutHeaderType() {
    }

    public SetOutHeaderType(String headerName, ExpressionType expression) {
        super(expression);
        setHeaderName(headerName);
    }

    public SetOutHeaderType(String headerName, Expression expression) {
        super(expression);
        setHeaderName(headerName);
    }

    @Override
    public String toString() {
        return "SetOutHeader[" + getHeaderName() + ", " + getExpression() + "]";
    }

    @Override
    public String getShortName() {
        return "setOutHeader";
    }

    @Override
    public Processor createProcessor(RouteContext routeContext) throws Exception {
        ObjectHelper.notNull(getHeaderName(), "headerName");
        Expression expr = getExpression().createExpression(routeContext);
        return ProcessorBuilder.setOutHeader(getHeaderName(), expr);
    }

    public void setHeaderName(String headerName) {
        this.headerName = headerName;
    }

    public String getHeaderName() {
        return headerName;

FUNC_DECL RETURN VAR_DECL PARAM CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL


public class DirectEndpoint<E extends Exchange> extends DefaultEndpoint<E> {
    private static final transient Log LOG = LogFactory.getLog(DirectEndpoint.class);
    private boolean allowMultipleConsumers = true;
    private final CopyOnWriteArrayList<DefaultConsumer<E>> consumers = new CopyOnWriteArrayList<DefaultConsumer<E>>();

    public DirectEndpoint(String uri, DirectComponent<E> component) {
        super(uri, component);
    }

    public DirectEndpoint(String endpointUri) {
        super(endpointUri);
    }

    public Producer createProducer() throws Exception {
        return new DirectProducer<E>(this);
    }

    public Consumer<E> createConsumer(Processor processor) throws Exception {
        return new DefaultConsumer<E>(this, processor) {
            @Override
            public void start() throws Exception {
                if (!allowMultipleConsumers && !consumers.isEmpty()) {
                    throw new IllegalStateException("Endpoint " + getEndpointUri() + " only allows 1 active consumer but you attempted to start a 2nd consumer.");
                }

                consumers.add(this);
                super.start();
            }

            @Override
            public void stop() throws Exception {
                super.stop();
                consumers.remove(this);
            }
        };
    }

    public boolean isAllowMultipleConsumers() {
        return allowMultipleConsumers;
    }

    public void setAllowMultipleConsumers(boolean allowMutlipleConsumers) {
        this.allowMultipleConsumers = allowMutlipleConsumers;
    }

    public boolean isSingleton() {
        return true;
    }

    public List<DefaultConsumer<E>> getConsumers() {
        return consumers;


org.apache.xalan.xsltc.compiler.NotCall

final class NotCall extends FunctionCall {
    public NotCall(QName fname, Vector arguments) {
	super(fname, arguments);
    }

    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
	final InstructionList il = methodGen.getInstructionList();
	argument().translate(classGen, methodGen);
	il.append(ICONST_1);
	il.append(IXOR);
    }

    public void translateDesynthesized(ClassGenerator classGen,
				       MethodGenerator methodGen) {
	final InstructionList il = methodGen.getInstructionList();
	final Expression exp = argument();
	exp.translateDesynthesized(classGen, methodGen);
	final BranchHandle gotoh = il.append(new GOTO(null));
	_falseList = exp._trueList;
	_falseList.add(gotoh);

FUNC_DECL VAR_DECL PARAM PARAM CALL CALL CALL CALL CALL


public class HCenterRecord
    extends Record
{
    public final static short sid = 0x83;
    private short             field_1_hcenter;

    public HCenterRecord()
    {
    }

    /**
     * Constructs an HCenter record and sets its fields appropriately.
     *
     * @param id     id must be 0x83 or an exception will be throw upon validation
     * @param size  the size of the data area of the record
     * @param data  data of the record (should not contain sid/len)
     */

    public HCenterRecord(RecordInputStream in)
    {
        super(in);
    }

    protected void validateSid(short id)
    {
        if (id != sid)
        {
            throw new RecordFormatException("NOT A HCenter RECORD");
        }
    }

    protected void fillFields(RecordInputStream in)
    {
        field_1_hcenter = in.readShort();
    }

    /**
     * set whether or not to horizonatally center this sheet.
     * @param hc  center - t/f
     */

    public void setHCenter(boolean hc)
    {
        if (hc == true)
        {
            field_1_hcenter = 1;
        }
        else
        {
            field_1_hcenter = 0;
        }
    }

    /**
     * get whether or not to horizonatally center this sheet.
     * @return center - t/f
     */

    public boolean getHCenter()
    {
        return (field_1_hcenter == 1);
    }

    public String toString()
    {
        StringBuffer buffer = new StringBuffer();

        buffer.append("[HCENTER]\n");
        buffer.append("    .hcenter        = ").append(getHCenter())
            .append("\n");
        buffer.append("[/HCENTER]\n");
        return buffer.toString();
    }

    public int serialize(int offset, byte [] data)
    {
        LittleEndian.putShort(data, 0 + offset, sid);
        LittleEndian.putShort(data, 2 + offset, ( short ) 0x2);
        LittleEndian.putShort(data, 4 + offset, ( short ) field_1_hcenter);
        return getRecordSize();
    }

    public int getRecordSize()
    {
        return 6;
    }

    public short getSid()
    {
        return sid;
    }

    public Object clone() {
      HCenterRecord rec = new HCenterRecord();
      rec.field_1_hcenter = field_1_hcenter;
      return rec;

    public int getRecordSize()
    {
        return 6;

    public short getSid()
    {
        return sid;


public class DeliverEngine {
    private DeliverEngineSettings settings;

    public DeliverEngine(DeliverEngineSettings settings) {
        this.settings = settings;
    }

    /**
     * Delivers a resolved ivy file based upon last resolve call status. If resolve report file
     * cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been
     * called before ?).
     *
     * @param revision
     *            the revision to which the module should be delivered
     * @param destIvyPattern
     *            the pattern to which the delivered ivy file should be written
     * @param options
     *            the options with which deliver should be done
     */
    public void deliver(String revision, String destIvyPattern, DeliverOptions options)
            throws IOException, ParseException {
        String resolveId = options.getResolveId();
        if (resolveId == null) {
            throw new IllegalArgumentException("A resolveId must be specified for delivering.");
        }
        File[] files = getCache().getConfigurationResolveReportsInCache(resolveId);
        if (files.length == 0) {
            throw new IllegalStateException("No previous resolve found for id '" + resolveId
                    + "' Please resolve dependencies before delivering.");
        }
        XmlReportParser parser = new XmlReportParser();
        parser.parse(files[0]);
        ModuleRevisionId mrid = parser.getResolvedModule();
        deliver(mrid, revision, destIvyPattern, options);
    }

    private ResolutionCacheManager getCache() {
        return settings.getResolutionCacheManager();
    }

    /**
     * Delivers a resolved ivy file based upon last resolve call status. If resolve report file
     * cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been
     * called before ?).
     *
     * @param mrid
     *            the module revision id of the module to deliver
     * @param revision
     *            the revision to which the module should be delivered
     * @param destIvyPattern
     *            the pattern to which the delivered ivy file should be written
     * @param options
     *            the options with which deliver should be done
     */
    public void deliver(ModuleRevisionId mrid, String revision, String destIvyPattern,
            DeliverOptions options) throws IOException, ParseException {
        Message.info(":: delivering :: " + mrid + " :: " + revision + " :: " + options.getStatus()
                + " :: " + options.getPubdate());
        Message.verbose("\toptions = " + options);
        long start = System.currentTimeMillis();
        destIvyPattern = settings.substitute(destIvyPattern);

        // 1) find the resolved module descriptor in cache
        File ivyFile = getCache().getResolvedIvyFileInCache(mrid);
        if (!ivyFile.exists()) {
            throw new IllegalStateException("ivy file not found in cache for " + mrid
                    + ": please resolve dependencies before delivering (" + ivyFile + ")");
        }
        ModuleDescriptor md = null;
        URL ivyFileURL = null;
        try {
            ivyFileURL = ivyFile.toURI().toURL();
            md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFileURL,
                options.isValidate());
            md.setResolvedModuleRevisionId(ModuleRevisionId.newInstance(mrid,
                options.getPubBranch() == null ? mrid.getBranch() : options.getPubBranch(),
                revision));
            md.setResolvedPublicationDate(options.getPubdate());
        } catch (MalformedURLException e) {
            throw new RuntimeException("malformed url obtained for file " + ivyFile, e);
        } catch (ParseException e) {
            throw new RuntimeException("bad ivy file in cache for " + mrid
                    + ": please clean and resolve again", e);
        }

        // 2) parse resolvedRevisions From properties file
        Map resolvedRevisions = new HashMap(); // Map (ModuleId -> String revision)
        Map dependenciesStatus = new HashMap(); // Map (ModuleId -> String status)
        File ivyProperties = getCache().getResolvedIvyPropertiesInCache(mrid);
        if (!ivyProperties.exists()) {
            throw new IllegalStateException("ivy properties not found in cache for " + mrid
                    + ": please resolve dependencies before delivering (" + ivyFile + ")");
        }
        Properties props = new Properties();
        FileInputStream in = new FileInputStream(ivyProperties);
        props.load(in);
        in.close();

        for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
            String depMridStr = (String) iter.next();
            String[] parts = props.getProperty(depMridStr).split(" ");
            ModuleRevisionId decodedMrid = ModuleRevisionId.decode(depMridStr);
            if (options.isResolveDynamicRevisions()) {
                resolvedRevisions.put(decodedMrid, parts[0]);
            }
            dependenciesStatus.put(decodedMrid, parts[1]);
        }

        // 3) use pdrResolver to resolve dependencies info
        Map resolvedDependencies = new HashMap(); // Map (ModuleRevisionId -> String revision)
        DependencyDescriptor[] dependencies = md.getDependencies();
        for (int i = 0; i < dependencies.length; i++) {
            String rev = (String) resolvedRevisions.get(dependencies[i].getDependencyRevisionId());
            if (rev == null) {
                rev = dependencies[i].getDependencyRevisionId().getRevision();
            }
            String depStatus = (String) dependenciesStatus.get(dependencies[i]
                    .getDependencyRevisionId());
            resolvedDependencies.put(dependencies[i].getDependencyRevisionId(), options
                    .getPdrResolver().resolve(
                        md,
                        options.getStatus(),
                        ModuleRevisionId
                                .newInstance(dependencies[i].getDependencyRevisionId(), rev),
                        depStatus));
        }

        // 4) copy the source resolved ivy to the destination specified,
        // updating status, revision and dependency revisions obtained by
        // PublishingDependencyRevisionResolver
        File publishedIvy = settings.resolveFile(
                    IvyPatternHelper.substitute(destIvyPattern, md.getResolvedModuleRevisionId()));
        Message.info("\tdelivering ivy file to " + publishedIvy);

        String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md);
        Set confsToRemove = new HashSet(Arrays.asList(md.getConfigurationsNames()));
        confsToRemove.removeAll(Arrays.asList(confs));

        try {
            XmlModuleDescriptorUpdater.update(ivyFileURL, publishedIvy,
                    new UpdateOptions()
                        .setSettings(settings)
                        .setResolvedRevisions(resolvedDependencies)
                        .setStatus(options.getStatus())
                        .setRevision(revision)
                        .setBranch(options.getPubBranch())
                        .setPubdate(options.getPubdate())
                        .setConfsToExclude((String[]) confsToRemove
                            .toArray(new String[confsToRemove.size()])));
        } catch (SAXException ex) {
            throw new RuntimeException("bad ivy file in cache for " + mrid
                    + ": please clean and resolve again", ex);
        }

        Message.verbose("\tdeliver done (" + (System.currentTimeMillis() - start) + "ms)");