diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7e8e910
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+*.moc
+*.cmake
+Makefile
+CMakeFiles
+moc_*
+config*.h
+*.orig
diff --git a/DB/ImageInfo.cpp b/DB/ImageInfo.cpp
index d2cb1c6..9b33bb4 100644
--- a/DB/ImageInfo.cpp
+++ b/DB/ImageInfo.cpp
@@ -485,6 +485,25 @@ void DB::ImageInfo::createFolderCategoryItem( DB::CategoryPtr folderCategory, DB
     folderCategory->addItem( folderName );
 }
 
+void DB::ImageInfo::copyExtraData( const DB::ImageInfo& from) 
+{
+    _categoryInfomation = from._categoryInfomation;
+    _description = from._description;
+    // Hmm...  what should the date be?  orig or modified?
+    // _date = from._date;
+    _angle = from._angle;
+    _rating = from._rating;
+    _geoPosition = from._geoPosition;
+}
+
+void DB::ImageInfo::removeExtraData ()
+{
+    _categoryInfomation.clear();
+    _description = QString();
+    _rating = -1;
+    _geoPosition = GpsCoordinates();
+}
+
 void DB::ImageInfo::addCategoryInfo( const QString& category, const StringSet& values )
 {
     for ( StringSet::const_iterator valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
diff --git a/DB/ImageInfo.h b/DB/ImageInfo.h
index 30cb103..e99042f 100644
--- a/DB/ImageInfo.h
+++ b/DB/ImageInfo.h
@@ -147,6 +147,9 @@ public:
 
     void delaySavingChanges(bool b=true);
 
+    void copyExtraData( const ImageInfo& from);
+    void removeExtraData();
+
 protected:
     /** Save changes to database.
      *
diff --git a/DB/NewImageFinder.cpp b/DB/NewImageFinder.cpp
index 0cea112..3b89e50 100644
--- a/DB/NewImageFinder.cpp
+++ b/DB/NewImageFinder.cpp
@@ -19,9 +19,11 @@
 
 #include <sys/types.h>
 #include <dirent.h>
+#include <stdio.h>
 
 #include "DB/ImageDB.h"
 #include "DB/ResultId.h"
+#include "DB/Result.h"
 
 #include <qfileinfo.h>
 #include <QProgressDialog>
@@ -226,11 +228,77 @@ ImageInfoPtr NewImageFinder::loadExtraFile( const QString& relativeNewFileName,
         }
     }
 
+    QString err = Settings::SettingsData::instance()->modifiedFileComponent();
+    QRegExp modifiedFileComponent =
+        QRegExp(Settings::SettingsData::instance()->modifiedFileComponent());
+    
+    // check to see if this is a new version of a previous image
+    ImageInfoPtr info = ImageInfoPtr(new ImageInfo( relativeNewFileName, type ));
+    ImageInfoPtr originalInfo;
+    QString originalFileName;
+
+    if (Settings::SettingsData::instance()->detectModifiedFiles()) {
+        // should be cached because loading once per image is expensive
+        QString err = Settings::SettingsData::instance()->modifiedFileComponent();
+        QRegExp modifiedFileComponent =
+            QRegExp(Settings::SettingsData::instance()->modifiedFileComponent());
+        // requires at least *something* in the modifiedFileComponent
+        if (err.length() >= 0 &&
+            relativeNewFileName.contains(modifiedFileComponent)) {
+
+            originalFileName = relativeNewFileName;
+            QString originalFileComponent =
+                Settings::SettingsData::instance()->originalFileComponent();
+            originalFileName.replace(modifiedFileComponent, originalFileComponent);
+
+            MD5 originalSum = Utilities::MD5Sum( originalFileName );
+            if ( DB::ImageDB::instance()->md5Map()->contains( originalSum ) ) {
+                // we have a previous copy of this file; copy it's data
+                // from the original.
+                originalInfo = DB::ImageDB::instance()->info( originalFileName, DB::RelativeToImageRoot );
+                if ( !originalInfo ) {
+                    qWarning("How did that happen? We couldn't find info for the original image %s; can't copy the original data to %s", qPrintable(originalFileName), qPrintable(relativeNewFileName));
+                } else {
+                    info->copyExtraData(*originalInfo);
+                }
+
+                /* if requested to move, then delete old data from original */
+                if (Settings::SettingsData::instance()->moveOriginalContents() ) {
+                    originalInfo->removeExtraData();
+                }
+            }
+        }
+    }
+
     // also inserts image into exif db if present:
-    ImageInfoPtr info = ImageInfoPtr( new ImageInfo( relativeNewFileName, type ) );
     info->setMD5Sum(sum);
     DB::ImageDB::instance()->md5Map()->insert( sum, info->fileName(DB::RelativeToImageRoot) );
 
+    if (originalInfo &&
+        Settings::SettingsData::instance()->autoStackNewFiles() ) {
+        // we have to do this immediately to get the ids
+        ImageInfoList newImages;
+        markUnTagged(info);
+        newImages.append(info);
+        DB::ImageDB::instance()->addImages( newImages );
+
+        // stack the files together
+        DB::ResultId olderfile = DB::ImageDB::instance()->ID_FOR_FILE(originalFileName);
+        DB::ResultId newerfile = DB::ImageDB::instance()->ID_FOR_FILE(info->fileName(DB::AbsolutePath));
+        DB::Result tostack = DB::Result();
+
+        tostack.append(newerfile);
+        tostack.append(olderfile);
+        DB::ImageDB::instance()->stack(tostack);
+
+        // ordering: XXX we ideally want to place the new image right
+        // after the older one in the list.
+
+        // XXX: deal with already-stacked items; currently a silent fail
+
+        info = NULL;  // we already added it, so don't process again
+    }
+    
     return info;
 }
 
diff --git a/MainWindow/ExternalPopup.cpp b/MainWindow/ExternalPopup.cpp
index ff14764..f267560 100644
--- a/MainWindow/ExternalPopup.cpp
+++ b/MainWindow/ExternalPopup.cpp
@@ -22,6 +22,7 @@
 #include <qstringlist.h>
 #include <qlabel.h>
 #include <QPixmap>
+#include <QFile>
 #include <kservice.h>
 #include <kurl.h>
 #include <krun.h>
@@ -38,13 +39,13 @@ void MainWindow::ExternalPopup::populate( DB::ImageInfoPtr current, const QStrin
     _currentInfo = current;
     clear();
 
-    QStringList list = QStringList() << i18n("Current Item") << i18n("All Selected Items");
-    for ( int which = 0; which < 2; ++which ) {
+    QStringList list = QStringList() << i18n("Current Item") << i18n("All Selected Items") << i18n("Copy and Open");
+    for ( int which = 0; which < 3; ++which ) {
         if ( which == 0 && !current )
             continue;
 
         const bool multiple = (_list.count() > 1);
-        const bool enabled = (which == 0 && _currentInfo ) || (which == 1 && multiple);
+        const bool enabled = (which != 1 && _currentInfo ) || (which == 1 && multiple);
 
         // Title
         QAction* action = addAction( list[which] );
@@ -81,13 +82,33 @@ void MainWindow::ExternalPopup::slotExecuteService( QAction* action )
     Q_ASSERT( offers.count() >= 1 );
     KService::Ptr ptr = offers.first();
     KUrl::List lst;
+
     if ( action->data() == 1 ) {
         for( QStringList::Iterator it = _list.begin(); it != _list.end(); ++it ) {
             if ( _appToMimeTypeMap[name].contains( mimeType(*it) ) )
                 lst.append( KUrl(*it) );
         }
-    }
-    else {
+    } else if (action->data() == 2) {
+        QString origFile = _currentInfo->fileName(DB::AbsolutePath);
+        QString newFile = origFile;
+
+        QString origRegexpString = 
+            Settings::SettingsData::instance()->copyFileComponent();
+        QRegExp origRegexp =
+            QRegExp(origRegexpString);
+        QString copyFileReplacement = 
+            Settings::SettingsData::instance()->copyFileReplacementComponent();
+        
+        if (origRegexpString.length() > 0) {
+            newFile.replace(origRegexp, copyFileReplacement);
+            QFile::copy(origFile, newFile);
+            lst.append( newFile );
+        } else {
+            qWarning("No settings were appropriate for modifying the file name (you must fill in the regexp field; Opening the original instead");
+            lst.append( origFile );
+        }
+
+    } else {
         lst.append( KUrl(_currentInfo->fileName(DB::AbsolutePath)));
     }
 
diff --git a/Settings/GeneralPage.cpp b/Settings/GeneralPage.cpp
index 369b201..4ade1f7 100644
--- a/Settings/GeneralPage.cpp
+++ b/Settings/GeneralPage.cpp
@@ -6,6 +6,7 @@
 #include <QSpinBox>
 #include <QCheckBox>
 #include <QHBoxLayout>
+#include <QLineEdit>
 #include <QLabel>
 #include <QWidget>
 #include <Q3VGroupBox>
@@ -40,6 +41,29 @@ Settings::GeneralPage::GeneralPage( QWidget* parent )
     _searchForImagesOnStart = new QCheckBox( i18n("Search for new images and videos on startup"), box );
     _skipRawIfOtherMatches = new QCheckBox( i18n("Do not read RAW files if a matching JPEG/TIFF file exists"), box );
 
+    // Original/Modified File Support
+    Q3VGroupBox* modifiedBox = new Q3VGroupBox( i18n("Modified File Detection Settings"), this );
+    lay1->addWidget( modifiedBox );
+
+    _detectModifiedFiles = new QCheckBox(i18n("Try and detect modified files"), modifiedBox);
+
+    QLabel* modifiedFileComponentLabel = new QLabel( i18n("Modified file search regexp:" ), modifiedBox );
+    _modifiedFileComponent = new QLineEdit(modifiedBox);
+
+    QLabel* originalFileComponentLabel = new QLabel( i18n("Original file replacement text:" ), modifiedBox );
+    _originalFileComponent = new QLineEdit(modifiedBox);
+
+    _moveOriginalContents = new QCheckBox(i18n("Move meta-data (i.e. delete tags from the original):"), modifiedBox);
+
+    _autoStackNewFiles = new QCheckBox(i18n("Auto-stack new files on top of old:"), modifiedBox);
+
+    QLabel* copyFileComponentLabel = new QLabel( i18n("Copy file search regexp:" ), modifiedBox );
+    _copyFileComponent = new QLineEdit(modifiedBox);
+
+    QLabel* copyFileReplacementComponentLabel = new QLabel( i18n("Copy file replacement text:" ), modifiedBox );
+    _copyFileReplacementComponent = new QLineEdit(modifiedBox);
+
+
     // Datebar size
     container = new QWidget( this );
     lay1->addWidget( container );
@@ -133,6 +157,21 @@ Settings::GeneralPage::GeneralPage( QWidget* parent )
 
     txt = i18n( "Show the KPhotoAlbum splash screen on start up" );
     _showSplashScreen->setWhatsThis( txt );
+
+    txt = i18n( "<p>When KPhotoAlbum searches for new files and finds a file that matches the <i>modified file search regexp</i> it is assumed that an original version of the image may exist.  The regexp pattern will be replaced with the <i>original file string</i> text and if that file exists, all associated metadata (category information, ratings, etc) will be copied from the original file to the new one.</p>");
+    _detectModifiedFiles->setWhatsThis( txt );
+    modifiedFileComponentLabel->setWhatsThis( txt );
+    _modifiedFileComponent->setWhatsThis( txt );
+    originalFileComponentLabel->setWhatsThis( txt );
+    _originalFileComponent->setWhatsThis( txt );
+    _moveOriginalContents->setWhatsThis( txt );
+    _autoStackNewFiles->setWhatsThis( txt );
+
+    txt = i18n("<p>KPhotoAlbum can make a copy of an image before opening it with an external program.  These settings set the original rexexp to search for and contents to replace it with when deciding what the new filename should be.</p>");
+    copyFileComponentLabel->setWhatsThis( txt );
+    _copyFileComponent->setWhatsThis( txt );
+    copyFileReplacementComponentLabel->setWhatsThis( txt );
+    _copyFileReplacementComponent->setWhatsThis( txt );
 }
 
 void Settings::GeneralPage::loadSettings( Settings::SettingsData* opt )
@@ -150,6 +189,13 @@ void Settings::GeneralPage::loadSettings( Settings::SettingsData* opt )
         cat = DB::ImageDB::instance()->categoryCollection()->categories()[0];
 
     _albumCategory->setEditText( cat->text() );
+    _detectModifiedFiles->setChecked( opt->detectModifiedFiles() );
+    _modifiedFileComponent->setText( opt->modifiedFileComponent() );
+    _originalFileComponent->setText( opt->originalFileComponent() );
+    _moveOriginalContents->setChecked( opt->moveOriginalContents() );
+    _autoStackNewFiles->setChecked( opt->autoStackNewFiles() );
+    _copyFileComponent->setText( opt->copyFileComponent() );
+    _copyFileReplacementComponent->setText( opt->copyFileReplacementComponent() );
 
 }
 
@@ -167,4 +213,10 @@ void Settings::GeneralPage::saveSettings( Settings::SettingsData* opt )
     opt->setHistogramSize( QSize( _barWidth->value(), _barHeight->value() ) );
 
     opt->setAlbumCategory( name );
+    opt->setDetectModifiedFiles( _detectModifiedFiles->isChecked() );
+    opt->setModifiedFileComponent( _modifiedFileComponent->text() );
+    opt->setOriginalFileComponent( _originalFileComponent->text() );
+    opt->setAutoStackNewFiles( _autoStackNewFiles->isChecked() );
+    opt->setCopyFileComponent( _copyFileComponent->text() );
+    opt->setCopyFileReplacementComponent( _copyFileReplacementComponent->text() );
 }
diff --git a/Settings/GeneralPage.h b/Settings/GeneralPage.h
index 8923233..4200a6b 100644
--- a/Settings/GeneralPage.h
+++ b/Settings/GeneralPage.h
@@ -3,6 +3,7 @@
 #include <QWidget>
 
 class QComboBox;
+class QLineEdit;
 class QSpinBox;
 class QCheckBox;
 class KComboBox;
@@ -27,6 +28,13 @@ private:
     QSpinBox* _barHeight;
     QCheckBox* _showSplashScreen;
     QComboBox* _albumCategory;
+    QCheckBox* _detectModifiedFiles;
+    QLineEdit* _modifiedFileComponent;
+    QLineEdit* _originalFileComponent;
+    QCheckBox* _moveOriginalContents;
+    QCheckBox* _autoStackNewFiles;
+    QLineEdit* _copyFileComponent;
+    QLineEdit* _copyFileReplacementComponent;
 };
 }
 
diff --git a/Settings/SettingsData.cpp b/Settings/SettingsData.cpp
index 0650b39..33649f7 100644
--- a/Settings/SettingsData.cpp
+++ b/Settings/SettingsData.cpp
@@ -161,6 +161,13 @@ property_copy( showSplashScreen      , setShowSplashScreen      , bool
 property_copy( autoSave              , setAutoSave              , int           , General, 5                          )
 property_copy( backupCount           , setBackupCount           , int           , General, 5                          )
 property_enum( tTimeStamps           , setTTimeStamps           , TimeStampTrust, General, Always                     )
+property_copy( detectModifiedFiles   , setDetectModifiedFiles   , bool          , General, false                       )
+property_copy( modifiedFileComponent , setModifiedFileComponent , QString          , General, i18n("")                )
+property_copy( originalFileComponent , setOriginalFileComponent , QString          , General, i18n("")                )
+property_copy( moveOriginalContents  , setMoveOriginalContents  , bool          , General, false                      )
+property_copy( autoStackNewFiles     , setAutoStackNewFiles     , bool          , General, true                       )
+property_copy( copyFileComponent     , setCopyFileComponent     , QString       , General, i18n("")                   )
+property_copy( copyFileReplacementComponent , setCopyFileReplacementComponent , QString          , General, i18n("")                )
 
 getValueFunc( QSize,histogramSize,  General,QSize(15,30) )
 getValueFunc( ViewSortType,viewSortType,  General,(int)SortLastUse )
diff --git a/Settings/SettingsData.h b/Settings/SettingsData.h
index b6f8671..e29bb1d 100644
--- a/Settings/SettingsData.h
+++ b/Settings/SettingsData.h
@@ -86,6 +86,13 @@ public:
     property_copy( backupCount           , setBackupCount           , int );
     property_copy( viewSortType          , setViewSortType          , ViewSortType   );
     property_copy( tTimeStamps           , setTTimeStamps           , TimeStampTrust );
+    property_copy( detectModifiedFiles   , setDetectModifiedFiles   , bool );
+    property_copy( modifiedFileComponent , setModifiedFileComponent , QString );
+    property_copy( originalFileComponent , setOriginalFileComponent , QString );
+    property_copy( moveOriginalContents  , setMoveOriginalContents  , bool );
+    property_copy( autoStackNewFiles     , setAutoStackNewFiles  , bool );
+    property_copy( copyFileComponent     , setCopyFileComponent , QString );
+    property_copy( copyFileReplacementComponent , setCopyFileReplacementComponent , QString );
 
     bool trustTimeStamps();
 
