"""
Diff_Buffer_Backups.py - A Jython macro for jEdit for
comparing backups of buffers using the JDiffPlugin.

Copyright (C) 2002 Ollie Rutherfurd <oliver@jedit.org>

$Id: Diff_Buffer_Backups.py 28 2003-03-25 22:40:28Z oliver $
"""

__version__ = '$Revision: 1.6 $'[11:-2]
__author__ = 'Ollie Rutherfurd'

from java.awt import BorderLayout
from java.awt.event import ActionListener
from java.lang import Runnable
from javax.swing import Box, BoxLayout, DefaultListCellRenderer, JButton, \
	JComboBox, JDialog, JLabel, JOptionPane, JPanel, SwingUtilities
from javax.swing.border import EmptyBorder
from org.gjt.sp.jedit import Macros, MiscUtilities
from org.gjt.sp.jedit.io import VFSManager
from org.gjt.sp.jedit.gui import VariableGridLayout
import os.path


def getBackups(b):

	"""
	Gets list of backups for buffer `b`.

	Looks for:
	- a single backup in the backups directory
	- a single backup in the buffer's directory
	- numbered backups in the backups directory
	- numbered backups in the buffer's directory
	"""

	directory = jEdit.getProperty('backup.directory')
	prefix = jEdit.getProperty('backup.prefix')
	suffix = jEdit.getProperty('backup.suffix')

	bufferName = b.getName()
	bufferPath = b.getPath()
	bufferDir = b.getVFS().getParentOfPath(b.getPath())

	# if directory is None or empty string, assume
	# backups in current directory
	if directory is None or directory == '':
		directory = bufferDir
	else:
		# pickup if path starts with X:\
		if bufferPath[1:3] == ':\\':
			directory = MiscUtilities.constructPath(
				directory, bufferDir[0] + bufferDir[2:])
		# if a UNC path
		elif bufferPath.startswith('\\\\'):
			directory = MiscUtilities.constructPath(directory, bufferDir[2:])
		# not a 'windows drive' or UNC path
		else:
			directory = MiscUtilities.constructPath(directory, bufferDir[1:])

	# always include current buffer
	backups = [bufferPath]

	# look for a single backup in the buffer directory
	filename = MiscUtilities.constructPath(bufferDir,
		prefix + bufferName + suffix)
	if os.path.exists(filename):
		backups.append(filename)

	# look for a single backup in the backups directory
	# (if it's not the same as the buffer's directory)
	filename = MiscUtilities.constructPath(directory,
		prefix + bufferName + suffix)
	if os.path.exists(filename) and filename not in backups:
		backups.append(filename)

	# get numbered backups in buffer directory
	i = 1
	while 1:
		filename = os.path.join(bufferDir, 
			prefix + bufferName + suffix + str(i) + suffix)
		if not os.path.exists(filename):
			break
		backups.append(filename)
		i += 1

	if directory == bufferDir:
		return backups

	# get number backups in backup directory
	i = 1
	while 1:
		filename = os.path.join(directory, 
			prefix + bufferName + suffix + str(i) + suffix)
		if not os.path.exists(filename):
			break
		backups.append(filename)
		i += 1

	return backups

class BufferCellRenderer(DefaultListCellRenderer):
	"""
	CellRenderer to display buffer's icon.
	"""
	def __init__(self):
		DefaultListCellRenderer.__init__(self)

	def getListCellRendererComponent(self, jlist, value, index, isSelected, cellHasFocus):
		DefaultListCellRenderer.getListCellRendererComponent(self, jlist, value, index, isSelected, cellHasFocus)
		self.setIcon(value.getIcon())
		return self

class DiffBufferBackups(JDialog,ActionListener):
	"""
	Dialog that display list of buffers and backups for buffers.
	"""
	def __init__(self,view,modal=1):
		JDialog.__init__(self,view,'Diff Buffer Backups',modal)

		self.view = view

		panel = JPanel(BorderLayout(),border=EmptyBorder(12,12,12,12))
		self.setContentPane(panel)

		fields = JPanel(VariableGridLayout(VariableGridLayout.FIXED_NUM_COLUMNS, 2, 2, 2))
		fields.add(JLabel('Buffers:'))
		# only list 'local' buffers
		buffers = filter(lambda b: b.getVFS().getName() == 'file', jEdit.getBuffers())
		self.buffers = JComboBox(buffers,actionListener=self)
		self.buffers.setRenderer(BufferCellRenderer())
		fields.add(self.buffers)
		self.vOne = JComboBox()
		self.vTwo = JComboBox()
		fields.add(JLabel('Version 1:'))
		fields.add(self.vOne)
		fields.add(JLabel('Version 2:'))
		fields.add(self.vTwo)
		panel.add(fields, BorderLayout.CENTER)

		buttons = JPanel(border=EmptyBorder(12,50,0,50))
		buttons.setLayout(BoxLayout(buttons, BoxLayout.X_AXIS))
		buttons.add(Box.createGlue())
		self.diff = JButton('Diff',actionListener=self)
		self.getRootPane().setDefaultButton(self.diff)
		buttons.add(self.diff)
		buttons.add(Box.createHorizontalStrut(6))
		close = JButton('Close',actionListener=self)
		self.diff.setPreferredSize(close.getPreferredSize())
		buttons.add(close)
		buttons.add(Box.createGlue())
		panel.add(buttons, BorderLayout.SOUTH)

		# set selected buffer (will add backups for selected buffer)
		self.buffers.setSelectedItem(self.view.getBuffer())

		self.pack()
		self.setLocationRelativeTo(view)
		self.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
		self.setVisible(1)

	def actionPerformed(self,evt):
		if evt.getSource() == self.diff:
			self.diffSelected()
		elif evt.getSource() == self.buffers:
			self.getBufferBackups()
		else:
			self.close()

	def close(self):
		"""
		Do cleanup and close dialog.
		"""
		self.view = None
		self.dispose()

	def getBufferBackups(self):
		"""
		Populate buffer backup combo boxes.
		"""
		backups = getBackups(self.buffers.getSelectedItem())
		[v.removeAllItems() for v in (self.vOne,self.vTwo)]
		[(self.vOne.addItem(b), self.vTwo.addItem(b)) for b in backups]
		if len(backups) > 1:
			self.vTwo.setSelectedItem(backups[1])

	def diffSelected(self):
		"""
		Diff selected version using JDiffPlugin.
		"""
		v1 = self.vOne.getSelectedItem()
		v2 = self.vTwo.getSelectedItem()
		if v1 == v2:
			Macros.error(self.view, 'Please select different versions.')
			return
		SwingUtilities.invokeLater(DiffOpener(self.view,v1,v2,self.buffers.getSelectedItem().getMode()))

class DiffOpener(Runnable):

	def __init__(self, view, v1, v2, mode):
		self.view = view
		self.v1 = v1
		self.v2 = v2
		self.mode = mode

	def run(self):
		# open buffers
		b1 = jEdit.openFile(self.view, self.v1)
		b2 = jEdit.openFile(self.view, self.v2)

		# wait for buffers to load
		VFSManager.waitForRequests()

		# ensure 1 single vertical split
		while len(self.view.getEditPanes()) > 1:
			self.view.unsplit()
		self.view.splitVertically()

		# set buffers in editPanes
		editPanes = self.view.getEditPanes()
		editPanes[0].setBuffer(b1)
		editPanes[1].setBuffer(b2)

		# unfold everything
		for i in (0,1):
			editPanes[i].getTextArea().getFoldVisibilityManager().expandAllFolds()

		# make sure buffers are using correct mode, which
		# might not be picked up because of backup prefix/suffix
		# changing the file extension
		b1.setMode(self.mode)
		b2.setMode(self.mode)

		# do diff
		jdiff.DualDiff.toggleFor(self.view)


def main():

	# check if JDiffPlugin is installed
	if jEdit.getPlugin('jdiff.JDiffPlugin') is None:
		Macros.error(init.view, 'You must have JDiffPlugin 1.3 or greater installed to use this macro.')

	# check if plugins jars are automatically made available for importing
	# NOTE: JythonInterpreter 0.8 has a bug which prevents this from
	# being saved via the option pane
	if not jEdit.getBooleanProperty('options.jython.autoloadPlugins'):
		response = Macros.confirm(init.view, """JythonInterpreter must have `AutoLoad` plugins turned on.

Turn on this option?

Note: you will have to restart jEdit for this change to take effect.""", JOptionPane.YES_NO_CANCEL_OPTION)
		if response == JOptionPane.YES_OPTION:
			jEdit.setBooleanProperty('options.jython.autoloadPlugins',1)

		return	# can't run macro

	# try to import jdiff
	try:
		import jdiff
	except ImportError:
		Macros.error(init.view, 'Unable to import jdiff.')
		return

	DiffBufferBackups(init.view,modal=0)


if __name__ in ('__main__','main'):
	main()

# :indentSize=4:lineSeparator=\n:noTabs=false:tabSize=4:

