#    Back In Time
#    Copyright (C) 2008-2009 Oprea Dan
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


import os
import os.path
import stat
import sys

if len( os.getenv( 'DISPLAY', '' ) ) == 0:
	os.putenv( 'DISPLAY', ':0.0' )

import datetime
import gettext
import time
import threading

sys.path = [os.path.join( os.path.dirname( os.path.abspath( os.path.dirname( __file__ ) ) ), 'common' )] + sys.path

import backintime
import config
import tools
import logger
import snapshots
import guiapplicationinstance

from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyKDE4.kdecore import *
from PyKDE4.kdeui import *
from PyKDE4.kio import *

import kde4tools
import settingsdialog
import snapshotsdialog


_=gettext.gettext


class MainWindow( KMainWindow ):
	def __init__( self, config, app_instance, kapp, kaboutdata ):
		KMainWindow.__init__( self )

		self.config = config
		self.app_instance = app_instance
		self.kapp = kapp
		self.kaboutdata = kaboutdata
		self.snapshots = snapshots.Snapshots( config )
		self.last_take_snapshot_message = None

		#main toolbar
		self.main_toolbar = self.toolBar()
		self.main_toolbar.setFloatable( False )

		self.btn_take_snapshot = self.main_toolbar.addAction( KIcon( 'document-save' ), '' )
		self.btn_take_snapshot.setToolTip( QString.fromUtf8( _('Take snapshot') ) )
		QObject.connect( self.btn_take_snapshot, SIGNAL('triggered()'), self.on_btn_take_snapshot_clicked )

		self.btn_update_snapshots = self.main_toolbar.addAction( KIcon( 'view-refresh' ), '' )
		self.btn_update_snapshots.setToolTip( QString.fromUtf8( _('Update snapshots') ) )
		QObject.connect( self.btn_update_snapshots, SIGNAL('triggered()'), self.on_btn_update_snapshots_clicked )

		self.btn_name_snapshot = self.main_toolbar.addAction( KIcon( 'edit-rename' ), '' )
		self.btn_name_snapshot.setToolTip( QString.fromUtf8( _('Snapshot Name') ) )
		QObject.connect( self.btn_name_snapshot, SIGNAL('triggered()'), self.on_btn_name_snapshot_clicked )

		self.btn_remove_snapshot = self.main_toolbar.addAction( KIcon( 'edit-delete' ), '' )
		self.btn_remove_snapshot.setToolTip( QString.fromUtf8( _('Remove Snapshot') ) )
		QObject.connect( self.btn_remove_snapshot, SIGNAL('triggered()'), self.on_btn_remove_snapshot_clicked )
	
		self.main_toolbar.addSeparator()

		self.btn_settings = self.main_toolbar.addAction( KIcon( 'configure' ), '' )
		self.btn_settings.setToolTip( QString.fromUtf8( _('Settings') ) )
		QObject.connect( self.btn_settings, SIGNAL('triggered()'), self.on_btn_settings_clicked )

		self.main_toolbar.addSeparator()

		self.btn_about = self.main_toolbar.addAction( KIcon( 'help-about' ), '' )
		self.btn_about.setToolTip( QString.fromUtf8( _('About') ) )
		QObject.connect( self.btn_about, SIGNAL('triggered()'), self.on_btn_about_clicked )

		self.btn_help = self.main_toolbar.addAction( KIcon( 'help-contents' ), '' )
		self.btn_help.setToolTip( QString.fromUtf8( _('Help') ) )
		QObject.connect( self.btn_help, SIGNAL('triggered()'), self.on_btn_help_clicked )

		self.main_toolbar.addSeparator()

		self.btn_quit = self.main_toolbar.addAction( KIcon( 'application-exit' ), '' )
		self.btn_quit.setToolTip( QString.fromUtf8( _('Exit') ) )
		QObject.connect( self.btn_quit, SIGNAL('triggered()'), self.close )

		self.main_toolbar.addAction( KToolBarSpacerAction( self ) )

		self.main_toolbar.addSeparator()

		self.btn_link = self.main_toolbar.addAction( KIcon( 'go-home' ), '' )
		self.btn_link.setToolTip( QString.fromUtf8( 'backintime.le-web.org' ) )
		QObject.connect( self.btn_link, SIGNAL('triggered()'), self.open_url )

		#main splitter
		self.main_splitter = QSplitter( self )
		self.main_splitter.setOrientation( Qt.Horizontal )

		#timeline
		self.list_time_line = QTreeWidget( self )
		self.list_time_line.setRootIsDecorated( False )
		self.list_time_line.setEditTriggers( QAbstractItemView.NoEditTriggers )
		self.list_time_line.setHeaderLabel( QString.fromUtf8( _('Snapshots') ) )
		self.main_splitter.addWidget( self.list_time_line )

		#right widget
		self.right_widget = QGroupBox( self )
		self.main_splitter.addWidget( self.right_widget )
		right_layout = QVBoxLayout( self.right_widget )
		#left, top, right, bottom = right_layout.getContentsMargins()
		#right_layout.setContentsMargins( 0, 0, 0, right )

		#files toolbar
		self.files_view_toolbar = KToolBar( self )
		self.files_view_toolbar.setFloatable( False )

		self.btn_folder_up = self.files_view_toolbar.addAction( KIcon( 'go-up' ), '' )
		self.btn_folder_up.setToolTip( QString.fromUtf8( _('Up') ) )
		QObject.connect( self.btn_folder_up, SIGNAL('triggered()'), self.on_btn_folder_up_clicked )

		self.edit_current_path = KLineEdit( self )
		self.edit_current_path.setReadOnly( True )
		self.files_view_toolbar.addWidget( self.edit_current_path )

		#show hidden files
		self.show_hidden_files = self.config.get_bool_value( 'kde4.show_hidden_files', False )

		self.btn_show_hidden_files = KToggleAction( KIcon( 'list-add' ), '', self.files_view_toolbar )
		self.files_view_toolbar.addAction( self.btn_show_hidden_files )
		self.btn_show_hidden_files.setCheckable( True )
		self.btn_show_hidden_files.setChecked( self.show_hidden_files )
		self.btn_show_hidden_files.setToolTip( QString.fromUtf8( _('Show hidden files') ) )
		QObject.connect( self.btn_show_hidden_files, SIGNAL('toggled(bool)'), self.on_btn_show_hidden_files_toggled )

		self.files_view_toolbar.addSeparator()

		self.btn_restore = self.files_view_toolbar.addAction( KIcon( 'document-revert' ), '' )
		self.btn_restore.setToolTip( QString.fromUtf8( _('Restore') ) )
		QObject.connect( self.btn_restore, SIGNAL('triggered()'), self.on_btn_restore_clicked )

		self.btn_copy = self.files_view_toolbar.addAction( KIcon( 'edit-copy' ), '' )
		self.btn_copy.setToolTip( QString.fromUtf8( _('Copy') ) )
		QObject.connect( self.btn_copy, SIGNAL('triggered()'), self.on_btn_copy_to_clipboard_clicked )

		self.btn_snapshots = self.files_view_toolbar.addAction( KIcon( 'view-list-details' ), '' )
		self.btn_snapshots.setToolTip( QString.fromUtf8( _('Snapshots') ) )
		QObject.connect( self.btn_snapshots, SIGNAL('triggered()'), self.on_btn_snapshots_clicked )

		right_layout.addWidget( self.files_view_toolbar )

		#second spliter
		self.second_splitter = QSplitter( self )
		self.second_splitter.setOrientation( Qt.Horizontal )
		right_layout.addWidget( self.second_splitter )

		#places
		self.list_places = QTreeWidget( self )
		self.list_places.setRootIsDecorated( False )
		self.list_places.setEditTriggers( QAbstractItemView.NoEditTriggers )
		self.list_places.setHeaderLabel( QString.fromUtf8( _('Shortcuts') ) )
		self.second_splitter.addWidget( self.list_places )

		#files view stacked layout
		widget = QWidget( self )
		self.files_view_layout = QStackedLayout( widget )
		self.second_splitter.addWidget( widget )

		#folder don't exist label
		self.lbl_folder_dont_exists = QLabel( QString.fromUtf8( _('This folder don\'t exist\nin current snapshot !') ), self )
		kde4tools.set_font_bold( self.lbl_folder_dont_exists )
		self.lbl_folder_dont_exists.setFrameShadow( QFrame.Sunken )
		self.lbl_folder_dont_exists.setFrameShape( QFrame.Panel )
		self.lbl_folder_dont_exists.setAlignment( Qt.AlignHCenter | Qt.AlignVCenter )
		self.files_view_layout.addWidget( self.lbl_folder_dont_exists )

		#list files view
		self.list_files_view = QTreeView( self )
		self.files_view_layout.addWidget( self.list_files_view )
		self.list_files_view.setRootIsDecorated( False )
		self.list_files_view.setAlternatingRowColors( True )
		#self.list_files_view.setAllColumnsShowFocus( True )
		self.list_files_view.setEditTriggers( QAbstractItemView.NoEditTriggers )
		self.list_files_view.setItemsExpandable( False )
		self.list_files_view.setDragEnabled( True )
		self.list_files_view.setDragDropMode( QAbstractItemView.DragOnly )

		self.list_files_view.header().setClickable( True )
		self.list_files_view.header().setMovable( False )
		self.list_files_view.header().setSortIndicatorShown( True )
		
		self.list_files_view_model = KDirModel( self )
		self.list_files_view_model.removeColumns( 3, 2 )
		self.list_files_view_model.dirLister().setAutoErrorHandlingEnabled( False, self )
		self.list_files_view_model.dirLister().setAutoUpdate( False )
		self.list_files_view_model.dirLister().setDelayedMimeTypes( False )
		self.list_files_view_model.dirLister().setMainWindow( self )

		self.list_files_view_sort_filter_proxy = KDirSortFilterProxyModel( self )
		self.list_files_view_sort_filter_proxy.setSourceModel( self.list_files_view_model )

		self.list_files_view.setModel( self.list_files_view_sort_filter_proxy )

		self.list_files_view_delegate = KFileItemDelegate( self )
		self.list_files_view.setItemDelegate( self.list_files_view_delegate )

		for column_index in xrange( 3, self.list_files_view_model.columnCount() ):
			self.list_files_view.hideColumn( column_index )

		sort_column = self.config.get_int_value( 'kde4.main_window.files_view.sort.column', 0 )
		sort_order = self.config.get_bool_value( 'kde4.main_window.files_view.sort.ascending', True )
		if sort_order:
			sort_order = Qt.AscendingOrder
		else:
			sort_order = Qt.DescendingOrder

		self.list_files_view.header().setSortIndicator( sort_column, sort_order )
		self.list_files_view_sort_filter_proxy.sort( self.list_files_view.header().sortIndicatorSection(), self.list_files_view.header().sortIndicatorOrder() )
		QObject.connect( self.list_files_view.header(), SIGNAL('sortIndicatorChanged(int,Qt::SortOrder)'), self.list_files_view_sort_filter_proxy.sort )

		self.files_view_layout.setCurrentWidget( self.list_files_view )

		#
		self.setCentralWidget( self.main_splitter )
		
		self.statusBar().showMessage( QString.fromUtf8( _('Done') ) )

		self.snapshots_list = []
		self.snapshot_id = '/'
		self.path = self.config.get_str_value( 'kde4.last_path', '/' )
		self.edit_current_path.setText( QString.fromUtf8( self.path ) )

		#restore size and position
		x = self.config.get_int_value( 'kde4.main_window.x', -1 )
		y = self.config.get_int_value( 'kde4.main_window.y', -1 )
		if x >= 0 and y >= 0:
			self.move( x, y )

		w = self.config.get_int_value( 'kde4.main_window.width', 800 )
		h = self.config.get_int_value( 'kde4.main_window.height', 500 )
		self.resize( w, h )

		main_splitter_left_w = self.config.get_int_value( 'kde4.main_window.main_splitter_left_w', 150 )
		main_splitter_right_w = self.config.get_int_value( 'kde4.main_window.main_splitter_right_w', 450 )
		sizes = [ main_splitter_left_w, main_splitter_right_w ]
		self.main_splitter.setSizes( sizes )
		
		second_splitter_left_w = self.config.get_int_value( 'kde4.main_window.second_splitter_left_w', 150 )
		second_splitter_right_w = self.config.get_int_value( 'kde4.main_window.second_splitter_right_w', 300 )
		sizes = [ second_splitter_left_w, second_splitter_right_w ]
		self.second_splitter.setSizes( sizes )

		files_view_name_width = self.config.get_int_value( 'kde4.main_window.files_view.name_width', -1 )
		files_view_size_width = self.config.get_int_value( 'kde4.main_window.files_view.size_width', -1 )
		files_view_date_width = self.config.get_int_value( 'kde4.main_window.files_view.date_width', -1 )
		if files_view_name_width > 0 and files_view_size_width > 0 and files_view_date_width > 0:
			self.list_files_view.header().resizeSection( 0, files_view_name_width )
			self.list_files_view.header().resizeSection( 1, files_view_size_width )
			self.list_files_view.header().resizeSection( 2, files_view_date_width )

		self.text_validator = QRegExpValidator( QRegExp( '.*' ), self )

		#
		kde4tools.set_font_bold( self.right_widget )

		#force settingdialog if it is not configured
		if not cfg.is_configured():
			settingsdialog.SettingsDialog( self ).exec_()

		if not cfg.is_configured():
			return

		if not cfg.can_backup():
			KMessageBox.error( self, QString.fromUtf8( _('Can\'t find snapshots folder.\nIf it is on a removable drive please plug it and then press OK') ) )

		QObject.connect( self.list_files_view_model.dirLister(), SIGNAL('completed()'), self.on_dir_lister_completed )
		QObject.connect( self.list_files_view_model.dirLister(), SIGNAL('canceled()'), self.on_dir_lister_completed )

		#populate lists
		self.update_time_line()
		self.update_places()
		self.update_files_view( 0 )

		self.list_files_view.setFocus()

		self.update_snapshot_actions()

		QObject.connect( self.list_time_line, SIGNAL('currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)'), self.on_list_time_line_current_item_changed )
		QObject.connect( self.list_places, SIGNAL('currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)'), self.on_list_places_current_item_changed )
		QObject.connect( self.list_files_view, SIGNAL('activated(const QModelIndex&)'), self.on_list_files_view_item_activated )

		self.force_wait_lock_counter = 0
	
		self.timer_raise_application = QTimer( self )
		self.timer_raise_application.setInterval( 1000 )
		self.timer_raise_application.setSingleShot( False )
		QObject.connect( self.timer_raise_application, SIGNAL('timeout()'), self.raise_application )
		self.timer_raise_application.start()

		self.timer_update_take_snapshot = QTimer( self )
		self.timer_update_take_snapshot.setInterval( 1000 )
		self.timer_update_take_snapshot.setSingleShot( False )
		QObject.connect( self.timer_update_take_snapshot, SIGNAL('timeout()'), self.update_take_snapshot )
		self.timer_update_take_snapshot.start()

	def closeEvent( self, event ):
		self.config.set_str_value( 'kde4.last_path', self.path )

		self.config.set_int_value( 'kde4.main_window.x', self.x() )
		self.config.set_int_value( 'kde4.main_window.y', self.y() )
		self.config.set_int_value( 'kde4.main_window.width', self.width() )
		self.config.set_int_value( 'kde4.main_window.height', self.height() )

		sizes = self.main_splitter.sizes()
		self.config.set_int_value( 'kde4.main_window.main_splitter_left_w', sizes[0] )
		self.config.set_int_value( 'kde4.main_window.main_splitter_right_w', sizes[1] )
	
		sizes = self.second_splitter.sizes()
		self.config.set_int_value( 'kde4.main_window.second_splitter_left_w', sizes[0] )
		self.config.set_int_value( 'kde4.main_window.second_splitter_right_w', sizes[1] )

		self.config.set_int_value( 'kde4.main_window.files_view.name_width', self.list_files_view.header().sectionSize( 0 ) )
		self.config.set_int_value( 'kde4.main_window.files_view.size_width', self.list_files_view.header().sectionSize( 1 ) )
		self.config.set_int_value( 'kde4.main_window.files_view.date_width', self.list_files_view.header().sectionSize( 2 ) )

		self.config.set_bool_value( 'kde4.show_hidden_files', self.show_hidden_files )

		self.config.set_int_value( 'kde4.main_window.files_view.sort.column', self.list_files_view.header().sortIndicatorSection() )
		self.config.set_bool_value( 'kde4.main_window.files_view.sort.ascending', self.list_files_view.header().sortIndicatorOrder() == Qt.AscendingOrder )
		
		self.config.save()

		event.accept()

	def get_default_startup_folder_and_file( self ):
		last_path = self.config.get_str_value( 'gnome.last_path', '' )
		if len(last_path) > 0 and os.path.isdir(last_path):
			return ( last_path, None, False )
		return ( '/', None, False )

	def get_cmd_startup_folder_and_file( self, cmd ):
		if cmd is None:
			cmd = self.app_instance.raise_cmd

		if len( cmd ) < 1:
			return None

		path = None
		show_snapshots = False

		for arg in cmd.split( '\n' ):
			if len( arg ) < 1:
				continue
			if arg == '-s' or arg == '--snapshots':
				show_snapshots = True
				continue
			if arg[0] == '-':
				continue
			if path is None:
				path = arg

		if path is None:
			return None

		if len( path ) < 1:
			return None

		path = os.path.expanduser( path )
		path = os.path.abspath( path )

		if os.path.isdir( path ):
			if len( path ) < 1:
				show_snapshots = False

			if show_snapshots:
				return ( os.path.dirname( path ), path, True )
			else:
				return ( path, '', False )

		if os.path.isfile( path ):
			return ( os.path.dirname( path ), path, show_snapshots )

		return None

	def get_startup_folder_and_file( self, cmd = None ):
		startup_folder = self.get_cmd_startup_folder_and_file( cmd )
		if startup_folder is None:
			return self.get_default_startup_folder_and_file()
		return startup_folder

	def raise_application( self ):
		raise_cmd = self.app_instance.raise_command()
		if raise_cmd is None:
			return
		
		print "Raise cmd: " + raise_cmd
		self.kapp.alert( self )

	def update_take_snapshot( self, force_wait_lock = False ):
		if force_wait_lock:
			self.force_wait_lock_counter = 10
		
		busy = self.snapshots.is_busy()
		if busy:
			self.force_wait_lock_counter = 0

		if self.force_wait_lock_counter > 0:
			self.force_wait_lock_counter = self.force_wait_lock_counter - 1

		fake_busy = busy or self.force_wait_lock_counter > 0

		if fake_busy:
			take_snapshot_message = None

			if busy:
				take_snapshot_message = self.snapshots.get_take_snapshot_message()

			if take_snapshot_message is None:
				take_snapshot_message = ( 0, '...' )

			if take_snapshot_message != self.last_take_snapshot_message:
				self.last_take_snapshot_message = take_snapshot_message
				self.statusBar().showMessage( QString.fromUtf8( _('Working:') + ' ' + self.last_take_snapshot_message[1].replace( '\n', ' ' ) ) )

			if self.btn_take_snapshot.isEnabled():
				self.btn_take_snapshot.setEnabled( False )
		elif not self.btn_take_snapshot.isEnabled():
			self.btn_take_snapshot.setEnabled( True )
			
			snapshots_list = self.snapshots.get_snapshots_list()

			if snapshots_list != self.snapshots_list:
				self.snapshots_list = snapshots_list
				self.update_time_line( False )
			 	self.statusBar().showMessage( QString.fromUtf8( _('Done') ) )
			else:
				self.statusBar().showMessage( QString.fromUtf8( _('Done, no backup needed') ) )

		if not fake_busy:
			self.last_take_snapshot_message = None

	def on_list_places_current_item_changed( self, item, previous ):
		if item is None:
			return

		path = str( item.data( 0, Qt.UserRole ).toString().toUtf8() )
		if len( path ) == 0:
			return

		if path == self.path:
			return

		self.path = path
		self.update_files_view( 3 )

	def add_place( self, name, path, icon ):
		item = QTreeWidgetItem()

		item.setText( 0, name )

		if len( icon ) > 0:
			item.setIcon( 0, KIcon( icon ) )

		item.setData( 0, Qt.UserRole, QVariant( QString.fromUtf8( path ) ) )

		if len( path ) == 0:
			item.setFont( 0, kde4tools.get_font_bold( item.font( 0 ) ) )
			#item.setFlags( Qt.NoItemFlags )
			item.setFlags( Qt.ItemIsEnabled )
			item.setBackgroundColor( 0, QColor( 196, 196, 196 ) )

		self.list_places.addTopLevelItem( item )

		if path == self.path:
			self.list_places.setCurrentItem( item )

		return item

	def update_places( self ):
		self.list_places.clear()
		self.add_place( QString.fromUtf8( _('Global') ), '', '' )
		self.add_place( QString.fromUtf8( _('Root') ), '/', 'computer' )
		self.add_place( QString.fromUtf8( _('Home') ), os.path.expanduser( '~' ), 'user-home' )

		#add backup folders
		include_folders = self.config.get_include_folders()
		if len( include_folders ) > 0:
			self.add_place( QString.fromUtf8( _('Backup folders') ), '', '' )
			for folder in include_folders:
				self.add_place( QString.fromUtf8(folder[0]), folder[0], 'document-save' )

	def update_snapshot_actions( self ):
		enabled = False

		item = self.list_time_line.currentItem()
		if not item is None:
			if len( self.time_line_get_snapshot_id( item ) ) > 1:
				enabled = True

		#update remove/name snapshot buttons
		self.btn_name_snapshot.setEnabled( enabled )
		self.btn_remove_snapshot.setEnabled( enabled )

	def on_list_time_line_current_item_changed( self, item, previous ):
		self.update_snapshot_actions()

		if item is None:
			return

		snapshot_id = self.time_line_get_snapshot_id( item )
		if len( snapshot_id ) == 0:
			#self.list_time_line.setCurrentItem( previous )
			return

		if snapshot_id == self.snapshot_id:
			return

		self.snapshot_id = snapshot_id
		self.update_files_view( 2 )

	def time_line_get_snapshot_id( self, item ):
		return str( item.data( 0, Qt.UserRole ).toString().toUtf8() ) 

	def time_line_update_snapshot_name( self, item ):
		snapshot_id = self.time_line_get_snapshot_id( item )
		if len( snapshot_id ) > 0:
			item.setText( 0, self.snapshots.get_snapshot_display_name( snapshot_id ) )

	def add_time_line( self, snapshot_name, snapshot_id ):
		item = QTreeWidgetItem()
		item.setText( 0, snapshot_name )

		item.setData( 0, Qt.UserRole, QVariant( QString.fromUtf8( snapshot_id ) ) )

		if len( snapshot_id ) == 0:
			item.setFont( 0, kde4tools.get_font_bold( item.font( 0 ) ) )
			#item.setFlags( Qt.NoItemFlags )
			item.setFlags( Qt.ItemIsEnabled )
			item.setBackgroundColor( 0, QColor( 196, 196, 196 ) )

		self.list_time_line.addTopLevelItem( item )

		return item

	def update_time_line( self, get_snapshots_list = True ):
		self.list_time_line.clear()
		self.add_time_line( QString.fromUtf8( self.snapshots.get_snapshot_display_name( '/' ) ), '/' )

		if get_snapshots_list:
			self.snapshots_list = self.snapshots.get_snapshots_list() 

		groups = []
		now = datetime.date.today()

		#today
		date = now
		groups.append( (QString.fromUtf8( _('Today') ), self.snapshots.get_snapshot_id( date ), []) )

		#yesterday
		date = now - datetime.timedelta( days = 1 )
		groups.append( (QString.fromUtf8( _('Yesterday') ), self.snapshots.get_snapshot_id( date ), []) )

		#this week
		date = now - datetime.timedelta( days = now.weekday() )
		groups.append( (QString.fromUtf8( _('This week') ), self.snapshots.get_snapshot_id( date ), []) )

		#last week
		date = now - datetime.timedelta( days = now.weekday() + 7 )
		groups.append( (QString.fromUtf8( _('Last week') ), self.snapshots.get_snapshot_id( date ), []) )

		#fill groups
		for snapshot_id in self.snapshots_list:
			found = False

			for group in groups:
				if snapshot_id >= group[1]:
					group[2].append( snapshot_id )
					found = True
					break

			if not found:
				year = int( snapshot_id[ 0 : 4 ] )
				month = int( snapshot_id[ 4 : 6 ] )
				date = datetime.date( year, month, 1 )

				group_name = ''
				if year == now.year:
					group_name = date.strftime( '%B' ).capitalize()
				else:
					group_name = date.strftime( '%B, %Y' ).capitalize()

				groups.append( ( QString.fromUtf8( group_name ), self.snapshots.get_snapshot_id( date ), [ snapshot_id ]) )

		#fill time_line list
		for group in groups:
			if len( group[2] ) > 0:
				self.add_time_line( group[0], '' );
				for snapshot_id in group[2]:
					list_item = self.add_time_line( self.snapshots.get_snapshot_display_name( snapshot_id ), snapshot_id )
					if snapshot_id == self.snapshot_id:
						self.list_time_line.setCurrentItem( list_item )

		if self.list_time_line.currentItem() is None:
			self.list_time_line.setCurrentItem( self.list_time_line.topLevelItem( 0 ) )
			if self.snapshot_id != '/':
				self.snapshot_id = '/'
				self.update_files_view( 2 )

	def on_btn_take_snapshot_clicked( self ):
		backintime.take_snapshot_now_async()
		self.update_take_snapshot( True )

	def on_btn_update_snapshots_clicked( self ):
		self.update_time_line()
		self.update_files_view( 2 )

	def on_btn_name_snapshot_clicked( self ):
		item = self.list_time_line.currentItem()
		if item is None:
			return

		snapshot_id = self.time_line_get_snapshot_id( item )
		if len( snapshot_id ) <= 1:
			return

		name = self.snapshots.get_snapshot_name( snapshot_id )

		ret_val = KInputDialog.getText( QString.fromUtf8( _( 'Snapshot Name' ) ), '', name, self, self.text_validator )
		if not ret_val[1]:
			return
		
		new_name = str( ret_val[0].toUtf8() ).strip()
		if name == new_name:
			return

		self.snapshots.set_snapshot_name( snapshot_id, new_name )
		self.time_line_update_snapshot_name( item )

	def on_btn_remove_snapshot_clicked ( self ):
		item = self.list_time_line.currentItem()
		if item is None:
			return

		snapshot_id = self.time_line_get_snapshot_id( item )
		if len( snapshot_id ) <= 1:
			return
		
		if KMessageBox.Yes != KMessageBox.warningYesNo( self, QString.fromUtf8( _('Are you sure you want to remove the snapshot:\n%s') % self.snapshots.get_snapshot_display_name( snapshot_id ) ) ):
			return

		self.snapshots.remove_snapshot( snapshot_id )
		self.update_time_line()

	def on_btn_settings_clicked( self ):
		snapshots_path = self.config.get_snapshots_path()
		include_folders = self.config.get_include_folders()

		settingsdialog.SettingsDialog( self ).exec_()

		update_files_view = ( include_folders != self.config.get_include_folders() )

		if snapshots_path == self.config.get_snapshots_path() and not update_files_view:
		   return

		if update_files_view:
			self.update_places()

		if snapshots_path != self.config.get_snapshots_path():
			self.update_time_line( True )

	def on_btn_about_clicked( self ):
		dlg = KAboutApplicationDialog( self.kaboutdata, self )
		dlg.exec_()

	def on_btn_help_clicked( self ):
		KRun.runCommand( "khelpcenter help:/backintime", self )

	def open_url( self, url = 'http://backintime.le-web.org' ):
		self.run = KRun( KUrl( url ), self, True )

	def on_btn_show_hidden_files_toggled( self, checked ):
		self.show_hidden_files = checked
		self.update_files_view( 1 )

	def on_btn_restore_clicked( self ):
		if len( self.snapshot_id ) <= 1:
			return

		selected_file = str( self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex() ).toString().toUtf8() )
		if len( selected_file ) <= 0:
			return

		rel_path = os.path.join( self.path, selected_file )
		self.snapshots.restore( self.snapshot_id, rel_path )

	def on_btn_copy_to_clipboard_clicked( self ):
		selected_file = str( self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex() ).toString().toUtf8() )
		if len( selected_file ) <= 0:
			return

		path = self.snapshots.get_snapshot_path_to( self.snapshot_id, os.path.join( self.path, selected_file ) )
		kde4tools.clipboard_set_path( self.kapp, path )

	def on_btn_snapshots_clicked( self ):
		selected_file = str( self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex() ).toString().toUtf8() )
		if len( selected_file ) <= 0:
			return

		rel_path = os.path.join( self.path, selected_file )
		icon = None
		if self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex(), Qt.DecorationRole ).type() == QVariant.Icon:
			icon = self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex(), Qt.DecorationRole )

		dlg = snapshotsdialog.SnapshotsDialog( self, self.snapshot_id, rel_path, icon )
		if QDialog.Accepted == dlg.exec_():
			if dlg.snapshot_id != self.snapshot_id:
				for index in xrange( self.list_time_line.topLevelItemCount() ):
					item = self.list_time_line.topLevelItem( index )
					snapshot_id = self.time_line_get_snapshot_id( item )
					if snapshot_id == dlg.snapshot_id:
						self.snapshot_id = dlg.snapshot_id
						self.list_time_line.setCurrentItem( item )
						self.update_files_view( 2 )
						break

	def on_btn_folder_up_clicked( self ):
		if len( self.path ) <= 1:
			return

		path = os.path.dirname( self.path )
		if self.path == path:
			return

		self.path = path
		self.update_files_view( 0 )

	def on_list_files_view_item_activated( self, model_index ):
		if self.kapp.keyboardModifiers() and Qt.ControlModifier:
			return

		if model_index is None:
			return

		rel_path = str( self.list_files_view_sort_filter_proxy.data( model_index ).toString().toUtf8() )
		if len( rel_path ) <= 0:
			return

		rel_path = os.path.join( self.path, rel_path )
		full_path = self.snapshots.get_snapshot_path_to( self.snapshot_id, rel_path )

		if os.path.isdir( full_path ):
			self.path = rel_path
			self.update_files_view( 0 )
		else:
			self.run = KRun( KUrl( full_path ), self, True )

	def files_view_get_name( self, item ):
		return str( item.text( 0 ).toUtf8() )

	def files_view_get_type( self, item ):
		return int( item.text( 4 ) )

	def add_files_view( self, name, size_str, date_str, size_int, type ):
		full_path = self.snapshots.get_snapshot_path_to( self.snapshot_id, os.path.join( self.path, name ) )
		icon = KIcon( KMimeType.iconNameForUrl( KUrl( full_path ) ) )

		item = QTreeWidgetItem( self.list_files_view )

		item.setIcon( 0, icon )
		item.setText( 0, name )
		item.setText( 1, size_str )
		item.setText( 2, date_str )
		item.setText( 3, str( size_int ) )
		item.setText( 4, str( type ) )

		self.list_files_view.addTopLevelItem( item )
		return item

	def update_files_view( self, changed_from, selected_file = None, show_snapshots = False ): #0 - files view change directory, 1 - files view, 2 - time_line, 3 - places
		if 0 == changed_from or 3 == changed_from:
			selected_file = ''

		if 0 == changed_from:
			#update places
			self.list_places.setCurrentItem( None )
			for place_index in xrange( self.list_places.topLevelItemCount() ):
				item = self.list_places.topLevelItem( place_index )
				if self.path == str( item.data( 0, Qt.UserRole ).toString().toUtf8() ):
					self.list_places.setCurrentItem( item )
					break

		tooltip = ''
		text = ''
		if len( self.snapshot_id ) > 1:
			name = self.snapshots.get_snapshot_display_id( self.snapshot_id )
			text = _('Snapshot: %s') % name
			tooltip = _('View the snapshot made at %s') % name
		else:
			tooltip = _('View the current disk content')
			text = _('Now')

		self.right_widget.setTitle( QString.fromUtf8( _( text ) ) )
		self.right_widget.setToolTip( QString.fromUtf8( _( tooltip ) ) )

		#try to keep old selected file
		if selected_file is None:
			selected_file = str( self.list_files_view_sort_filter_proxy.data( self.list_files_view.currentIndex() ).toString().toUtf8() )

		self.selected_file = selected_file
	
		#update files view
		full_path = self.snapshots.get_snapshot_path_to( self.snapshot_id, self.path )

		if os.path.isdir( full_path ):
			self.list_files_view_model.dirLister().setShowingDotFiles( self.show_hidden_files )
			self.list_files_view_model.dirLister().openUrl( KUrl( QString.fromUtf8( full_path ) ), KDirLister.Reload )
			self.files_view_toolbar.setEnabled( False )
			self.files_view_layout.setCurrentWidget( self.list_files_view )
		else:
			self.btn_restore.setEnabled( False )
			self.btn_copy.setEnabled( False )
			self.btn_snapshots.setEnabled( False )
			self.files_view_layout.setCurrentWidget( self.lbl_folder_dont_exists )

		#show current path
		self.edit_current_path.setText( QString.fromUtf8( self.path ) )

		#update folder_up button state
		self.btn_folder_up.setEnabled( len( self.path ) > 1 )

#		#show snapshots
#		if show_snapshots:
#			self.on_btn_snapshots_clicked( None )

	def on_dir_lister_completed( self ):
		has_files = ( self.list_files_view_model.rowCount() > 0 )

		#update restore button state
		self.btn_restore.setEnabled( len( self.snapshot_id ) > 1 and has_files )

		#update copy button state
		self.btn_copy.setEnabled( has_files )

		#update snapshots button state
		self.btn_snapshots.setEnabled( has_files )

		#enable files toolbar
		self.files_view_toolbar.setEnabled( True )

		#select selected_file
		found = False

		if len( self.selected_file ) > 0:
			for index in xrange( self.list_files_view_sort_filter_proxy.rowCount() ):
				model_index = self.list_files_view_sort_filter_proxy.index( index, 0 )
				file_name = str( self.list_files_view_sort_filter_proxy.data( model_index ).toString().toUtf8() )
				if file_name == self.selected_file:
					self.list_files_view.setCurrentIndex( model_index )
					found = True
					break
			self.selected_file = ''

		if not found and has_files:
			self.list_files_view.setCurrentIndex( self.list_files_view_sort_filter_proxy.index( 0, 0 ) )


class KDE4TakeSnapshotCallback( threading.Thread ): #used to display status icon
	def __init__( self ):
		threading.Thread.__init__( self )
		self.stop_flag = False
		self.cfg = None

	def init( self, cfg ):
		self.cfg = cfg
		self.snapshots = snapshots.Snapshots( self.cfg )

	def snapshot_begin( self ):
		self.stop_flag = False
		self.start()

	def snapshot_end( self ):
		self.stop_flag = True
		try:
			self.join()
		except:
			pass

	def show_popup( self ):
		if not self.popup is None:
			self.popup.deleteLater()
			self.popup = None

		if not self.last_message is None:
			self.popup = KPassivePopup.message( self.cfg.APP_NAME, QString.fromUtf8( self.last_message[1] ), self.status_icon )
			self.popup.setAutoDelete( False )

	def run(self):
		logger.info( '[KDE4TakeSnapshotCallback.run]' )

		if not check_x_server():
			logger.info( '[KDE4TakeSnapshotCallback.run] no X server' )
			return

		logger.info( '[KDE4TakeSnapshotCallback.run] begin loop' )

		kapp, kaboutdata = create_kapplication( self.cfg )
		self.last_message = None

		self.status_icon = KSystemTrayIcon()
		self.status_icon.setIcon( KIcon('document-save') )
		#self.status_icon.actionCollection().clear()
		self.status_icon.setContextMenu( None )
		self.status_icon.show()
		self.popup = None
		QObject.connect( self.status_icon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.show_popup )
		first_error = self.cfg.is_notify_enabled()

		while True:
			kapp.processEvents()
		
			if self.stop_flag:
				break

			if not kapp.hasPendingEvents():
				message = self.snapshots.get_take_snapshot_message()
				if message is None and self.last_message is None:
					message = ( 0, _('Working...') )

				if not message is None:
					if message != self.last_message:
						self.last_message = message
						self.status_icon.setToolTip( QString.fromUtf8( self.last_message[1] ) )

						if self.last_message[0] != 0:
							self.status_icon.setIcon( KIcon('document-save-as') )
							if first_error:
								first_error = False
								self.show_popup()
						else:
							self.status_icon.setIcon( KIcon('document-save') )

				time.sleep( 0.2 )
		
		self.status_icon.hide()
		kapp.processEvents()
		
		logger.info( '[KDE4TakeSnapshotCallback.run] end loop' )


def create_kapplication( cfg ):
	kaboutdata = KAboutData( 'backintime', '', ki18n( cfg.APP_NAME ), cfg.VERSION, ki18n( '' ), KAboutData.License_GPL_V2, ki18n( cfg.COPYRIGHT ), ki18n( '' ), 'http://backintime.le-web.org', 'dan@le-web.org' )
	kaboutdata.setProgramIconName( 'document-save' )

	#extra_translations = _('about-translators')
	#if extra_translations is None:
	#	extra_translations = ''
	#elif extra_translations == 'about-translators':
	#	extra_translations = ''
	#
	#translation_text = cfg.get_translations() + extra_translations
	translation_text = cfg.get_translations()
	
	translators = []
	translator_emails = []
	for line in translation_text.split( '\n' ):
		line = line.strip()
		if len( line ) == 0:
			continue
		
		index1 = line.find( ':' )
		if index1 < 0:
			continue

		index2 = line.find( '<', index1 )
		if index2 < 0:
			continue

		index3 = line.find( '>', index2 )
		if index3 < 0:
			continue

		translators.append( line[ index1 + 1 : index2 ].strip() )
		translator_emails.append( line[ index2 + 1 : index3 ].strip() )

	kaboutdata.setTranslator( ki18n( ','.join( translators ) ), ki18n( ','.join( translator_emails ) ) )

	#KCmdLineArgs.init( sys.argv, kaboutdata )
	KCmdLineArgs.init( [sys.argv[0]], kaboutdata )
	return ( KApplication(), kaboutdata )


if __name__ == '__main__':
	cfg = backintime.start_app( 'backintime-kde4' )

	raise_cmd = ''
	if len( sys.argv ) > 1:
		raise_cmd = '\n'.join( sys.argv[ 1 : ] )

	app_instance = guiapplicationinstance.GUIApplicationInstance( cfg.get_app_instance_file(), raise_cmd )

	logger.openlog()
	kapp, kaboutdata = create_kapplication( cfg )

	main_window = MainWindow( cfg, app_instance, kapp, kaboutdata )

	if cfg.is_configured():
		main_window.show()
		kapp.exec_()

	logger.closelog()

	app_instance.exit_application()

