Index: vcview.py
===================================================================
--- vcview.py	(revision 1178)
+++ vcview.py	(working copy)
@@ -19,7 +19,6 @@
 import gtk
 import os
 from gettext import gettext as _
-import re
 
 import tree
 import misc
@@ -443,29 +442,11 @@
         self._open_files(self._get_selected_files())
 
     def show_patch(self, prefix, patch):
-        if not patch: return
-
         tmpdir = tempfile.mkdtemp("-meld")
         self.tempdirs.append(tmpdir)
 
-        regex = re.compile(self.vc.PATCH_INDEX_RE, re.M)
-        files = [f.strip() for f in regex.findall(patch)]
-        diffs = []
-        for fname in files:
-            destfile = os.path.join(tmpdir,fname)
-            destdir = os.path.dirname( destfile )
-
-            if not os.path.exists(destdir):
-                os.makedirs(destdir)
-            pathtofile = os.path.join(prefix, fname)
-            try:
-                shutil.copyfile( pathtofile, destfile)
-            except IOError: # it is missing, create empty file
-                open(destfile,"w").close()
-            diffs.append( (destfile, pathtofile) )
-
-        patchcmd = self.vc.patch_command( tmpdir )
-        if misc.write_pipe(patchcmd, patch) == 0:
+        status, patchcmd, diffs = self.vc.get_diffs(patch, tmpdir, prefix)
+        if status == 0:
             for d in diffs:
                 self.emit("create-diff", d)
         else:
Index: vc/patch.py
===================================================================
--- vc/patch.py	(revision 0)
+++ vc/patch.py	(revision 0)
@@ -0,0 +1,52 @@
+### Copyright (C) 2009 Vincent Legoll <vincent.legoll@gmail.com>
+
+### Redistribution and use in source and binary forms, with or without
+### modification, are permitted provided that the following conditions
+### are met:
+### 
+### 1. Redistributions of source code must retain the above copyright
+###    notice, this list of conditions and the following disclaimer.
+### 2. Redistributions in binary form must reproduce the above copyright
+###    notice, this list of conditions and the following disclaimer in the
+###    documentation and/or other materials provided with the distribution.
+
+### THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+### IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+### OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+### IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+### INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+### NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+### DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+### THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+### THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import _vc
+
+# TODO: add support for showing diff without having original files (c.f. kompare)
+
+class Vc(_vc.Vc):
+
+    CMD = "patch"
+    NAME = "Patch Viewer"
+    PATCH_STRIP_NUM = 0
+    PATCH_INDEX_RE = "^---[ \t]+(\S+)[ \t]+.*$"
+
+    def __init__(self, location):
+        _vc.Vc.__init__(self)
+        # This plugin is only for patch files
+        if os.path.isdir(location) or not self.is_patch(location):
+            raise ValueError()
+        self.root = os.path.dirname(location)
+
+    def diff_command(self):
+        return ["cat"]
+
+    def is_reverse(self):
+        return False
+
+    def is_patch(self, location):
+        if len(self.get_files(open(location).read())) > 0:
+            return True
+        return False
Index: vc/_vc.py
===================================================================
--- vc/_vc.py	(revision 1178)
+++ vc/_vc.py	(working copy)
@@ -21,7 +21,8 @@
 ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 ### THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import os
+import os, re, shutil
+import misc
 from gettext import gettext as _
 
 # ignored, new, normal, ignored changes,
@@ -70,6 +71,7 @@
 class Vc(object):
 
     PATCH_STRIP_NUM = 0
+    PATCH_INDEX_RE = ''
 
     def commit_command(self, message):
         raise NotImplementedError()
@@ -83,9 +85,49 @@
         raise NotImplementedError()
     def revert_command(self):
         raise NotImplementedError()
+
     def patch_command(self, workdir):
-        return ["patch","--strip=%i"%self.PATCH_STRIP_NUM,"--reverse","--directory=%s" % workdir]
+        ret = ["patch", "--strip=%i" % self.PATCH_STRIP_NUM]
+        if self.is_reverse():
+            ret.append("--reverse")
+        return ret + ["--directory=%s" % workdir]
 
+    def is_reverse(self):
+        return True
+
+    def get_files(self, patch):
+        regex = re.compile(self.PATCH_INDEX_RE, re.M)
+        return [f.strip() for f in regex.findall(patch)]
+
+    def get_diffs(self, patch, tmpdir, prefix):
+        diffs = []
+        for fname in self.get_files(patch):
+            destfile = os.path.join(tmpdir,fname)
+            destdir = os.path.dirname( destfile )
+
+            if not os.path.exists(destdir):
+                os.makedirs(destdir)
+            pathtofile = os.path.join(prefix, fname)
+            if not os.path.exists(pathtofile):
+                if os.path.exists('/dev/null'):
+                    pathtofile = '/dev/null'
+                else:
+                    open(pathtofile,"w").close()
+
+            try:
+                shutil.copyfile( pathtofile, destfile)
+            except IOError: # it is missing, create empty file
+                open(destfile,"w").close()
+
+            if self.is_reverse():
+                diffs.append( (destfile, pathtofile) )
+            else:
+                diffs.append( (pathtofile, destfile) )
+
+        patchcmd = self.patch_command( tmpdir )
+        status = misc.write_pipe(patchcmd, patch)
+        return status, patchcmd, diffs
+
     def get_working_directory(self, workdir):
         return workdir
 
Index: meldapp.py
===================================================================
--- meldapp.py	(revision 1178)
+++ meldapp.py	(working copy)
@@ -926,6 +926,16 @@
         if tab:
             tab.set_labels( options.label )
 
+    def _single_file_open(self, a):
+        doc = vcview.VcView(self.prefs)
+        def cleanup():
+            self.scheduler.remove_scheduler(doc.scheduler)
+        self.scheduler.add_task(cleanup)
+        self.scheduler.add_scheduler(doc.scheduler)
+        doc.set_location( os.path.dirname(a) )
+        doc.connect("create-diff", lambda obj,arg: self.append_diff(arg) )
+        doc.run_diff([a])
+
     def open_paths(self, paths, auto_compare=False):
         tab = None
         if len(paths) == 0:
@@ -933,18 +943,17 @@
 
         elif len(paths) == 1:
             a = paths[0]
-            if os.path.isfile(a):
-                doc = vcview.VcView(self.prefs)
-                def cleanup():
-                    self.scheduler.remove_scheduler(doc.scheduler)
-                self.scheduler.add_task(cleanup)
-                self.scheduler.add_scheduler(doc.scheduler)
-                doc.set_location( os.path.dirname(a) )
-                doc.connect("create-diff", lambda obj,arg: self.append_diff(arg) )
-                doc.run_diff([a])
+            if os.path.isdir(a):
+                tab = self.append_vcview([a], auto_compare)
             else:
-                tab = self.append_vcview([a], auto_compare)
-                    
+                import vc.patch
+                try:
+                    vc.patch.Vc(a)
+                    tab = self.append_vcview([a], auto_compare)
+                except ValueError:
+                    if a.endswith('.patch') or a.endswith('.diff'):
+                        self.usage(_("Patch format is not recognized."))
+                    self._single_file_open(a)   
         elif len(paths) in (2,3):
             tab = self.append_diff(paths, auto_compare)
         else:
