2008-09-13 16:24:43 +00:00
#region Disclaimer / License
2009-02-10 23:36:15 +00:00
// Copyright (C) 2009, Kenneth Skovhede
2008-09-13 16:24:43 +00:00
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
using System ;
using System.Collections.Generic ;
using System.Windows.Forms ;
using System.Data.LightDatamodel ;
using System.Drawing ;
using Duplicati.Datamodel ;
2008-09-13 16:32:45 +00:00
namespace Duplicati.GUI
2008-09-13 16:24:43 +00:00
{
static class Program
{
/// <summary>
/// This is the only access to the database
/// </summary>
public static IDataFetcherCached DataConnection ;
/// <summary>
/// This is the TrayIcon instance
/// </summary>
public static NotifyIcon TrayIcon ;
/// <summary>
/// This is the lock to be used before manipulating the shared resources
/// </summary>
public static object MainLock = new object ();
public static ServiceStatus StatusDialog ;
public static ServiceSetup SetupDialog ;
public static WizardHandler Wizard ;
public static ApplicationSettings ApplicationSettings ;
/// <summary>
/// This is the scheduling thread
/// </summary>
public static Scheduler Scheduler ;
/// <summary>
/// This is the working thread
/// </summary>
public static WorkerThread < IDuplicityTask > WorkThread ;
2009-02-14 17:30:52 +00:00
/// <summary>
/// The path to the file that contains the current database
/// </summary>
public static string DatabasePath ;
2009-03-11 20:56:01 +00:00
/// <summary>
/// The actual runner, do not call directly. Only used for events.
/// </summary>
public static DuplicatiRunner Runner ;
2008-09-13 16:24:43 +00:00
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main ()
{
Application . EnableVisualStyles ();
Application . SetCompatibleTextRenderingDefault ( false );
2009-03-21 16:37:30 +00:00
SingleInstance singleInstance = null ;
try
{
2009-03-21 17:06:45 +00:00
try
{
singleInstance = new SingleInstance ( Application . ProductName );
}
catch ( Exception ex )
{
2009-04-08 19:11:42 +00:00
MessageBox . Show ( "Unable to start up, perhaps another process is already running?\nError message: " + ex . ToString (), Application . ProductName , MessageBoxButtons . OK , MessageBoxIcon . Error );
2009-03-21 17:06:45 +00:00
return ;
}
2009-03-21 16:37:30 +00:00
if (! singleInstance . IsFirstInstance )
2009-04-08 19:11:42 +00:00
{
//Linux shows this output
Console . WriteLine ( "Another instance is running, and was notified" );
2009-03-21 16:37:30 +00:00
return ;
2009-04-08 19:11:42 +00:00
}
2009-03-21 16:37:30 +00:00
singleInstance . SecondInstanceDetected += new SingleInstance . SecondInstanceDelegate ( singleInstance_SecondInstanceDetected );
2008-09-13 16:24:43 +00:00
#if DEBUG
2009-03-21 16:37:30 +00:00
DatabasePath = System . IO . Path . Combine ( Application . StartupPath , "Duplicati.sqlite" );
2008-09-13 16:24:43 +00:00
#else
2009-03-21 16:37:30 +00:00
DatabasePath = System . IO . Path . Combine ( System . IO . Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ), Application . ProductName ), "Duplicati.sqlite" );
2008-09-13 16:24:43 +00:00
#endif
2009-04-08 19:11:42 +00:00
if ( new Version ( System . Data . SQLite . SQLiteConnection . SQLiteVersion ) < new Version ( 3 , 6 , 3 ))
{
//The official Mono SQLite provider is also broken with less than 3.6.3
MessageBox . Show ( "Wrong version of SQLite detected (" + System . Data . SQLite . SQLiteConnection . SQLiteVersion + "), must be 3.6.3 or higher" , Application . ProductName , MessageBoxButtons . OK , MessageBoxIcon . Error );
return ;
}
System . Data . IDbConnection con = new System . Data . SQLite . SQLiteConnection ();
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
try
{
if (! System . IO . Directory . Exists ( System . IO . Path . GetDirectoryName ( DatabasePath )))
System . IO . Directory . CreateDirectory ( System . IO . Path . GetDirectoryName ( DatabasePath ));
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
//This also opens the db for us :)
DatabaseUpgrader . UpgradeDatebase ( con , DatabasePath );
}
catch ( Exception ex )
{
MessageBox . Show ( "Failed to create, open or upgrade the database.\r\nError message: " + ex . Message , Application . ProductName , MessageBoxButtons . OK , MessageBoxIcon . Error );
return ;
}
DataConnection = new DataFetcherWithRelations ( new SQLiteDataProvider ( con ));
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon = new NotifyIcon ();
TrayIcon . ContextMenuStrip = new ContextMenuStrip ();
TrayIcon . Icon = Properties . Resources . TrayNormal ;
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon . ContextMenuStrip . Items . Add ( "Status" , Properties . Resources . StatusMenuIcon , new EventHandler ( Status_Clicked ));
2009-04-01 08:30:14 +00:00
TrayIcon . ContextMenuStrip . Items . Add ( "Wizard ..." , Properties . Resources . WizardMenuIcon , new EventHandler ( Setup_Clicked ));
2009-03-21 16:37:30 +00:00
TrayIcon . ContextMenuStrip . Items . Add ( new ToolStripSeparator ());
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon . ContextMenuStrip . Items . Add ( "Settings" , Properties . Resources . SettingsMenuIcon , new EventHandler ( Settings_Clicked ));
TrayIcon . ContextMenuStrip . Items . Add ( new ToolStripSeparator ());
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon . ContextMenuStrip . Items . Add ( "Quit" , Properties . Resources . CloseMenuIcon , new EventHandler ( Quit_Clicked ));
TrayIcon . ContextMenuStrip . Items [ 0 ]. Font = new Font ( TrayIcon . ContextMenuStrip . Items [ 0 ]. Font , FontStyle . Bold );
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
ApplicationSettings = new ApplicationSettings ( DataConnection );
Runner = new DuplicatiRunner ();
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
WorkThread = new WorkerThread < IDuplicityTask >( new WorkerThread < IDuplicityTask >. ProcessItemDelegate ( Runner . ExecuteTask ));
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
Scheduler = new Scheduler ( DataConnection , WorkThread , MainLock );
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
WorkThread . CompletedWork += new EventHandler ( WorkThread_CompletedWork );
WorkThread . StartingWork += new EventHandler ( WorkThread_StartingWork );
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
DataConnection . AfterDataConnection += new DataConnectionEventHandler ( DataConnection_AfterDataConnection );
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon . Text = "Duplicati ready" ;
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
TrayIcon . DoubleClick += new EventHandler ( TrayIcon_DoubleClick );
TrayIcon . Visible = true ;
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
long count = 0 ;
lock ( MainLock )
count = Program . DataConnection . GetObjects < Schedule >(). Length ;
2009-02-01 23:20:07 +00:00
2009-03-21 16:37:30 +00:00
if ( count == 0 )
{
//TODO: shows the wrong icon... Should run under Application.Run() ...
ShowWizard ();
}
Application . Run ();
}
catch ( Exception ex )
2008-09-13 16:24:43 +00:00
{
2009-03-21 16:37:30 +00:00
MessageBox . Show ( "A serious error occured in Duplicati: " + ex . ToString (), Application . ProductName , MessageBoxButtons . OK , MessageBoxIcon . Error );
2008-09-13 16:24:43 +00:00
}
2009-03-21 16:37:30 +00:00
if ( Scheduler != null )
Scheduler . Terminate ( true );
if ( WorkThread != null )
WorkThread . Terminate ( true );
if ( TrayIcon != null )
TrayIcon . Visible = false ;
if ( singleInstance != null )
singleInstance . Dispose ();
}
2008-09-13 16:24:43 +00:00
2009-03-21 16:37:30 +00:00
static void singleInstance_SecondInstanceDetected ( string [] commandlineargs )
{
//TODO: This actually blocks the app thread, and thus may pile up remote invocations
ShowWizard ();
2008-09-13 16:24:43 +00:00
}
static void DataConnection_AfterDataConnection ( object sender , DataActions action )
{
2009-02-22 21:30:32 +00:00
if ( action == DataActions . Insert || action == DataActions . Update )
Scheduler . Reschedule ();
2008-09-13 16:24:43 +00:00
}
static void WorkThread_StartingWork ( object sender , EventArgs e )
{
2009-03-16 22:28:54 +00:00
TrayIcon . Icon = Properties . Resources . TrayWorking ;
2008-09-13 16:24:43 +00:00
TrayIcon . Text = "Duplicati running " + ( WorkThread . CurrentTask == null ? "" : WorkThread . CurrentTask . Schedule . Name );
}
static void WorkThread_CompletedWork ( object sender , EventArgs e )
{
2009-03-16 22:28:54 +00:00
TrayIcon . Icon = Properties . Resources . TrayNormal ;
2008-09-13 16:24:43 +00:00
TrayIcon . Text = "Duplicati ready" ;
}
private static void Quit_Clicked ( object sender , EventArgs e )
{
Application . Exit ();
}
private static void Settings_Clicked ( object sender , EventArgs e )
{
ShowSettings ();
}
private static void Status_Clicked ( object sender , EventArgs e )
{
ShowStatus ();
}
private static void Setup_Clicked ( object sender , EventArgs e )
{
ShowWizard ();
}
private static void TrayIcon_DoubleClick ( object sender , EventArgs e )
{
ShowStatus ();
}
public static void ShowStatus ()
{
2009-04-08 19:11:42 +00:00
//TODO: Guard against calls from other threads
2008-09-13 16:24:43 +00:00
if ( StatusDialog == null || ! StatusDialog . Visible )
StatusDialog = new ServiceStatus ();
StatusDialog . Show ();
StatusDialog . Activate ();
}
public static void ShowWizard ()
{
2009-04-08 19:11:42 +00:00
//TODO: Guard against calls from other threads
2008-09-13 16:24:43 +00:00
if ( Wizard == null || ! Wizard . Visible )
Wizard = new WizardHandler ();
Wizard . Show ();
}
public static void ShowSetup ()
{
2009-04-08 19:11:42 +00:00
//TODO: Guard against calls from other threads
2008-09-13 16:24:43 +00:00
if ( SetupDialog == null || ! SetupDialog . Visible )
SetupDialog = new ServiceSetup ();
SetupDialog . Show ();
SetupDialog . Activate ();
}
public static void ShowSettings ()
{
2009-04-08 19:11:42 +00:00
//TODO: Guard against calls from other threads
2008-09-13 16:24:43 +00:00
lock ( MainLock )
{
ApplicationSetup dlg = new ApplicationSetup ();
dlg . ShowDialog ();
}
}
}
}