summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2013-01-04 14:50:19 +0100
committerThomas Preud'homme <robotux@celest.fr>2013-01-04 14:50:19 +0100
commit8f9f382e1c97cab2e72e97495650c73ac4b97314 (patch)
tree78510a0d81368c09b56f444fb19bb132c8bc3009
Imported Upstream version 0.3.0.5
-rw-r--r--AuthPlugin.cpp123
-rw-r--r--AuthPlugin.h46
-rw-r--r--COPYING674
-rw-r--r--CliParser.cpp73
-rw-r--r--CliParser.h40
-rw-r--r--CompilerInfo.h17
-rw-r--r--CopyEngineManager.cpp342
-rw-r--r--CopyEngineManager.h102
-rwxr-xr-xCopyListener.cpp413
-rwxr-xr-xCopyListener.h113
-rw-r--r--Core.cpp786
-rw-r--r--Core.h136
-rw-r--r--DebugEngine.cpp386
-rw-r--r--DebugEngine.h114
-rw-r--r--DebugEngineMacro.h26
-rw-r--r--Environment.h19
-rw-r--r--EventDispatcher.cpp163
-rw-r--r--EventDispatcher.h87
-rw-r--r--ExtraSocket.cpp32
-rw-r--r--ExtraSocket.h28
-rw-r--r--FacilityEngine.cpp170
-rw-r--r--FacilityEngine.h70
-rw-r--r--GlobalClass.cpp40
-rw-r--r--GlobalClass.h44
-rw-r--r--HelpDialog.cpp175
-rw-r--r--HelpDialog.h50
-rw-r--r--HelpDialog.ui219
-rwxr-xr-xLanguagesManager.cpp284
-rw-r--r--LanguagesManager.h81
-rw-r--r--LocalListener.cpp265
-rw-r--r--LocalListener.h65
-rw-r--r--LocalPluginOptions.cpp63
-rw-r--r--LocalPluginOptions.h45
-rw-r--r--LogThread.cpp222
-rw-r--r--LogThread.h68
-rwxr-xr-xOptionDialog.cpp724
-rwxr-xr-xOptionDialog.h101
-rw-r--r--OptionDialog.ui905
-rw-r--r--OptionEngine.cpp271
-rw-r--r--OptionEngine.h100
-rw-r--r--PlatformMacro.h61
-rw-r--r--PluginInformation.cpp126
-rw-r--r--PluginInformation.h44
-rw-r--r--PluginInformation.ui136
-rwxr-xr-xPluginLoader.cpp230
-rwxr-xr-xPluginLoader.h79
-rw-r--r--PluginsManager.cpp889
-rw-r--r--PluginsManager.h147
-rw-r--r--README56
-rw-r--r--ResourcesManager.cpp210
-rw-r--r--ResourcesManager.h57
-rw-r--r--SessionLoader.cpp123
-rw-r--r--SessionLoader.h53
-rw-r--r--Singleton.h52
-rw-r--r--StructEnumDefinition.h146
-rw-r--r--StructEnumDefinition_UltracopierSpecific.h57
-rw-r--r--SystrayIcon.cpp388
-rw-r--r--SystrayIcon.h101
-rw-r--r--ThemesManager.cpp245
-rw-r--r--ThemesManager.h90
-rw-r--r--Variable.h39
-rw-r--r--interface/FacilityInterface.h38
-rw-r--r--interface/OptionInterface.h37
-rw-r--r--interface/PluginInterface_CopyEngine.h214
-rw-r--r--interface/PluginInterface_Listener.h48
-rw-r--r--interface/PluginInterface_PluginLoader.h33
-rw-r--r--interface/PluginInterface_SessionLoader.h31
-rw-r--r--interface/PluginInterface_Themes.h123
-rw-r--r--lib/qt-tar-xz/QTarDecode.cpp113
-rw-r--r--lib/qt-tar-xz/QTarDecode.h37
-rw-r--r--lib/qt-tar-xz/QXzDecode.cpp148
-rw-r--r--lib/qt-tar-xz/QXzDecode.h42
-rw-r--r--lib/qt-tar-xz/QXzDecodeThread.cpp50
-rw-r--r--lib/qt-tar-xz/QXzDecodeThread.h39
-rw-r--r--lib/qt-tar-xz/xz.h273
-rw-r--r--lib/qt-tar-xz/xz_config.h123
-rw-r--r--lib/qt-tar-xz/xz_crc32.c52
-rw-r--r--lib/qt-tar-xz/xz_dec_bcj.c564
-rw-r--r--lib/qt-tar-xz/xz_dec_lzma2.c1175
-rw-r--r--lib/qt-tar-xz/xz_dec_stream.c822
-rw-r--r--lib/qt-tar-xz/xz_lzma2.h204
-rw-r--r--lib/qt-tar-xz/xz_private.h159
-rw-r--r--lib/qt-tar-xz/xz_stream.h57
-rw-r--r--main.cpp36
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ar/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ar/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/de/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/de/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/el/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/el/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/es/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/es/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/fr/translation.qmbin0 -> 1268 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/fr/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/hi/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/hi/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/id/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/id/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/it/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/it/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ja/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ja/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/nl/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/nl/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/no/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/no/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/pl/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/pl/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ru/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/ru/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/th/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/th/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/tr/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/tr/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/Languages/zh/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Clean/Languages/zh/translation.ts80
-rw-r--r--plugins-alternative/Themes/Clean/StructEnumDefinition.h1
-rwxr-xr-xplugins-alternative/Themes/Clean/documentation.dox29
-rw-r--r--plugins-alternative/Themes/Clean/factory.cpp70
-rw-r--r--plugins-alternative/Themes/Clean/factory.h39
-rw-r--r--plugins-alternative/Themes/Clean/informations.xml27
-rw-r--r--plugins-alternative/Themes/Clean/interface.cpp415
-rw-r--r--plugins-alternative/Themes/Clean/interface.h146
-rw-r--r--plugins-alternative/Themes/Clean/interface.pro40
-rw-r--r--plugins-alternative/Themes/Clean/interface.ui131
-rw-r--r--plugins-alternative/Themes/Clean/resources.qrc5
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/informations.pngbin0 -> 734 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Caught_Unix.pngbin0 -> 798 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Caught_Windows.pngbin0 -> 563 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Semiuncaught_Unix.pngbin0 -> 1007 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Semiuncaught_Windows.pngbin0 -> 664 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Uncaught_Unix.pngbin0 -> 789 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources/SystemTrayIcon/systray_Uncaught_Windows.pngbin0 -> 551 bytes
-rw-r--r--plugins-alternative/Themes/Clean/resources_unix.qrc7
-rw-r--r--plugins-alternative/Themes/Clean/resources_windows.qrc7
-rw-r--r--plugins-alternative/Themes/Teracopy/DebugEngineMacro.h25
-rw-r--r--plugins-alternative/Themes/Teracopy/Environment.h11
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ar/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ar/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/de/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/de/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/el/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/el/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/es/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/es/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/fr/translation.qmbin0 -> 3356 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/fr/translation.ts113
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/hi/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/hi/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/id/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/id/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/it/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/it/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ja/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ja/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/nl/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/nl/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/no/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/no/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/pl/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/pl/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ru/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/ru/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/th/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/th/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/tr/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/tr/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/zh/translation.qmbin0 -> 327 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/Languages/zh/translation.ts109
-rw-r--r--plugins-alternative/Themes/Teracopy/StructEnumDefinition.h1
-rw-r--r--plugins-alternative/Themes/Teracopy/Variable.h16
-rwxr-xr-xplugins-alternative/Themes/Teracopy/documentation.dox29
-rw-r--r--plugins-alternative/Themes/Teracopy/factory.cpp83
-rw-r--r--plugins-alternative/Themes/Teracopy/factory.h46
-rw-r--r--plugins-alternative/Themes/Teracopy/informations.xml27
-rw-r--r--plugins-alternative/Themes/Teracopy/interface.cpp529
-rw-r--r--plugins-alternative/Themes/Teracopy/interface.h174
-rw-r--r--plugins-alternative/Themes/Teracopy/interface.pro42
-rw-r--r--plugins-alternative/Themes/Teracopy/interface.ui415
-rw-r--r--plugins-alternative/Themes/Teracopy/resources.qrc12
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/add.pngbin0 -> 564 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/exit.pngbin0 -> 775 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/informations.pngbin0 -> 734 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/options.pngbin0 -> 660 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Caught_Unix.pngbin0 -> 798 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Caught_Windows.pngbin0 -> 563 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Semiuncaught_Unix.pngbin0 -> 1007 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Semiuncaught_Windows.pngbin0 -> 664 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Uncaught_Unix.pngbin0 -> 789 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/SystemTrayIcon/systray_Uncaught_Windows.pngbin0 -> 551 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/checkbox.pngbin0 -> 654 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/main.pngbin0 -> 563 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources/player_play.pngbin0 -> 501 bytes
-rw-r--r--plugins-alternative/Themes/Teracopy/resources_unix.qrc7
-rw-r--r--plugins-alternative/Themes/Teracopy/resources_windows.qrc7
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/AvancedQFile.cpp94
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/AvancedQFile.h32
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/CompilerInfo.h1
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/DebugEngineMacro.h25
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Environment.h12
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/ar/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/de/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/el/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/es/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/fr/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/hi/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/id/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/it/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/ja/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/nl/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/no/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/pl/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/pt/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/ru/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/th/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/tr/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Languages/zh/translation.ts459
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/ListThread.cpp1479
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/ListThread.h340
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/ListThread_InodeAction.cpp54
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/MkPath.cpp100
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/MkPath.h56
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/ReadThread.cpp513
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/ReadThread.h137
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/RmPath.cpp127
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/RmPath.h56
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/StructEnumDefinition.h1
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/StructEnumDefinition_CopyEngine.h51
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/TransferThread.cpp977
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/TransferThread.h202
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/Variable.h33
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/WriteThread.cpp344
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/WriteThread.h114
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/copyEngine-collision-and-error.cpp565
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/copyEngine.cpp492
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/copyEngine.h293
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/copyEngine.pro68
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/debugDialog.cpp70
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/debugDialog.h40
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/debugDialog.ui100
-rwxr-xr-xplugins/CopyEngine/Ultracopier-0.3/documentation.dox41
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/factory.cpp239
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/factory.h81
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileErrorDialog.cpp78
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileErrorDialog.h45
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileErrorDialog.ui220
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileExistsDialog.cpp176
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileExistsDialog.h56
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileExistsDialog.ui367
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileIsSameDialog.cpp143
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileIsSameDialog.h53
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/fileIsSameDialog.ui192
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/folderExistsDialog.cpp96
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/folderExistsDialog.h50
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/folderExistsDialog.ui282
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/informations.xml27
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/options.ui149
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/scanFileOrFolder.cpp235
-rw-r--r--plugins/CopyEngine/Ultracopier-0.3/scanFileOrFolder.h69
-rw-r--r--plugins/Languages/ar/flag.pngbin0 -> 992 bytes
-rw-r--r--plugins/Languages/ar/informations.xml33
-rw-r--r--plugins/Languages/ar/translation.ts865
-rw-r--r--plugins/Languages/de/flag.pngbin0 -> 753 bytes
-rw-r--r--plugins/Languages/de/informations.xml33
-rw-r--r--plugins/Languages/de/translation.ts865
-rw-r--r--plugins/Languages/el/flag.pngbin0 -> 779 bytes
-rw-r--r--plugins/Languages/el/informations.xml33
-rw-r--r--plugins/Languages/el/translation.ts865
-rw-r--r--plugins/Languages/es/flag.pngbin0 -> 782 bytes
-rw-r--r--plugins/Languages/es/informations.xml33
-rw-r--r--plugins/Languages/es/translation.ts871
-rw-r--r--plugins/Languages/fr/flag.pngbin0 -> 738 bytes
-rw-r--r--plugins/Languages/fr/informations.xml36
-rw-r--r--plugins/Languages/fr/translation.ts871
-rw-r--r--plugins/Languages/hi/flag.pngbin0 -> 696 bytes
-rw-r--r--plugins/Languages/hi/informations.xml33
-rw-r--r--plugins/Languages/hi/translation.ts865
-rw-r--r--plugins/Languages/id/flag.pngbin0 -> 659 bytes
-rw-r--r--plugins/Languages/id/informations.xml33
-rw-r--r--plugins/Languages/id/translation.ts865
-rw-r--r--plugins/Languages/it/flag.pngbin0 -> 710 bytes
-rw-r--r--plugins/Languages/it/informations.xml33
-rw-r--r--plugins/Languages/it/translation.ts800
-rw-r--r--plugins/Languages/ja/flag.pngbin0 -> 630 bytes
-rw-r--r--plugins/Languages/ja/informations.xml34
-rw-r--r--plugins/Languages/ja/translation.ts800
-rw-r--r--plugins/Languages/nl/flag.pngbin0 -> 679 bytes
-rw-r--r--plugins/Languages/nl/informations.xml33
-rw-r--r--plugins/Languages/nl/translation.ts865
-rw-r--r--plugins/Languages/no/flag.pngbin0 -> 739 bytes
-rw-r--r--plugins/Languages/no/informations.xml33
-rw-r--r--plugins/Languages/no/translation.ts865
-rw-r--r--plugins/Languages/pl/flag.pngbin0 -> 703 bytes
-rw-r--r--plugins/Languages/pl/informations.xml33
-rw-r--r--plugins/Languages/pl/translation.ts865
-rw-r--r--plugins/Languages/pt/flag.pngbin0 -> 703 bytes
-rw-r--r--plugins/Languages/pt/informations.xml33
-rw-r--r--plugins/Languages/pt/translation.ts865
-rw-r--r--plugins/Languages/ru/flag.pngbin0 -> 676 bytes
-rw-r--r--plugins/Languages/ru/informations.xml33
-rw-r--r--plugins/Languages/ru/translation.ts865
-rw-r--r--plugins/Languages/th/flag.pngbin0 -> 694 bytes
-rw-r--r--plugins/Languages/th/informations.xml33
-rw-r--r--plugins/Languages/th/translation.ts865
-rw-r--r--plugins/Languages/tr/flag.pngbin0 -> 672 bytes
-rw-r--r--plugins/Languages/tr/informations.xml33
-rw-r--r--plugins/Languages/tr/translation.ts865
-rw-r--r--plugins/Languages/zh/flag.pngbin0 -> 576 bytes
-rw-r--r--plugins/Languages/zh/informations.xml36
-rw-r--r--plugins/Languages/zh/translation.ts800
-rw-r--r--plugins/Listener/catchcopy-v0002/DebugEngineMacro.h25
-rw-r--r--plugins/Listener/catchcopy-v0002/Environment.h11
-rw-r--r--plugins/Listener/catchcopy-v0002/StructEnumDefinition.h1
-rw-r--r--plugins/Listener/catchcopy-v0002/Variable.h16
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.cpp379
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.h114
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.cpp31
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.h27
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.cpp735
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.h162
-rwxr-xr-xplugins/Listener/catchcopy-v0002/catchcopy-api-0002/VariablesCatchcopy.h14
-rwxr-xr-xplugins/Listener/catchcopy-v0002/documentation.dox33
-rw-r--r--plugins/Listener/catchcopy-v0002/informations.xml27
-rwxr-xr-xplugins/Listener/catchcopy-v0002/listener.cpp72
-rwxr-xr-xplugins/Listener/catchcopy-v0002/listener.h58
-rw-r--r--plugins/Listener/catchcopy-v0002/listener.pro17
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/DebugEngineMacro.h25
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/Environment.h11
-rw-r--r--plugins/PluginLoader/catchcopy-v0002/PlatformMacro.h1
-rw-r--r--plugins/PluginLoader/catchcopy-v0002/StructEnumDefinition.h1
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/Variable.h16
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/documentation.dox34
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/informations.xml27
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/pluginLoader.cpp464
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/pluginLoader.h50
-rwxr-xr-xplugins/PluginLoader/catchcopy-v0002/pluginLoader.pro17
-rw-r--r--plugins/SessionLoader/KDE4/DebugEngineMacro.h25
-rw-r--r--plugins/SessionLoader/KDE4/Environment.h11
-rw-r--r--plugins/SessionLoader/KDE4/StructEnumDefinition.h1
-rw-r--r--plugins/SessionLoader/KDE4/Variable.h16
-rwxr-xr-xplugins/SessionLoader/KDE4/documentation.dox33
-rw-r--r--plugins/SessionLoader/KDE4/informations.xml27
-rw-r--r--plugins/SessionLoader/KDE4/sessionLoader.cpp51
-rw-r--r--plugins/SessionLoader/KDE4/sessionLoader.h33
-rw-r--r--plugins/SessionLoader/KDE4/sessionLoader.pro11
-rw-r--r--plugins/SessionLoader/Windows/DebugEngineMacro.h25
-rw-r--r--plugins/SessionLoader/Windows/Environment.h11
-rw-r--r--plugins/SessionLoader/Windows/StructEnumDefinition.h1
-rw-r--r--plugins/SessionLoader/Windows/Variable.h16
-rwxr-xr-xplugins/SessionLoader/Windows/documentation.dox33
-rw-r--r--plugins/SessionLoader/Windows/informations.xml27
-rwxr-xr-xplugins/SessionLoader/Windows/sessionLoader.cpp58
-rwxr-xr-xplugins/SessionLoader/Windows/sessionLoader.h31
-rw-r--r--plugins/SessionLoader/Windows/sessionLoader.pro11
-rw-r--r--plugins/Themes/Oxygen/DebugEngineMacro.h25
-rw-r--r--plugins/Themes/Oxygen/Environment.h11
-rw-r--r--plugins/Themes/Oxygen/Languages/ar/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/de/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/el/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/es/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/fr/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/hi/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/id/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/it/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/ja/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/nl/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/no/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/pl/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/pt/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/ru/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/th/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/tr/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/Languages/zh/translation.ts218
-rw-r--r--plugins/Themes/Oxygen/StructEnumDefinition.h1
-rw-r--r--plugins/Themes/Oxygen/TransferModel.cpp402
-rw-r--r--plugins/Themes/Oxygen/TransferModel.h79
-rw-r--r--plugins/Themes/Oxygen/Variable.h16
-rwxr-xr-xplugins/Themes/Oxygen/documentation.dox32
-rw-r--r--plugins/Themes/Oxygen/factory.cpp130
-rw-r--r--plugins/Themes/Oxygen/factory.h59
-rw-r--r--plugins/Themes/Oxygen/informations.xml27
-rwxr-xr-xplugins/Themes/Oxygen/interface.cpp901
-rwxr-xr-xplugins/Themes/Oxygen/interface.h213
-rw-r--r--plugins/Themes/Oxygen/interface.pro46
-rw-r--r--plugins/Themes/Oxygen/interface.ui1019
-rw-r--r--plugins/Themes/Oxygen/options.ui38
-rw-r--r--plugins/Themes/Oxygen/resources.qrc22
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/add.pngbin0 -> 564 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/exit.pngbin0 -> 775 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/informations.pngbin0 -> 734 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/options.pngbin0 -> 660 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Caught_Unix.pngbin0 -> 798 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Caught_Windows.pngbin0 -> 563 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Semiuncaught_Unix.pngbin0 -> 1007 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Semiuncaught_Windows.pngbin0 -> 664 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Uncaught_Unix.pngbin0 -> 789 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/SystemTrayIcon/systray_Uncaught_Windows.pngbin0 -> 551 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/add.pngbin0 -> 564 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/cancel.pngbin0 -> 775 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/export-transfer-list.pngbin0 -> 504 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/import-transfer-list.pngbin0 -> 481 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/main.pngbin0 -> 563 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/moveDown.pngbin0 -> 525 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/moveUp.pngbin0 -> 484 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/player_end.pngbin0 -> 506 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/player_pause.pngbin0 -> 484 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/player_play.pngbin0 -> 501 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/putOnBottom.pngbin0 -> 691 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/putOnTop.pngbin0 -> 650 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/remove.pngbin0 -> 722 bytes
-rw-r--r--plugins/Themes/Oxygen/resources/search.pngbin0 -> 808 bytes
-rw-r--r--plugins/Themes/Oxygen/resources_unix.qrc7
-rw-r--r--plugins/Themes/Oxygen/resources_windows.qrc7
-rw-r--r--resources/Languages/en/flag.pngbin0 -> 779 bytes
-rw-r--r--resources/Languages/en/informations.xml31
-rw-r--r--resources/bug-128x128.pngbin0 -> 12933 bytes
-rw-r--r--resources/document-encrypt.pngbin0 -> 561 bytes
-rw-r--r--resources/img-src/application-exit.svgzbin0 -> 6400 bytes
-rw-r--r--resources/img-src/applications-development.svgzbin0 -> 7861 bytes
-rw-r--r--resources/img-src/arrow-down-double.svgzbin0 -> 5704 bytes
-rw-r--r--resources/img-src/arrow-down.svgzbin0 -> 5072 bytes
-rw-r--r--resources/img-src/arrow-up-double.svgzbin0 -> 5698 bytes
-rw-r--r--resources/img-src/arrow-up.svgzbin0 -> 5071 bytes
-rw-r--r--resources/img-src/checkbox.svgzbin0 -> 3936 bytes
-rw-r--r--resources/img-src/document-encrypt.svgzbin0 -> 20939 bytes
-rw-r--r--resources/img-src/document-preview.svgzbin0 -> 19169 bytes
-rw-r--r--resources/img-src/document-save_16.svgzbin0 -> 4954 bytes
-rw-r--r--resources/img-src/document-save_22.svgzbin0 -> 30302 bytes
-rw-r--r--resources/img-src/drive-removable-media-usb.svgzbin0 -> 4247 bytes
-rw-r--r--resources/img-src/help-about.svgzbin0 -> 13549 bytes
-rw-r--r--resources/img-src/kbugbuster.svgzbin0 -> 20091 bytes
-rw-r--r--resources/img-src/list-add.svgzbin0 -> 4165 bytes
-rw-r--r--resources/img-src/media-playback-pause.svgzbin0 -> 2054 bytes
-rw-r--r--resources/img-src/media-playback-start.svgzbin0 -> 1916 bytes
-rw-r--r--resources/img-src/media-skip-forward.svgzbin0 -> 2065 bytes
-rw-r--r--resources/img-src/process-stop.svgzbin0 -> 4174 bytes
-rw-r--r--resources/img-src/system-shutdown.svgzbin0 -> 6070 bytes
-rw-r--r--resources/img-src/text-formatting.svg11924
-rw-r--r--resources/moveDown.pngbin0 -> 525 bytes
-rw-r--r--resources/moveUp.pngbin0 -> 484 bytes
-rw-r--r--resources/none-128x128.pngbin0 -> 11200 bytes
-rw-r--r--resources/resources-windows.rc30
-rw-r--r--resources/resources.qrc13
-rw-r--r--resources/resources_unix.qrc7
-rw-r--r--resources/resources_windows.qrc7
-rw-r--r--resources/systray_Caught_Unix.pngbin0 -> 798 bytes
-rw-r--r--resources/systray_Caught_Windows.pngbin0 -> 563 bytes
-rw-r--r--resources/systray_Semiuncaught_Unix.pngbin0 -> 1007 bytes
-rw-r--r--resources/systray_Semiuncaught_Windows.pngbin0 -> 664 bytes
-rw-r--r--resources/systray_Uncaught_Unix.pngbin0 -> 789 bytes
-rw-r--r--resources/systray_Uncaught_Windows.pngbin0 -> 551 bytes
-rw-r--r--resources/ultracopier-128x128.pngbin0 -> 7440 bytes
-rw-r--r--resources/ultracopier-16x16.pngbin0 -> 672 bytes
-rw-r--r--resources/ultracopier.desktop20
-rw-r--r--resources/ultracopier.icnsbin0 -> 36804 bytes
-rw-r--r--resources/ultracopier.icobin0 -> 34118 bytes
-rwxr-xr-xultracopier.dox39
-rw-r--r--ultracopier.pro118
458 files changed, 74385 insertions, 0 deletions
diff --git a/AuthPlugin.cpp b/AuthPlugin.cpp
new file mode 100644
index 0000000..fcea81c
--- /dev/null
+++ b/AuthPlugin.cpp
@@ -0,0 +1,123 @@
+/** \file AuthPlugin.cpp
+\brief Define the authentication plugin
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\copyright GNU Public License 3 (GPL3), see the file COPYING */
+
+#include <QDir>
+
+#include "AuthPlugin.h"
+
+AuthPlugin::AuthPlugin()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the overall instance
+ stopIt=false;
+ //set sem to 1
+ sem.release();
+ moveToThread(this);
+}
+
+AuthPlugin::~AuthPlugin()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ stop();
+}
+
+QStringList AuthPlugin::getFileList(const QString &path)
+{
+ QStringList list;
+ QDir dir(path);
+ if(dir.exists())
+ {
+ foreach(QString dirName, dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
+ list<<getFileList(path+dirName+QDir::separator());
+ foreach(QString fileName, dir.entryList(QDir::Files|QDir::NoDotAndDotDot))
+ list<<path+fileName;
+ }
+ return list;
+}
+
+void AuthPlugin::run()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ sem.acquire();
+ stopIt=false;
+ foreach(QString basePath,readPath)
+ {
+ foreach(QString dirSub,searchPathPlugin)
+ {
+ QString pluginComposed=basePath+dirSub+QDir::separator();
+ QDir dir(pluginComposed);
+ if(dir.exists())
+ {
+ foreach(QString dirName, dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
+ {
+ QString pluginBasePath = pluginComposed+dirName+QDir::separator();
+ if(QFile::exists(pluginBasePath+"sign.key"))
+ {
+ QCryptographicHash folderHash(QCryptographicHash::Sha1);
+ QStringList filesList=getFileList(pluginBasePath);
+ if(stopIt)
+ return;
+ QFile keyDescriptor(pluginBasePath+"sign.key");
+ if(keyDescriptor.open(QIODevice::ReadOnly))
+ {
+ if(stopIt)
+ return;
+ bool errorFound=false;
+ foreach(QString fileToAddToCheckSum,filesList)
+ if(fileToAddToCheckSum!=(pluginBasePath+"sign.key"))
+ {
+ QFile fileDescriptor(fileToAddToCheckSum);
+ if(fileDescriptor.open(QIODevice::ReadOnly))
+ {
+ if(stopIt)
+ return;
+ folderHash.addData(fileDescriptor.readAll());
+ fileDescriptor.close();
+ if(stopIt)
+ return;
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Error at open this file: "+fileToAddToCheckSum+", error string: "+fileDescriptor.errorString());
+ errorFound=true;
+ break;
+ }
+ }
+ if(!errorFound)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"folder: \""+pluginBasePath+"\", hash: "+QString(folderHash.result().toHex()));
+ QByteArray key=keyDescriptor.readAll();
+ if(key==folderHash.result())
+ emit authentifiedPath(pluginBasePath);
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"This plugin have wrong authentification");
+ }
+ keyDescriptor.close();
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"file: \""+pluginBasePath+"sign.key\", unable to open the key file: "+keyDescriptor.errorString());
+ }
+ }
+ }
+ }
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"stop()");
+ sem.release();
+}
+
+void AuthPlugin::loadSearchPath(const QStringList &readPath,const QStringList &searchPathPlugin)
+{
+ this->readPath=readPath;
+ this->searchPathPlugin=searchPathPlugin;
+}
+
+void AuthPlugin::stop()
+{
+ stopIt=true;
+ sem.acquire();
+ sem.release();
+}
diff --git a/AuthPlugin.h b/AuthPlugin.h
new file mode 100644
index 0000000..dda14ac
--- /dev/null
+++ b/AuthPlugin.h
@@ -0,0 +1,46 @@
+/** \file AuthPlugin.h
+\brief Define the authentication plugin
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef AUTHPLUGIN_H
+#define AUTHPLUGIN_H
+
+#include <QThread>
+#include <QObject>
+#include <QSemaphore>
+#include <QStringList>
+#include <QString>
+#include <QCryptographicHash>
+
+#include "Environment.h"
+
+/** \brief allow authentify the plugin */
+class AuthPlugin : public QThread
+{
+ Q_OBJECT
+public:
+ AuthPlugin();
+ ~AuthPlugin();
+ /** \brief stop all action to close ultracopier */
+ void stop();
+ /** \brief add path to check
+ \param readPath list of read place
+ \param searchPathPlugin list of plugin place
+ */
+ void loadSearchPath(const QStringList &readPath,const QStringList &searchPathPlugin);
+protected:
+ void run();
+private:
+ bool stopIt;
+ QSemaphore sem;
+ QStringList readPath;
+ QStringList searchPathPlugin;
+ static QStringList getFileList(const QString &path);
+signals:
+ void authentifiedPath(QString);
+};
+
+#endif // AUTHPLUGIN_H
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..818433e
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/CliParser.cpp b/CliParser.cpp
new file mode 100644
index 0000000..ffd511d
--- /dev/null
+++ b/CliParser.cpp
@@ -0,0 +1,73 @@
+/** \file CliParser.cpp
+\brief To group into one class, the CLI parsing
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "CliParser.h"
+
+CliParser::CliParser(QObject *parent) :
+ QObject(parent)
+{
+}
+
+void CliParser::cli(const QStringList &ultracopierArguments,const bool &external)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"ultracopierArguments: "+ultracopierArguments.join(";"));
+ if(ultracopierArguments.size()==1)
+ {
+ if(external)
+ QMessageBox::warning(NULL,tr("Warning"),tr("Ultracopier is already running, right click on its system tray icon (near the clock) to use it"));
+ // else do nothing, is normal starting without arguements
+ return;
+ }
+ if(ultracopierArguments.size()==2 && ultracopierArguments.last()=="quit" && external)
+ {
+ QCoreApplication::exit();
+ return;
+ }
+ if(ultracopierArguments.size()>3)
+ {
+ if(ultracopierArguments[1]=="Copy" || ultracopierArguments[1]=="cp")
+ {
+ QStringList transferList=ultracopierArguments;
+ transferList.removeFirst();
+ transferList.removeFirst();
+ if(transferList.last()=="?")
+ {
+ transferList.removeLast();
+ emit newCopy(transferList);
+ }
+ else
+ {
+ QString destination=transferList.last();
+ transferList.removeLast();
+ emit newCopy(transferList,destination);
+ }
+ return;
+ }
+ if(ultracopierArguments[1]=="Move" || ultracopierArguments[1]=="mv")
+ {
+ QStringList transferList=ultracopierArguments;
+ transferList.removeFirst();
+ transferList.removeFirst();
+ if(transferList.last()=="?")
+ {
+ transferList.removeLast();
+ emit newMove(transferList);
+ }
+ else
+ {
+ QString destination=transferList.last();
+ transferList.removeLast();
+ emit newMove(transferList,destination);
+ }
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Command line not understand");
+ QMessageBox::warning(NULL,tr("Warning"),tr("Command line not understand"));
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Command line not understand");
+ QMessageBox::warning(NULL,tr("Warning"),tr("Command line not understand"));
+}
diff --git a/CliParser.h b/CliParser.h
new file mode 100644
index 0000000..92276c0
--- /dev/null
+++ b/CliParser.h
@@ -0,0 +1,40 @@
+/** \file CliParser.h
+\brief To group into one class, the CLI parsing
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef CLIPARSER_H
+#define CLIPARSER_H
+
+#include <QObject>
+#include <QMessageBox>
+#include <QCoreApplication>
+
+#include "Environment.h"
+
+/** \brief class to parse all command line options */
+class CliParser : public QObject
+{
+ Q_OBJECT
+public:
+ explicit CliParser(QObject *parent = 0);
+public slots:
+ /** \brief method to parse the ultracopier arguments
+ \param ultracopierArguments the argument list
+ \param external true if the arguments come from other instance of ultracopier
+ */
+ void cli(const QStringList &ultracopierArguments,const bool &external);
+signals:
+ /** new copy without destination have been pased by the CLI */
+ void newCopy(QStringList sources);
+ /** new copy with destination have been pased by the CLI */
+ void newCopy(QStringList sources,QString destination);
+ /** new move without destination have been pased by the CLI */
+ void newMove(QStringList sources);
+ /** new move with destination have been pased by the CLI */
+ void newMove(QStringList sources,QString destination);
+};
+
+#endif // CLIPARSER_H
diff --git a/CompilerInfo.h b/CompilerInfo.h
new file mode 100644
index 0000000..5209988
--- /dev/null
+++ b/CompilerInfo.h
@@ -0,0 +1,17 @@
+/** \file CompilerInfo.h
+\brief Define the compiler info
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+/// \def COMPILERINFO the string to identify the compiler
+#if defined(Q_CC_GNU)
+ #define COMPILERINFO QString("GCC build: ")+__DATE__+" "+__TIME__
+#else
+ #if defined(__DATE__) && defined(__TIME__)
+ #define COMPILERINFO QString("Unknow compiler: ")+__DATE__+" "+__TIME__
+ #else
+ #define COMPILERINFO QString("Unknow compiler")
+ #endif
+#endif
diff --git a/CopyEngineManager.cpp b/CopyEngineManager.cpp
new file mode 100644
index 0000000..758d9b2
--- /dev/null
+++ b/CopyEngineManager.cpp
@@ -0,0 +1,342 @@
+/** \file CopyEngineManager.cpp
+\brief Define the copy engine manager
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDebug>
+#include <QMessageBox>
+
+#include "CopyEngineManager.h"
+
+CopyEngineManager::CopyEngineManager(OptionDialog *optionDialog)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ this->optionDialog=optionDialog;
+ //setup the ui layout
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_CopyEngine);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this,SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this,SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins,SIGNAL(pluginListingIsfinish()), this,SLOT(allPluginIsloaded()));
+ plugins->unlockPluginListEdition();
+ //load the options
+ isConnected=false;
+ connect(languages, SIGNAL(newLanguageLoaded(QString)), &facilityEngine,SLOT(retranslate()));
+}
+
+void CopyEngineManager::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_CopyEngine)
+ return;
+ //setFileName
+ QString pluginPath=plugin.path+PluginsManager::getResolvedPluginName("copyEngine");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+pluginPath);
+ //search into loaded session
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).pluginPath==pluginPath)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("Engine already found!"));
+ return;
+ }
+ index++;
+ }
+ CopyEnginePlugin newItem;
+ newItem.pluginPath=pluginPath;
+ newItem.path=plugin.path;
+ newItem.name=plugin.name;
+ newItem.pointer=new QPluginLoader(newItem.pluginPath);
+ QObject *pluginObject = newItem.pointer->instance();
+ if(pluginObject==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to load the plugin: %1").arg(newItem.pointer->errorString()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to load the plugin for %1").arg(newItem.pluginPath));
+ newItem.pointer->unload();
+ return;
+ }
+ newItem.factory = qobject_cast<PluginInterface_CopyEngineFactory *>(pluginObject);
+ //check if found
+ index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).factory==newItem.factory)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Plugin already found"));
+ newItem.pointer->unload();
+ return;
+ }
+ index++;
+ }
+ if(newItem.factory==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to cast the plugin: %1").arg(newItem.pointer->errorString()));
+ newItem.pointer->unload();
+ return;
+ }
+ #ifdef ULTRACOPIER_DEBUG
+ qRegisterMetaType<DebugLevel>("DebugLevel");
+ connect(newItem.factory,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SLOT(debugInformation(DebugLevel,QString,QString,QString,int)),Qt::QueuedConnection);
+ #endif // ULTRACOPIER_DEBUG
+ newItem.options=new LocalPluginOptions("CopyEngine-"+newItem.name);
+ newItem.factory->setResources(newItem.options,plugin.writablePath,plugin.path,&facilityEngine,ULTRACOPIER_VERSION_PORTABLE_BOOL);
+ newItem.optionsWidget=newItem.factory->options();
+ newItem.supportedProtocolsForTheSource=newItem.factory->supportedProtocolsForTheSource();
+ newItem.supportedProtocolsForTheDestination=newItem.factory->supportedProtocolsForTheDestination();
+ newItem.canDoOnlyCopy=newItem.factory->canDoOnlyCopy();
+ newItem.type=newItem.factory->getCopyType();
+ newItem.transferListOperation=newItem.factory->getTransferListOperation();
+ optionDialog->addCopyEngineWidget(newItem.name,newItem.optionsWidget);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"plugin: "+newItem.name+" loaded, send options");
+ //emit newCopyEngineOptions(plugin.path,newItem.name,newItem.optionsWidget);
+ pluginList << newItem;
+ connect(languages,SIGNAL(newLanguageLoaded(QString)),newItem.factory,SLOT(newLanguageLoaded()));
+ if(plugins->allPluginHaveBeenLoaded())
+ allPluginIsloaded();
+ if(isConnected)
+ emit addCopyEngine(newItem.name,newItem.canDoOnlyCopy);
+}
+
+void CopyEngineManager::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).path==plugin.path)
+ {
+ if(pluginList.at(index).intances.size()<=0)
+ {
+ emit removeCopyEngine(pluginList.at(index).name);
+ pluginList.removeAt(index);
+ allPluginIsloaded();
+ return;
+ }
+ }
+ index++;
+ }
+}
+
+void CopyEngineManager::onePluginWillBeUnloaded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_CopyEngine)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).path==plugin.path)
+ {
+ optionDialog->removeCopyEngineWidget(pluginList.at(index).name);
+ delete pluginList.at(index).options;
+ delete pluginList.at(index).factory;
+ pluginList.at(index).pointer->unload();
+ return;
+ }
+ index++;
+ }
+}
+
+CopyEngineManager::returnCopyEngine CopyEngineManager::getCopyEngine(const CopyMode &mode,const QStringList &protocolsUsedForTheSources,const QString &protocolsUsedForTheDestination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, pluginList.size(): %1, mode: %2, and particular protocol").arg(pluginList.size()).arg((int)mode));
+ returnCopyEngine temp;
+ int index=0;
+ bool isTheGoodEngine=false;
+ while(index<pluginList.size())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("pluginList.at(%1).name: %2").arg(index).arg(pluginList.at(index).name));
+ isTheGoodEngine=false;
+ if(mode!=Move || !pluginList.at(index).canDoOnlyCopy)
+ {
+ if(protocolsUsedForTheSources.size()==0)
+ isTheGoodEngine=true;
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("pluginList.at(index).supportedProtocolsForTheDestination: %1").arg(pluginList.at(index).supportedProtocolsForTheDestination.join(";")));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("protocolsUsedForTheDestination: %1").arg(protocolsUsedForTheDestination));
+ if(pluginList.at(index).supportedProtocolsForTheDestination.contains(protocolsUsedForTheDestination))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("pluginList.at(index).supportedProtocolsForTheSource: %1").arg(pluginList.at(index).supportedProtocolsForTheSource.join(";")));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("protocolsUsedForTheSources.at(indexProto): %1").arg(protocolsUsedForTheSources.join(";")));
+ isTheGoodEngine=true;
+ int indexProto=0;
+ while(indexProto<protocolsUsedForTheSources.size())
+ {
+ if(!pluginList.at(index).supportedProtocolsForTheSource.contains(protocolsUsedForTheSources.at(indexProto)))
+ {
+ isTheGoodEngine=false;
+ break;
+ }
+ indexProto++;
+ }
+ }
+ }
+ }
+ if(isTheGoodEngine)
+ {
+ pluginList[index].intances<<pluginList[index].factory->getInstance();
+ temp.engine=pluginList[index].intances.last();
+ temp.canDoOnlyCopy=pluginList.at(index).canDoOnlyCopy;
+ temp.type=pluginList.at(index).type;
+ temp.transferListOperation=pluginList.at(index).transferListOperation;
+ return temp;
+ }
+ index++;
+ }
+ if(mode==Move)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Cannot find any copy engine with motions support");
+ QMessageBox::critical(NULL,tr("Warning"),tr("Cannot find any copy engine with motions support"));
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Cannot find any compatible engine!");
+ QMessageBox::critical(NULL,tr("Warning"),tr("Cannot find any compatible engine!"));
+ }
+ temp.engine=NULL;
+ temp.type=File;
+ temp.canDoOnlyCopy=true;
+ return temp;
+}
+
+CopyEngineManager::returnCopyEngine CopyEngineManager::getCopyEngine(const CopyMode &mode,const QString &name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, pluginList.size(): %1, with mode: %2, and name: %3").arg(pluginList.size()).arg((int)mode).arg(name));
+ returnCopyEngine temp;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).name==name)
+ {
+ if(mode==Move && pluginList.at(index).canDoOnlyCopy)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"This copy engine does not support motions: pluginList.at(index).canDoOnlyCopy: "+QString::number(pluginList.at(index).canDoOnlyCopy));
+ QMessageBox::critical(NULL,tr("Warning"),tr("This copy engine does not support motions"));
+ temp.engine=NULL;
+ return temp;
+ }
+ pluginList[index].intances<<pluginList[index].factory->getInstance();
+ temp.engine=pluginList[index].intances.last();
+ temp.canDoOnlyCopy=pluginList.at(index).canDoOnlyCopy;
+ temp.type=pluginList.at(index).type;
+ temp.transferListOperation=pluginList.at(index).transferListOperation;
+ return temp;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Cannot find any engine with this name");
+ QMessageBox::critical(NULL,tr("Warning"),tr("Cannot find any engine with this name"));
+ temp.engine=NULL;
+ temp.type=File;
+ temp.canDoOnlyCopy=true;
+ return temp;
+}
+
+#ifdef ULTRACOPIER_DEBUG
+void CopyEngineManager::debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne)
+{
+ DebugEngine::addDebugInformationStatic(level,fonction,text,file,ligne,"Copy Engine plugin");
+}
+#endif // ULTRACOPIER_DEBUG
+
+/// \brief To notify when new value into a group have changed
+void CopyEngineManager::newOptionValue(const QString &groupName,const QString &variableName,const QVariant &value)
+{
+ if(groupName=="CopyEngine" && variableName=="List")
+ {
+ Q_UNUSED(value)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"start(\""+groupName+"\",\""+variableName+"\",\""+value.toString()+"\")");
+ allPluginIsloaded();
+ }
+}
+
+void CopyEngineManager::setIsConnected()
+{
+ /* ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ prevent bug, I don't know why, in one case it bug here
+ */
+ isConnected=true;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ emit addCopyEngine(pluginList.at(index).name,pluginList.at(index).canDoOnlyCopy);
+ index++;
+ }
+}
+
+void CopyEngineManager::allPluginIsloaded()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QStringList actualList;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ actualList << pluginList.at(index).name;
+ index++;
+ }
+ QStringList preferedList=options->getOptionValue("CopyEngine","List").toStringList();
+ preferedList.removeDuplicates();
+ actualList.removeDuplicates();
+ index=0;
+ while(index<preferedList.size())
+ {
+ if(!actualList.contains(preferedList.at(index)))
+ {
+ preferedList.removeAt(index);
+ index--;
+ }
+ index++;
+ }
+ index=0;
+ while(index<actualList.size())
+ {
+ if(!preferedList.contains(actualList.at(index)))
+ preferedList << actualList.at(index);
+ index++;
+ }
+ options->setOptionValue("CopyEngine","List",preferedList);
+ QList<CopyEnginePlugin> newPluginList;
+ index=0;
+ while(index<preferedList.size())
+ {
+ int pluginListIndex=0;
+ while(pluginListIndex<pluginList.size())
+ {
+ if(preferedList.at(index)==pluginList.at(pluginListIndex).name)
+ {
+ newPluginList << pluginList.at(pluginListIndex);
+ break;
+ }
+ pluginListIndex++;
+ }
+ index++;
+ }
+ pluginList=newPluginList;
+}
+
+bool CopyEngineManager::protocolsSupportedByTheCopyEngine(PluginInterface_CopyEngine * engine,const QStringList &protocolsUsedForTheSources,const QString &protocolsUsedForTheDestination)
+{
+ int index=0;
+ while(index<pluginList.size())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("pluginList.at(%1).name: %2").arg(index).arg(pluginList.at(index).name));
+ if(pluginList.at(index).intances.contains(engine))
+ {
+ if(!pluginList.at(index).supportedProtocolsForTheDestination.contains(protocolsUsedForTheDestination))
+ return false;
+ int indexProto=0;
+ while(indexProto<protocolsUsedForTheSources.size())
+ {
+ if(!pluginList.at(index).supportedProtocolsForTheSource.contains(protocolsUsedForTheSources.at(indexProto)))
+ return false;
+ indexProto++;
+ }
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/CopyEngineManager.h b/CopyEngineManager.h
new file mode 100644
index 0000000..afec5e5
--- /dev/null
+++ b/CopyEngineManager.h
@@ -0,0 +1,102 @@
+/** \file CopyEngineManager.h
+\brief Define the copy engine manager
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef COPYENGINEMANAGER_H
+#define COPYENGINEMANAGER_H
+
+#include <QObject>
+#include <QPluginLoader>
+#include <QList>
+#include <QWidget>
+#include <QString>
+
+#include "Environment.h"
+#include "GlobalClass.h"
+#include "LocalPluginOptions.h"
+#include "OptionDialog.h"
+#include "interface/PluginInterface_CopyEngine.h"
+#include "FacilityEngine.h"
+
+namespace Ui {
+ class CopyEngineOptions;
+}
+
+/** \brief Manage copy engine plugins and their instance */
+class CopyEngineManager : public QObject, public GlobalClass
+{
+ Q_OBJECT
+public:
+ /** \brief internal structure to return one copy engine instance */
+ struct returnCopyEngine
+ {
+ PluginInterface_CopyEngine * engine; ///< The copy engine instance
+ bool canDoOnlyCopy; ///< true if can do only the copy (not move)
+ CopyType type; ///< Kind of copy what it can do
+ TransferListOperation transferListOperation;
+ };
+ explicit CopyEngineManager(OptionDialog *optionDialog);
+ /** \brief return copy engine instance when know the sources and destinations
+ \param mode the mode (copy/move)
+ \param protocolsUsedForTheSources list of sources used
+ \param protocolsUsedForTheDestination list of destination used
+ \see getCopyEngine()
+ */
+ returnCopyEngine getCopyEngine(const CopyMode &mode,const QStringList &protocolsUsedForTheSources,const QString &protocolsUsedForTheDestination);
+ /** \brief return copy engine instance with specific engine
+ \param mode the mode (copy/move)
+ \param name name of the engine needed
+ \see getCopyEngine()
+ */
+ returnCopyEngine getCopyEngine(const CopyMode &mode,const QString &name);
+ //bool currentEngineCanDoOnlyCopy(QStringList protocolsUsedForTheSources,QString protocolsUsedForTheDestination="");
+ //CopyType currentEngineGetCopyType(QStringList protocolsUsedForTheSources,QString protocolsUsedForTheDestination="");
+ /** \brief to send all signal because all object is connected on it */
+ void setIsConnected();
+ /** \brief check if the protocols given is supported by the copy engine
+ \see Core::newCopy()
+ \see Core::newMove()
+ */
+ bool protocolsSupportedByTheCopyEngine(PluginInterface_CopyEngine * engine,const QStringList &protocolsUsedForTheSources,const QString &protocolsUsedForTheDestination);
+private slots:
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ void onePluginWillBeUnloaded(const PluginsAvailable &plugin);
+ #ifdef ULTRACOPIER_DEBUG
+ void debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne);
+ #endif // ULTRACOPIER_DEBUG
+ /// \brief To notify when new value into a group have changed
+ void newOptionValue(const QString &groupName,const QString &variableName,const QVariant &value);
+ void allPluginIsloaded();
+private:
+ /// \brief the option interface
+ struct CopyEnginePlugin
+ {
+ QString path;
+ QString name;
+ QString pluginPath;
+ QStringList supportedProtocolsForTheSource;
+ QStringList supportedProtocolsForTheDestination;
+ QPluginLoader * pointer;
+ PluginInterface_CopyEngineFactory * factory;
+ QList<PluginInterface_CopyEngine *> intances;
+ bool canDoOnlyCopy;
+ CopyType type;
+ TransferListOperation transferListOperation;
+ LocalPluginOptions *options;
+ QWidget *optionsWidget;
+ };
+ QList<CopyEnginePlugin> pluginList;
+ OptionDialog *optionDialog;
+ bool isConnected;
+ FacilityEngine facilityEngine;
+signals:
+ //void newCopyEngineOptions(QString,QString,QWidget *);
+ void addCopyEngine(QString name,bool canDoOnlyCopy);
+ void removeCopyEngine(QString name);
+};
+
+#endif // COPYENGINEMANAGER_H
diff --git a/CopyListener.cpp b/CopyListener.cpp
new file mode 100755
index 0000000..4387156
--- /dev/null
+++ b/CopyListener.cpp
@@ -0,0 +1,413 @@
+/** \file CopyListener.h
+\brief Define the copy listener
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "CopyListener.h"
+
+
+CopyListener::CopyListener(QObject *parent) :
+ QObject(parent)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the options
+ tryListen=false;
+ QList<QPair<QString, QVariant> > KeysList;
+ KeysList.append(qMakePair(QString("CatchCopyAsDefault"),QVariant(true)));
+ options->addOptionGroup("CopyListener",KeysList);
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_Listener);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ qRegisterMetaType<PluginsAvailable>("PluginsAvailable");
+ qRegisterMetaType<ListeningState>("ListeningState");
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this,SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this,SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins,SIGNAL(pluginListingIsfinish()), this,SLOT(allPluginIsloaded()));
+ connect(&pluginLoader,SIGNAL(pluginLoaderReady(CatchState,bool,bool)), this,SIGNAL(pluginLoaderReady(CatchState,bool,bool)));
+ plugins->unlockPluginListEdition();
+ last_state=NotListening;
+ last_have_plugin=false;
+ last_inWaitOfReply=false;
+}
+
+CopyListener::~CopyListener()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_Listener);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginWillBeRemoved(currentPlugin);
+}
+
+void CopyListener::resendState()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ sendState(true);
+ pluginLoader.resendState();
+ }
+}
+
+void CopyListener::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_Listener)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"try load: "+plugin.path+PluginsManager::getResolvedPluginName("listener"));
+ //setFileName
+ QPluginLoader *pluginLoader=new QPluginLoader(plugin.path+PluginsManager::getResolvedPluginName("listener"));
+ QObject *pluginInstance = pluginLoader->instance();
+ if(pluginInstance)
+ {
+ PluginInterface_Listener *listen = qobject_cast<PluginInterface_Listener *>(pluginInstance);
+ //check if found
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).listenInterface==listen)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Plugin already found"));
+ pluginLoader->unload();
+ return;
+ }
+ index++;
+ }
+ if(listen)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Plugin correctly loaded");
+ #ifdef ULTRACOPIER_DEBUG
+ connect(listen,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SLOT(debugInformation(DebugLevel,QString,QString,QString,int)));
+ #endif // ULTRACOPIER_DEBUG
+ connect(listen,SIGNAL(newCopy(quint32,QStringList)), this,SLOT(newPluginCopy(quint32,QStringList)));
+ connect(listen,SIGNAL(newCopy(quint32,QStringList,QString)), this,SLOT(newPluginCopy(quint32,QStringList,QString)));
+ connect(listen,SIGNAL(newMove(quint32,QStringList)), this,SLOT(newPluginMove(quint32,QStringList)));
+ connect(listen,SIGNAL(newMove(quint32,QStringList,QString)), this,SLOT(newPluginMove(quint32,QStringList,QString)));
+ PluginListener newPluginListener;
+ newPluginListener.listenInterface = listen;
+ newPluginListener.pluginLoader = pluginLoader;
+ newPluginListener.path = plugin.path+PluginsManager::getResolvedPluginName("listener");
+ newPluginListener.state = NotListening;
+ newPluginListener.inWaitOfReply = false;
+ newPluginListener.options=new LocalPluginOptions("Listener-"+plugin.name);
+ newPluginListener.listenInterface->setResources(newPluginListener.options,plugin.writablePath,plugin.path,ULTRACOPIER_VERSION_PORTABLE_BOOL);
+ pluginList << newPluginListener;
+ connect(pluginList.last().listenInterface,SIGNAL(newState(ListeningState)),this,SLOT(newState(ListeningState)));
+ if(tryListen)
+ {
+ pluginList.last().inWaitOfReply=true;
+ listen->listen();
+ }
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to cast the plugin: "+pluginLoader->errorString());
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to load the plugin: "+pluginLoader->errorString());
+}
+
+#ifdef ULTRACOPIER_DEBUG
+void CopyListener::debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne)
+{
+ DebugEngine::addDebugInformationStatic(level,fonction,text,file,ligne,"Listener plugin");
+}
+#endif // ULTRACOPIER_DEBUG
+
+bool CopyListener::oneListenerIsLoaded()
+{
+ return (pluginList.size()>0);
+}
+
+void CopyListener::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_Listener)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"unload the current plugin");
+ int indexPlugin=0;
+ while(indexPlugin<pluginList.size())
+ {
+ if((plugin.path+PluginsManager::getResolvedPluginName("listener"))==pluginList.at(indexPlugin).path)
+ {
+ int index=0;
+ while(index<copyRunningList.size())
+ {
+ if(copyRunningList.at(index).listenInterface==pluginList.at(indexPlugin).listenInterface)
+ copyRunningList[index].listenInterface=NULL;
+ index++;
+ }
+ pluginList.at(indexPlugin).listenInterface->close();
+ disconnect(pluginList.at(indexPlugin).listenInterface);
+ pluginList.at(indexPlugin).pluginLoader->unload();
+ delete pluginList.at(indexPlugin).options;
+ pluginList.removeAt(indexPlugin);
+ sendState();
+ return;
+ }
+ indexPlugin++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"not found");
+}
+
+void CopyListener::newState(const ListeningState &state)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ PluginInterface_Listener *temp=qobject_cast<PluginInterface_Listener *>(QObject::sender());
+ if(temp==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("listener not located!"));
+ return;
+ }
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(temp==pluginList.at(index).listenInterface)
+ {
+ pluginList[index].state=state;
+ pluginList[index].inWaitOfReply=false;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("new state for the plugin %1: %2").arg(index).arg(state));
+ sendState(true);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("listener not found!"));
+}
+
+void CopyListener::listen()
+{
+ tryListen=true;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginList.size())
+ {
+ pluginList[index].inWaitOfReply=true;
+ pluginList.at(index).listenInterface->listen();
+ index++;
+ }
+ pluginLoader.load();
+}
+
+void CopyListener::close()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ tryListen=false;
+ pluginLoader.unload();
+ int index=0;
+ while(index<pluginList.size())
+ {
+ pluginList[index].inWaitOfReply=true;
+ pluginList.at(index).listenInterface->close();
+ index++;
+ }
+ copyRunningList.clear();
+}
+
+QStringList CopyListener::parseWildcardSources(QStringList sources)
+{
+ QStringList returnList;
+ int index=0;
+ while(index<sources.size())
+ {
+ if(sources.at(index).contains("*"))
+ {
+ QFileInfo info(sources.at(index));
+ QDir folder(info.absoluteDir());
+ QFileInfoList fileFile=folder.entryInfoList(QStringList() << info.fileName());
+ int index=0;
+ while(index<fileFile.size())
+ {
+ returnList << fileFile.at(index).absoluteFilePath();
+ index++;
+ }
+ }
+ else
+ returnList << sources.at(index);
+ index++;
+ }
+ return returnList;
+}
+
+QStringList CopyListener::stripSeparator(QStringList sources)
+{
+ int index=0;
+ while(index<sources.size())
+ {
+ sources[index].remove(QRegExp("[\\\\/]+$"));
+ index++;
+ }
+ return sources;
+}
+
+/** new copy without destination have been pased by the CLI */
+void CopyListener::newCopy(QStringList sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ emit newCopy(incrementOrderId(),QStringList() << "file",stripSeparator(parseWildcardSources(sources)));
+}
+
+/** new copy with destination have been pased by the CLI */
+void CopyListener::newCopy(QStringList sources,QString destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ emit newCopy(incrementOrderId(),QStringList() << "file",stripSeparator(parseWildcardSources(sources)),"file",destination);
+}
+
+/** new move without destination have been pased by the CLI */
+void CopyListener::newMove(QStringList sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ emit newMove(incrementOrderId(),QStringList() << "file",stripSeparator(parseWildcardSources(sources)));
+}
+
+/** new move with destination have been pased by the CLI */
+void CopyListener::newMove(QStringList sources,QString destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ emit newMove(incrementOrderId(),QStringList() << "file",stripSeparator(parseWildcardSources(sources)),"file",destination);
+}
+
+void CopyListener::copyFinished(const quint32 & orderId,const bool &withError)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<copyRunningList.size())
+ {
+ if(orderId==copyRunningList.at(index).orderId)
+ {
+ orderList.removeAll(orderId);
+ if(copyRunningList.at(index).listenInterface!=NULL)
+ copyRunningList.at(index).listenInterface->transferFinished(copyRunningList.at(index).pluginOrderId,withError);
+ copyRunningList.removeAt(index);
+ return;
+ }
+ index++;
+ }
+}
+
+void CopyListener::copyCanceled(const quint32 & orderId)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<copyRunningList.size())
+ {
+ if(orderId==copyRunningList.at(index).orderId)
+ {
+ orderList.removeAll(orderId);
+ if(copyRunningList.at(index).listenInterface!=NULL)
+ copyRunningList.at(index).listenInterface->transferCanceled(copyRunningList.at(index).pluginOrderId);
+ copyRunningList.removeAt(index);
+ return;
+ }
+ index++;
+ }
+}
+
+void CopyListener::newPluginCopy(const quint32 &orderId,const QStringList &sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"sources: "+sources.join(";"));
+ PluginInterface_Listener *plugin = qobject_cast<PluginInterface_Listener *>(sender());
+ CopyRunning newCopyInformation;
+ newCopyInformation.listenInterface = plugin;
+ newCopyInformation.pluginOrderId = orderId;
+ newCopyInformation.orderId = incrementOrderId();
+ copyRunningList << newCopyInformation;
+ emit newCopy(orderId,QStringList() << "file",stripSeparator(sources));
+}
+
+void CopyListener::newPluginCopy(const quint32 &orderId,const QStringList &sources,const QString &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"sources: "+sources.join(";")+", destination: "+destination);
+ PluginInterface_Listener *plugin = qobject_cast<PluginInterface_Listener *>(sender());
+ CopyRunning newCopyInformation;
+ newCopyInformation.listenInterface = plugin;
+ newCopyInformation.pluginOrderId = orderId;
+ newCopyInformation.orderId = incrementOrderId();
+ copyRunningList << newCopyInformation;
+ emit newCopy(orderId,QStringList() << "file",stripSeparator(sources),"file",destination);
+}
+
+void CopyListener::newPluginMove(const quint32 &orderId,const QStringList &sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"sources: "+sources.join(";"));
+ PluginInterface_Listener *plugin = qobject_cast<PluginInterface_Listener *>(sender());
+ CopyRunning newCopyInformation;
+ newCopyInformation.listenInterface = plugin;
+ newCopyInformation.pluginOrderId = orderId;
+ newCopyInformation.orderId = incrementOrderId();
+ copyRunningList << newCopyInformation;
+ emit newMove(orderId,QStringList() << "file",stripSeparator(sources));
+}
+
+void CopyListener::newPluginMove(const quint32 &orderId,const QStringList &sources,const QString &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"sources: "+sources.join(";")+", destination: "+destination);
+ PluginInterface_Listener *plugin = qobject_cast<PluginInterface_Listener *>(sender());
+ CopyRunning newCopyInformation;
+ newCopyInformation.listenInterface = plugin;
+ newCopyInformation.pluginOrderId = orderId;
+ newCopyInformation.orderId = incrementOrderId();
+ copyRunningList << newCopyInformation;
+ emit newMove(orderId,QStringList() << "file",stripSeparator(sources),"file",destination);
+}
+
+quint32 CopyListener::incrementOrderId()
+{
+ do
+ {
+ nextOrderId++;
+ if(nextOrderId>2000000)
+ nextOrderId=0;
+ } while(orderList.contains(nextOrderId));
+ return nextOrderId;
+}
+
+void CopyListener::allPluginIsloaded()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"with value: "+QString::number(pluginList.size()>0));
+ sendState(true);
+}
+
+void CopyListener::sendState(bool force)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, pluginList.size(): %1, force: %2").arg(pluginList.size()).arg(force));
+ ListeningState current_state=NotListening;
+ bool found_not_listen=false,found_listen=false,found_inWaitOfReply=false;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(current_state==NotListening)
+ {
+ if(pluginList.at(index).state==SemiListening)
+ current_state=SemiListening;
+ else if(pluginList.at(index).state==NotListening)
+ found_not_listen=true;
+ else if(pluginList.at(index).state==FullListening)
+ found_listen=true;
+ }
+ if(pluginList.at(index).inWaitOfReply)
+ found_inWaitOfReply=true;
+ index++;
+ }
+ if(current_state==NotListening)
+ {
+ if(found_not_listen && found_listen)
+ current_state=SemiListening;
+ else if(found_not_listen)
+ current_state=NotListening;
+ else if(FullListening)
+ current_state=FullListening;
+ else
+ current_state=SemiListening;
+ }
+ bool have_plugin=pluginList.size()>0;
+ if(force || current_state!=last_state || have_plugin!=last_have_plugin || found_inWaitOfReply!=last_inWaitOfReply)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("send listenerReady(%1,%2,%3)").arg(current_state).arg(have_plugin).arg(found_inWaitOfReply));
+ emit listenerReady(current_state,have_plugin,found_inWaitOfReply);
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Skip the signal sending"));
+ last_state=NotListening;
+ last_have_plugin=have_plugin;
+ last_inWaitOfReply=found_inWaitOfReply;
+}
diff --git a/CopyListener.h b/CopyListener.h
new file mode 100755
index 0000000..c5cd84e
--- /dev/null
+++ b/CopyListener.h
@@ -0,0 +1,113 @@
+/** \file CopyListener.h
+\brief Define the class to load the plugin and lunch it
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef COPYLISTENER_H
+#define COPYLISTENER_H
+
+#include <QObject>
+#include <QList>
+#include <QPluginLoader>
+
+#include "interface/PluginInterface_Listener.h"
+#include "Environment.h"
+#include "GlobalClass.h"
+#include "PluginLoader.h"
+
+/** \brief to load all the listener and parse all event */
+class CopyListener : public QObject, public GlobalClass
+{
+ Q_OBJECT
+ public:
+ explicit CopyListener(QObject *parent = 0);
+ ~CopyListener();
+ /** \brief send of one listener is loaded */
+ bool oneListenerIsLoaded();
+ /** \brief to resend the state */
+ void resendState();
+ private slots:
+ //void newPlugin();
+ void newPluginCopy(const quint32 &orderId,const QStringList &sources);
+ void newPluginCopy(const quint32 &orderId,const QStringList &sources,const QString &destination);
+ void newPluginMove(const quint32 &orderId,const QStringList &sources);
+ void newPluginMove(const quint32 &orderId,const QStringList &sources,const QString &destination);
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ void newState(const ListeningState &state);
+ #ifdef ULTRACOPIER_DEBUG
+ void debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne);
+ #endif // ULTRACOPIER_DEBUG
+ void allPluginIsloaded();
+ public slots:
+ /** \brief the copy is finished
+ \param orderId id used when it have send the copy
+ \param withError true if it have found error
+ \see newCopy()
+ \see newMove()
+ */
+ void copyFinished(const quint32 & orderId,const bool &withError);
+ /** \brief the copy is canceled by the user
+ \param orderId id used when it have send the copy
+ \see newCopy()
+ \see newMove()
+ */
+ void copyCanceled(const quint32 & orderId);
+ /** \brief try listen, to get copy/move from external source (mainly the file manager)
+ \see close()
+ */
+ void listen();
+ /** \brief stop listen, to get copy/move from external source (mainly the file manager)
+ \see listen()
+ */
+ void close();
+ /** new copy without destination have been pased by the CLI */
+ void newCopy(QStringList sources);
+ /** new copy with destination have been pased by the CLI */
+ void newCopy(QStringList sources,QString destination);
+ /** new move without destination have been pased by the CLI */
+ void newMove(QStringList sources);
+ /** new move with destination have been pased by the CLI */
+ void newMove(QStringList sources,QString destination);
+ signals:
+ void newCopy(quint32 orderId,QStringList protocolsUsedForTheSources,QStringList sources);
+ void newCopy(quint32 orderId,QStringList protocolsUsedForTheSources,QStringList sources,QString protocolsUsedForTheDestination,QString destination);
+ void newMove(quint32 orderId,QStringList protocolsUsedForTheSources,QStringList sources);
+ void newMove(quint32 orderId,QStringList protocolsUsedForTheSources,QStringList sources,QString protocolsUsedForTheDestination,QString destination);
+ void listenerReady(ListeningState state,bool havePlugin,bool someAreInWaitOfReply);
+ void pluginLoaderReady(CatchState state,bool havePlugin,bool someAreInWaitOfReply);
+ private:
+ struct PluginListener
+ {
+ PluginInterface_Listener *listenInterface;
+ QPluginLoader *pluginLoader;
+ QString path;
+ ListeningState state;
+ bool inWaitOfReply;
+ LocalPluginOptions *options;
+ };
+ QList<PluginListener> pluginList;
+ //for the options
+ quint32 nextOrderId;
+ QList<quint32> orderList;
+ //for the copy as suspend
+ struct CopyRunning
+ {
+ PluginInterface_Listener *listenInterface;
+ quint32 pluginOrderId;
+ quint32 orderId;
+ };
+ QList<CopyRunning> copyRunningList;
+ quint32 incrementOrderId();
+ bool tryListen;
+ PluginLoader pluginLoader;
+ ListeningState last_state;
+ bool last_have_plugin,last_inWaitOfReply;
+ void sendState(bool force=false);
+ QStringList parseWildcardSources(QStringList sources);
+ QStringList stripSeparator(QStringList sources);
+};
+
+#endif // COPYLISTENER_H
diff --git a/Core.cpp b/Core.cpp
new file mode 100644
index 0000000..f27181b
--- /dev/null
+++ b/Core.cpp
@@ -0,0 +1,786 @@
+/** \file Core.cpp
+\brief Define the class for the core
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QMessageBox>
+#include <QtPlugin>
+
+#include "Core.h"
+
+Core::Core(CopyEngineManager *copyEngineList)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ this->copyEngineList=copyEngineList;
+ nextId=0;
+ forUpateInformation.setInterval(ULTRACOPIER_TIME_INTERFACE_UPDATE);
+ loadInterface();
+ //connect(&copyEngineList, SIGNAL(newCanDoOnlyCopy(bool)), this, SIGNAL(newCanDoOnlyCopy(bool)));
+ connect(themes, SIGNAL(theThemeNeedBeUnloaded()), this, SLOT(unloadInterface()));
+ connect(themes, SIGNAL(theThemeIsReloaded()), this, SLOT(loadInterface()));
+ connect(&forUpateInformation, SIGNAL(timeout()), this, SLOT(periodiqueSync()));
+}
+
+void Core::newCopy(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ openNewCopy(Copy,false,protocolsUsedForTheSources);
+ copyList.last().orderId<<orderId;
+ copyList.last().engine->newCopy(sources);
+ copyList.last().interface->haveExternalOrder();
+}
+
+void Core::newCopy(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources,const QString &protocolsUsedForTheDestination,const QString &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+sources.join(";")+", dest: "+destination);
+ //search to group the window
+ int GroupWindowWhen=options->getOptionValue("Ultracopier","GroupWindowWhen").toInt();
+ bool haveSameSource=false,haveSameDestination=false;
+ if(GroupWindowWhen!=0)
+ {
+ int index=0;
+ while(index<copyList.size())
+ {
+ if(!copyList.at(index).ignoreMode && copyList.at(index).mode==Copy)
+ {
+ if(GroupWindowWhen!=5)
+ {
+ if(GroupWindowWhen!=2)
+ haveSameSource=copyList.at(index).engine->haveSameSource(sources);
+ if(GroupWindowWhen!=1)
+ haveSameDestination=copyList.at(index).engine->haveSameDestination(destination);
+ }
+ if(
+ GroupWindowWhen==5 ||
+ (GroupWindowWhen==1 && haveSameSource) ||
+ (GroupWindowWhen==2 && haveSameDestination) ||
+ (GroupWindowWhen==3 && (haveSameSource && haveSameDestination)) ||
+ (GroupWindowWhen==4 && (haveSameSource || haveSameDestination))
+ )
+ {
+ /*protocols are same*/
+ if(copyEngineList->protocolsSupportedByTheCopyEngine(copyList.at(index).engine,protocolsUsedForTheSources,protocolsUsedForTheDestination))
+ {
+ copyList[index].orderId<<orderId;
+ copyList.at(index).engine->newCopy(sources,destination);
+ copyList.at(index).interface->haveExternalOrder();
+ return;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ //else open new windows
+ openNewCopy(Copy,false,protocolsUsedForTheSources,protocolsUsedForTheDestination);
+ copyList.last().orderId<<orderId;
+ copyList.last().engine->newCopy(sources,destination);
+ copyList.last().interface->haveExternalOrder();
+}
+
+void Core::newMove(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources)
+{
+ openNewCopy(Move,false,protocolsUsedForTheSources);
+ copyList.last().orderId<<orderId;
+ copyList.last().engine->newMove(sources);
+ copyList.last().interface->haveExternalOrder();
+}
+
+void Core::newMove(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources,const QString &protocolsUsedForTheDestination,const QString &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //search to group the window
+ int GroupWindowWhen=options->getOptionValue("Ultracopier","GroupWindowWhen").toInt();
+ bool haveSameSource=false,haveSameDestination=false;
+ if(GroupWindowWhen!=0)
+ {
+ int index=0;
+ while(index<copyList.size())
+ {
+ if(!copyList.at(index).ignoreMode && copyList.at(index).mode==Move)
+ {
+ if(GroupWindowWhen!=5)
+ {
+ if(GroupWindowWhen!=2)
+ haveSameSource=copyList.at(index).engine->haveSameSource(sources);
+ if(GroupWindowWhen!=1)
+ haveSameDestination=copyList.at(index).engine->haveSameDestination(destination);
+ }
+ if(
+ GroupWindowWhen==5 ||
+ (GroupWindowWhen==1 && haveSameSource) ||
+ (GroupWindowWhen==2 && haveSameDestination) ||
+ (GroupWindowWhen==3 && (haveSameSource && haveSameDestination)) ||
+ (GroupWindowWhen==4 && (haveSameSource || haveSameDestination))
+ )
+ {
+ /*protocols are same*/
+ if(copyEngineList->protocolsSupportedByTheCopyEngine(copyList.at(index).engine,protocolsUsedForTheSources,protocolsUsedForTheDestination))
+ {
+ copyList[index].orderId<<orderId;
+ copyList.at(index).engine->newCopy(sources,destination);
+ copyList.at(index).interface->haveExternalOrder();
+ return;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ //else open new windows
+ openNewCopy(Move,false,protocolsUsedForTheSources,protocolsUsedForTheDestination);
+ copyList.last().orderId<<orderId;
+ copyList.last().engine->newMove(sources,destination);
+ copyList.last().interface->haveExternalOrder();
+}
+
+/// \todo name to open the right copy engine
+void Core::addWindowCopyMove(const CopyMode &mode,const QString &name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+name);
+ openNewCopy(mode,false,name);
+ ActionOnManualOpen ActionOnManualOpen_value=(ActionOnManualOpen)options->getOptionValue("Ultracopier","ActionOnManualOpen").toInt();
+ if(ActionOnManualOpen_value!=ActionOnManualOpen_Nothing)
+ {
+ if(ActionOnManualOpen_value==ActionOnManualOpen_Folder)
+ copyList.last().engine->userAddFolder(mode);
+ else
+ copyList.last().engine->userAddFile(mode);
+ }
+}
+
+/// \todo name to open the right copy engine
+void Core::addWindowTransfer(const QString &name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start"+name);
+ openNewCopy(Copy,true,name);
+}
+
+void Core::loadInterface()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the extra files to check the themes availability
+ if(copyList.size()>0)
+ {
+ bool error=false;
+ index=0;
+ loop_size=copyList.size();
+ while(index<loop_size)
+ {
+ copyList[index].interface=themes->getThemesInstance();
+ if(copyList[index].interface==NULL)
+ {
+ copyInstanceCanceledByIndex(index);
+ index--;
+ error=true;
+ }
+ else
+ {
+ if(!copyList.at(index).ignoreMode)
+ copyList.at(index).interface->forceCopyMode(copyList.at(index).mode);
+ connectInterfaceAndSync(copyList.count()-1);
+ copyList.at(index).engine->syncTransferList();
+ }
+ index++;
+ }
+ if(error)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to load the interface, copy aborted");
+ QMessageBox::critical(NULL,tr("Error"),tr("Unable to load the interface, copy aborted"));
+ }
+ }
+}
+
+void Core::unloadInterface()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ index=0;
+ loop_size=copyList.size();
+ while(index<loop_size)
+ {
+ if(copyList.at(index).interface!=NULL)
+ {
+ disconnectInterface(index);
+ delete copyList.at(index).interface;
+ copyList[index].interface=NULL;
+ copyList[index].copyEngineIsSync=false;
+ }
+ index++;
+ }
+}
+
+int Core::incrementId()
+{
+ do
+ {
+ nextId++;
+ if(nextId>2000000)
+ nextId=0;
+ } while(idList.contains(nextId));
+ return nextId;
+}
+
+int Core::openNewCopy(const CopyMode &mode,const bool &ignoreMode,const QStringList &protocolsUsedForTheSources,const QString &protocolsUsedForTheDestination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ CopyEngineManager::returnCopyEngine returnInformations=copyEngineList->getCopyEngine(mode,protocolsUsedForTheSources,protocolsUsedForTheDestination);
+ return connectCopyEngine(mode,ignoreMode,returnInformations);
+}
+
+int Core::openNewCopy(const CopyMode &mode,const bool &ignoreMode,const QString &name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start, mode: "+QString::number(mode)+", name: "+name);
+ CopyEngineManager::returnCopyEngine returnInformations=copyEngineList->getCopyEngine(mode,name);
+ return connectCopyEngine(mode,ignoreMode,returnInformations);
+}
+
+int Core::connectCopyEngine(const CopyMode &mode,bool ignoreMode,const CopyEngineManager::returnCopyEngine &returnInformations)
+{
+ if(returnInformations.canDoOnlyCopy)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Mode force for unknow reason");
+ ignoreMode=false;//force mode if need, normaly not used
+ }
+ CopyInstance newItem;
+ newItem.engine=returnInformations.engine;
+ if(newItem.engine!=NULL)
+ {
+ PluginInterface_Themes *theme=themes->getThemesInstance();
+ if(theme!=NULL)
+ {
+ newItem.id=incrementId();
+ newItem.lastProgression=0;
+ newItem.interface=theme;
+ newItem.ignoreMode=ignoreMode;
+ newItem.mode=mode;
+ newItem.type=returnInformations.type;
+ newItem.transferListOperation=returnInformations.transferListOperation;
+ newItem.baseTime=0;
+ newItem.numberOfFile=0;
+ newItem.numberOfTransferedFile=0;
+ newItem.sizeToCopy=0;
+ newItem.action=Idle;
+ newItem.lastProgression=0;//store the real byte transfered, used in time remaining calculation
+ newItem.isPaused=false;
+ newItem.baseTime=0;//stored in ms
+ newItem.isRunning=false;
+ newItem.haveError=false;
+ newItem.lastConditionalSync.start();
+ newItem.nextConditionalSync=new QTimer();
+ newItem.nextConditionalSync->setSingleShot(true);
+ newItem.copyEngineIsSync=true;
+
+ if(!ignoreMode)
+ newItem.interface->forceCopyMode(mode);
+ if(copyList.size()==0)
+ forUpateInformation.start();
+ copyList << newItem;
+ connectEngine(copyList.count()-1);
+ connectInterfaceAndSync(copyList.count()-1);
+ return newItem.id;
+ }
+ delete newItem.engine;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to load the interface, copy aborted");
+ QMessageBox::critical(NULL,tr("Error"),tr("Unable to load the interface, copy aborted"));
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to load the copy engine, copy aborted");
+ QMessageBox::critical(NULL,tr("Error"),tr("Unable to load the copy engine, copy aborted"));
+ }
+ return -1;
+}
+
+void Core::resetSpeedDetectedEngine()
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ resetSpeedDetected(index);
+}
+
+void Core::resetSpeedDetectedInterface()
+{
+ int index=indexCopySenderInterface();
+ if(index!=-1)
+ resetSpeedDetected(index);
+}
+
+void Core::resetSpeedDetected(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start on %1").arg(index));
+ copyList[index].runningTime.restart();
+ copyList[index].lastSpeedDetected.clear();
+ copyList[index].lastSpeedTime.clear();
+}
+
+void Core::actionInProgess(const EngineActionInProgress &action)
+{
+ index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("action: %1, from %2").arg(action).arg(index));
+ //drop here the duplicate action
+ if(copyList[index].action==action)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("The copy engine have send 2x the same EngineActionInProgress"));
+ return;
+ }
+ //update time runing for time remaning caculation
+ if(action==Copying || action==CopyingAndListing)
+ {
+ if(!copyList.at(index).isRunning)
+ {
+ copyList[index].isRunning=true;
+ copyList[index].runningTime.restart();
+ }
+ }
+ else
+ {
+ if(copyList.at(index).isRunning)
+ {
+ copyList[index].isRunning=false;
+ copyList[index].baseTime+=copyList[index].runningTime.elapsed();
+ }
+ }
+ //do sync
+ periodiqueSync(index);
+ copyList[index].action=action;
+ if(copyList.at(index).interface!=NULL)
+ copyList.at(index).interface->actionInProgess(action);
+ if(action==Idle)
+ {
+ index_sub_loop=0;
+ loop_size=copyList.at(index).orderId.size();
+ while(index_sub_loop<loop_size)
+ {
+ emit copyCanceled(copyList.at(index).orderId.at(index_sub_loop));
+ index_sub_loop++;
+ }
+ copyList[index].orderId.clear();
+ resetSpeedDetected(index);
+ }
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the interface sender");
+}
+
+void Core::newFolderListing(const QString &path)
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ copyList[index].folderListing=path;
+ copyList.at(index).interface->newFolderListing(path);
+ }
+}
+
+void Core::newCollisionAction(const QString &action)
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ copyList[index].collisionAction=action;
+ copyList.at(index).interface->newCollisionAction(action);
+ }
+}
+
+void Core::newErrorAction(const QString &action)
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ copyList[index].errorAction=action;
+ copyList.at(index).interface->newErrorAction(action);
+ }
+}
+
+void Core::isInPause(const bool &isPaused)
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ if(!isPaused)
+ resetSpeedDetected(index);
+ copyList[index].isPaused=isPaused;
+ copyList.at(index).interface->isInPause(isPaused);
+ }
+}
+
+int Core::indexCopySenderCopyEngine()
+{
+ QObject * senderObject=sender();
+ if(senderObject==NULL)
+ {
+ //QMessageBox::critical(NULL,tr("Internal error"),tr("A communication error occured between the interface and the copy plugin. Please report this bug."));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Qt sender() NULL");
+ return -1;
+ }
+ index=0;
+ loop_size=copyList.size();
+ while(index<loop_size)
+ {
+ if(copyList.at(index).engine==senderObject)
+ return index;
+ index++;
+ }
+ //QMessageBox::critical(NULL,tr("Internal error"),tr("A communication error occured between the interface and the copy plugin. Please report this bug."));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Sender not located in the list");
+ return -1;
+}
+
+int Core::indexCopySenderInterface()
+{
+ QObject * senderObject=sender();
+ if(senderObject==NULL)
+ {
+ //QMessageBox::critical(NULL,tr("Internal error"),tr("A communication error occured between the interface and the copy plugin. Please report this bug."));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Qt sender() NULL");
+ return -1;
+ }
+ index=0;
+ loop_size=copyList.size();
+ while(index<loop_size)
+ {
+ if(copyList.at(index).interface==senderObject)
+ return index;
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to locate QObject * sender");
+ PluginInterface_Themes * interface = qobject_cast<PluginInterface_Themes *>(senderObject);
+ if(interface==NULL)
+ {
+ //QMessageBox::critical(NULL,tr("Internal error"),tr("A communication error occured between the interface and the copy plugin. Please report this bug."));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Qt sender themes NULL");
+ return -1;
+ }
+ index=0;
+ while(index<loop_size)
+ {
+ if(copyList.at(index).interface==interface)
+ return index;
+ index++;
+ }
+ //QMessageBox::critical(NULL,tr("Internal error"),tr("A communication error occured between the interface and the copy plugin. Please report this bug."));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Sender not located in the list");
+ return -1;
+}
+
+void Core::connectEngine(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start with index: %1: %2").arg(index).arg((quint64)sender()));
+ disconnectEngine(index);
+
+ CopyInstance& currentCopyInstance=copyList[index];
+ connect(currentCopyInstance.engine,SIGNAL(newFolderListing(QString)), this,SLOT(newFolderListing(QString)),Qt::QueuedConnection);//to check to change
+ connect(currentCopyInstance.engine,SIGNAL(newCollisionAction(QString)), this,SLOT(newCollisionAction(QString)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(newErrorAction(QString)), this,SLOT(newErrorAction(QString)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(actionInProgess(EngineActionInProgress)), this,SLOT(actionInProgess(EngineActionInProgress)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(isInPause(bool)), this,SLOT(isInPause(bool)),Qt::QueuedConnection);//to check to change
+ connect(currentCopyInstance.engine,SIGNAL(cancelAll()), this,SLOT(copyInstanceCanceledByEngine()),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(error(QString,quint64,QDateTime,QString)), this,SLOT(error(QString,quint64,QDateTime,QString)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(rmPath(QString)), this,SLOT(rmPath(QString)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(mkPath(QString)), this,SLOT(mkPath(QString)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(syncReady()), this,SLOT(syncReady()),Qt::QueuedConnection);
+}
+
+void Core::connectInterfaceAndSync(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start with index: %1: %2").arg(index).arg((quint64)sender()));
+ disconnectInterface(index);
+
+ CopyInstance& currentCopyInstance=copyList[index];
+ connect(currentCopyInstance.interface,SIGNAL(pause()), currentCopyInstance.engine,SLOT(pause()));
+ connect(currentCopyInstance.interface,SIGNAL(resume()), currentCopyInstance.engine,SLOT(resume()));
+ connect(currentCopyInstance.interface,SIGNAL(skip(quint64)), currentCopyInstance.engine,SLOT(skip(quint64)));
+ connect(currentCopyInstance.interface,SIGNAL(sendErrorAction(QString)), currentCopyInstance.engine,SLOT(setErrorAction(QString)));
+ connect(currentCopyInstance.interface,SIGNAL(newSpeedLimitation(qint64)), currentCopyInstance.engine,SLOT(setSpeedLimitation(qint64)));
+ connect(currentCopyInstance.interface,SIGNAL(sendCollisionAction(QString)), currentCopyInstance.engine,SLOT(setCollisionAction(QString)));
+ connect(currentCopyInstance.interface,SIGNAL(userAddFolder(CopyMode)), currentCopyInstance.engine,SLOT(userAddFolder(CopyMode)));
+ connect(currentCopyInstance.interface,SIGNAL(userAddFile(CopyMode)), currentCopyInstance.engine,SLOT(userAddFile(CopyMode)));
+
+ connect(currentCopyInstance.interface,SIGNAL(removeItems(QList<int>)), currentCopyInstance.engine,SLOT(removeItems(QList<int>)));
+ connect(currentCopyInstance.interface,SIGNAL(moveItemsOnTop(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsOnTop(QList<int>)));
+ connect(currentCopyInstance.interface,SIGNAL(moveItemsUp(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsUp(QList<int>)));
+ connect(currentCopyInstance.interface,SIGNAL(moveItemsDown(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsDown(QList<int>)));
+ connect(currentCopyInstance.interface,SIGNAL(moveItemsOnBottom(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsOnBottom(QList<int>)));
+ connect(currentCopyInstance.interface,SIGNAL(exportTransferList()), currentCopyInstance.engine,SLOT(exportTransferList()));
+ connect(currentCopyInstance.interface,SIGNAL(importTransferList()), currentCopyInstance.engine,SLOT(importTransferList()));
+
+ connect(currentCopyInstance.interface,SIGNAL(newSpeedLimitation(qint64)), this,SLOT(resetSpeedDetectedInterface()));
+ connect(currentCopyInstance.interface,SIGNAL(resume()), this,SLOT(resetSpeedDetectedInterface()));
+ connect(currentCopyInstance.interface,SIGNAL(cancel()), this,SLOT(copyInstanceCanceledByInterface()),Qt::QueuedConnection);
+ connect(currentCopyInstance.interface,SIGNAL(urlDropped(QList<QUrl>)), this,SLOT(urlDropped(QList<QUrl>)),Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(newActionOnList(QList<returnActionOnCopyList>)),this,SLOT(getActionOnList(QList<returnActionOnCopyList>)), Qt::QueuedConnection);
+
+ connect(currentCopyInstance.engine,SIGNAL(pushFileProgression(QList<ProgressionItem>)), currentCopyInstance.interface,SLOT(setFileProgression(QList<ProgressionItem>)), Qt::QueuedConnection);
+ connect(currentCopyInstance.engine,SIGNAL(pushGeneralProgression(quint64,quint64)), currentCopyInstance.interface,SLOT(setGeneralProgression(quint64,quint64)), Qt::QueuedConnection);
+
+ currentCopyInstance.interface->setSpeedLimitation(currentCopyInstance.engine->getSpeedLimitation());
+ currentCopyInstance.interface->setErrorAction(currentCopyInstance.engine->getErrorAction());
+ currentCopyInstance.interface->setCollisionAction(currentCopyInstance.engine->getCollisionAction());
+ currentCopyInstance.interface->setCopyType(currentCopyInstance.type);
+ currentCopyInstance.interface->setTransferListOperation(currentCopyInstance.transferListOperation);
+ currentCopyInstance.interface->actionInProgess(currentCopyInstance.action);
+ currentCopyInstance.interface->isInPause(currentCopyInstance.isPaused);
+ if(currentCopyInstance.haveError)
+ currentCopyInstance.interface->errorDetected();
+ QWidget *tempWidget=currentCopyInstance.interface->getOptionsEngineWidget();
+ if(tempWidget!=NULL)
+ currentCopyInstance.interface->getOptionsEngineEnabled(currentCopyInstance.engine->getOptionsEngine(tempWidget));
+
+ //put entry into the interface
+ currentCopyInstance.engine->syncTransferList();
+
+ //force the updating, without wait the timer
+ periodiqueSync(index);
+}
+
+void Core::disconnectEngine(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start with index: %1").arg(index));
+ CopyInstance& currentCopyInstance=copyList[index];
+ disconnect(currentCopyInstance.engine,SIGNAL(newFolderListing(QString)), this,SLOT(newFolderListing(QString)));//to check to change
+ disconnect(currentCopyInstance.engine,SIGNAL(newCollisionAction(QString)), this,SLOT(newCollisionAction(QString)));
+ disconnect(currentCopyInstance.engine,SIGNAL(newErrorAction(QString)), this,SLOT(newErrorAction(QString)));
+ disconnect(currentCopyInstance.engine,SIGNAL(actionInProgess(EngineActionInProgress)), this,SLOT(actionInProgess(EngineActionInProgress)));
+ disconnect(currentCopyInstance.engine,SIGNAL(isInPause(bool)), this,SLOT(isInPause(bool)));//to check to change
+ disconnect(currentCopyInstance.engine,SIGNAL(cancelAll()), this,SLOT(copyInstanceCanceledByEngine()));
+ disconnect(currentCopyInstance.engine,SIGNAL(error(QString,quint64,QDateTime,QString)), this,SLOT(error(QString,quint64,QDateTime,QString)));
+ disconnect(currentCopyInstance.engine,SIGNAL(rmPath(QString)), this,SLOT(rmPath(QString)));
+ disconnect(currentCopyInstance.engine,SIGNAL(mkPath(QString)), this,SLOT(mkPath(QString)));
+
+}
+
+void Core::disconnectInterface(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start with index: %1").arg(index));
+ CopyInstance& currentCopyInstance=copyList[index];
+ disconnect(currentCopyInstance.interface,SIGNAL(pause()), currentCopyInstance.engine,SLOT(pause()));
+ disconnect(currentCopyInstance.interface,SIGNAL(resume()), currentCopyInstance.engine,SLOT(resume()));
+ disconnect(currentCopyInstance.interface,SIGNAL(skip(quint64)), currentCopyInstance.engine,SLOT(skip(quint64)));
+ disconnect(currentCopyInstance.interface,SIGNAL(sendErrorAction(QString)), currentCopyInstance.engine,SLOT(setErrorAction(QString)));
+ disconnect(currentCopyInstance.interface,SIGNAL(newSpeedLimitation(qint64)), currentCopyInstance.engine,SLOT(setSpeedLimitation(qint64)));
+ disconnect(currentCopyInstance.interface,SIGNAL(sendCollisionAction(QString)), currentCopyInstance.engine,SLOT(setCollisionAction(QString)));
+ disconnect(currentCopyInstance.interface,SIGNAL(userAddFolder(CopyMode)), currentCopyInstance.engine,SLOT(userAddFolder(CopyMode)));
+ disconnect(currentCopyInstance.interface,SIGNAL(userAddFile(CopyMode)), currentCopyInstance.engine,SLOT(userAddFile(CopyMode)));
+
+ disconnect(currentCopyInstance.interface,SIGNAL(removeItems(QList<int>)), currentCopyInstance.engine,SLOT(removeItems(QList<int>)));
+ disconnect(currentCopyInstance.interface,SIGNAL(moveItemsOnTop(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsOnTop(QList<int>)));
+ disconnect(currentCopyInstance.interface,SIGNAL(moveItemsUp(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsUp(QList<int>)));
+ disconnect(currentCopyInstance.interface,SIGNAL(moveItemsDown(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsDown(QList<int>)));
+ disconnect(currentCopyInstance.interface,SIGNAL(moveItemsOnBottom(QList<int>)), currentCopyInstance.engine,SLOT(moveItemsOnBottom(QList<int>)));
+
+ disconnect(currentCopyInstance.interface,SIGNAL(newSpeedLimitation(qint64)), this,SLOT(resetSpeedDetectedInterface()));
+ disconnect(currentCopyInstance.interface,SIGNAL(resume()), this,SLOT(resetSpeedDetectedInterface()));
+ disconnect(currentCopyInstance.interface,SIGNAL(cancel()), this,SLOT(copyInstanceCanceledByInterface()));
+ disconnect(currentCopyInstance.interface,SIGNAL(urlDropped(QList<QUrl>)), this,SLOT(urlDropped(QList<QUrl>)));
+
+ disconnect(currentCopyInstance.engine,SIGNAL(newActionOnList(QList<returnActionOnCopyList>)), currentCopyInstance.interface,SLOT(getActionOnList(QList<returnActionOnCopyList>)));
+ disconnect(currentCopyInstance.engine,SIGNAL(pushFileProgression(QList<ProgressionItem>)), currentCopyInstance.interface,SLOT(setFileProgression(QList<ProgressionItem>)));
+ disconnect(currentCopyInstance.engine,SIGNAL(pushGeneralProgression(quint64,quint64)), currentCopyInstance.interface,SLOT(setGeneralProgression(quint64,quint64)));
+}
+
+void Core::periodiqueSync()
+{
+ index_sub_loop=0;
+ loop_size=copyList.size();
+ while(index_sub_loop<loop_size)
+ {
+ if(copyList.at(index_sub_loop).action==Copying || copyList.at(index_sub_loop).action==CopyingAndListing)
+ periodiqueSync(index_sub_loop);
+ index_sub_loop++;
+ }
+}
+
+void Core::periodiqueSync(const int &index)
+{
+ CopyInstance& currentCopyInstance=copyList[index];
+ if(currentCopyInstance.engine==NULL || currentCopyInstance.interface==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"some thread is null");
+ return;
+ }
+
+ /** ***************** Do time calcul ******************* **/
+ if(!currentCopyInstance.isPaused)
+ {
+ //calcul the last difference of the transfere
+ quint64 realByteTransfered=currentCopyInstance.engine->realByteTransfered();
+ quint64 diffCopiedSize=0;
+ if(realByteTransfered>=currentCopyInstance.lastProgression)
+ diffCopiedSize=realByteTransfered-currentCopyInstance.lastProgression;
+ currentCopyInstance.lastProgression=realByteTransfered;
+ //do the remaining time calculation
+ //byte per ms: lastProgression/(baseTime+currentCopyInstance.runningTime.elapsed()
+ //currentCopyInstance.lastProgression
+ if(currentCopyInstance.lastProgression==0)
+ currentCopyInstance.interface->remainingTime(-1);
+ else
+ currentCopyInstance.interface->remainingTime(
+ (
+ (double)(realByteTransfered)
+ *(currentCopyInstance.baseTime+currentCopyInstance.runningTime.elapsed())
+ /(currentCopyInstance.lastProgression)
+ )/1000
+ );
+ if(lastProgressionTime.isNull())
+ lastProgressionTime.start();
+ else
+ {
+ if((currentCopyInstance.action==Copying || currentCopyInstance.action==CopyingAndListing))
+ {
+ currentCopyInstance.lastSpeedTime << lastProgressionTime.elapsed();
+ currentCopyInstance.lastSpeedDetected << diffCopiedSize;
+ while(currentCopyInstance.lastSpeedDetected.size()>ULTRACOPIER_MAXVALUESPEEDSTORED)
+ {
+ currentCopyInstance.lastSpeedTime.removeFirst();
+ currentCopyInstance.lastSpeedDetected.removeFirst();
+ }
+ totTime=0;
+ totSpeed=0;
+ index_sub_loop=0;
+ loop_size=currentCopyInstance.lastSpeedDetected.size();
+ while(index_sub_loop<loop_size)
+ {
+ totTime+=currentCopyInstance.lastSpeedTime.at(index_sub_loop);
+ totSpeed+=currentCopyInstance.lastSpeedDetected.at(index_sub_loop);
+ index_sub_loop++;
+ }
+ totTime/=1000;
+ currentCopyInstance.interface->detectedSpeed(totSpeed/totTime);
+ }
+ lastProgressionTime.restart();
+ }
+ }
+}
+
+void Core::copyInstanceCanceledByEngine()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ copyInstanceCanceledByIndex(index);
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
+
+void Core::copyInstanceCanceledByInterface()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=indexCopySenderInterface();
+ if(index!=-1)
+ copyInstanceCanceledByIndex(index);
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
+
+void Core::copyInstanceCanceledByIndex(const int &index)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start, remove with the index: "+QString::number(index));
+ disconnectEngine(index);
+ disconnectInterface(index);
+ CopyInstance& currentCopyInstance=copyList[index];
+ currentCopyInstance.engine->cancel();
+ delete currentCopyInstance.nextConditionalSync;
+ delete currentCopyInstance.engine;
+ delete currentCopyInstance.interface;
+ index_sub_loop=0;
+ loop_size=currentCopyInstance.orderId.size();
+ while(index_sub_loop<loop_size)
+ {
+ emit copyCanceled(currentCopyInstance.orderId.at(index_sub_loop));
+ index_sub_loop++;
+ }
+ currentCopyInstance.orderId.clear();
+ copyList.removeAt(index);
+ if(copyList.size()==0)
+ forUpateInformation.stop();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"copyList.size(): "+QString::number(copyList.size()));
+}
+
+//error occurred
+void Core::error(const QString &path,const quint64 &size,const QDateTime &mtime,const QString &error)
+{
+ log.error(path,size,mtime,error);
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ copyList[index].haveError=true;
+ copyList.at(index).interface->errorDetected();
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
+
+//for the extra logging
+void Core::rmPath(const QString &path)
+{
+ log.rmPath(path);
+}
+
+void Core::mkPath(const QString &path)
+{
+ log.mkPath(path);
+}
+
+void Core::syncReady()
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ copyList[index].copyEngineIsSync=true;
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
+
+void Core::getActionOnList(const QList<returnActionOnCopyList> & actionList)
+{
+ int index=indexCopySenderCopyEngine();
+ if(index!=-1)
+ {
+ if(copyList[index].copyEngineIsSync)
+ copyList[index].interface->getActionOnList(actionList);
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
+
+void Core::urlDropped(const QList<QUrl> &urls)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=indexCopySenderInterface();
+ if(index!=-1)
+ {
+ QStringList sources;
+ int index_loop=0;
+ while(index_loop<urls.size())
+ {
+ if(!urls.at(index_loop).isEmpty())
+ sources << urls.at(index_loop).toLocalFile();
+ index_loop++;
+ }
+ if(sources.size()==0)
+ return;
+ else
+ {
+ if(copyList.at(index).ignoreMode)
+ {
+ QMessageBox::StandardButton reply=QMessageBox::question(copyList.at(index).interface,tr("Transfer mode"),tr("Do you want do as a copy? Else if you reply no, it will be moved."),QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,QMessageBox::Cancel);
+ if(reply==QMessageBox::Yes)
+ copyList.at(index).engine->newCopy(sources);
+ if(reply==QMessageBox::No)
+ copyList.at(index).engine->newMove(sources);
+ }
+ else
+ {
+ if(copyList.at(index).mode==Copy)
+ copyList.at(index).engine->newCopy(sources);
+ else
+ copyList.at(index).engine->newMove(sources);
+ }
+ }
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to locate the copy engine sender");
+}
diff --git a/Core.h b/Core.h
new file mode 100644
index 0000000..c0f948e
--- /dev/null
+++ b/Core.h
@@ -0,0 +1,136 @@
+/** \file Core.h
+\brief Define the class definition for core, the Copy of each copy/move window
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef CORE_H
+#define CORE_H
+
+#include <QObject>
+#include <QStringList>
+#include <QString>
+#include <QList>
+#include <QTimer>
+#include <QTime>
+#include <QFile>
+#include <QUrl>
+
+#include "Environment.h"
+#include "StructEnumDefinition.h"
+#include "CopyEngineManager.h"
+#include "GlobalClass.h"
+#include "LogThread.h"
+#include "interface/PluginInterface_CopyEngine.h"
+#include "interface/PluginInterface_Themes.h"
+
+/** \brief Define the class definition for core, the Copy of each copy/move window
+
+This class provide a core for dispatch the event of signal/slot, it checks too if not other instance is running */
+class Core : public QObject, public GlobalClass
+{
+ Q_OBJECT
+ public:
+ /// \brief Initate the core of one copy or move window, dispatch the event specific at this window
+ Core(CopyEngineManager *copyEngineList);
+ private:
+ CopyEngineManager *copyEngineList;
+ struct RunningTransfer
+ {
+ ItemOfCopyList item;
+ bool progression;
+ };
+ struct CopyInstance
+ {
+ int id;
+ PluginInterface_CopyEngine * engine;
+ PluginInterface_Themes * interface;
+ bool ignoreMode;
+ CopyMode mode;
+ quint64 numberOfFile;
+ quint64 numberOfTransferedFile;
+ quint64 sizeToCopy;
+ EngineActionInProgress action;
+ quint64 lastProgression;//store the real byte transfered, used in time remaining calculation
+ QList<quint64> lastSpeedDetected;//stored in bytes
+ QList<double> lastSpeedTime;//stored in ms
+ QList<RunningTransfer> transferItemList;//full info of started item, to have wich progression to poll
+ QList<quint32> orderId;//external order send via listener plugin
+ QString folderListing;
+ QString collisionAction;
+ QString errorAction;
+ bool isPaused;
+ quint64 baseTime;//stored in ms
+ QTime runningTime;
+ bool isRunning;
+ CopyType type;
+ TransferListOperation transferListOperation;
+ bool haveError;
+ QTime lastConditionalSync;
+ QTimer *nextConditionalSync;
+ bool copyEngineIsSync;
+ };
+ QList<CopyInstance> copyList;
+ int openNewCopy(const CopyMode &mode,const bool &ignoreMode,const QStringList &protocolsUsedForTheSources=QStringList(),const QString &protocolsUsedForTheDestination="");
+ int openNewCopy(const CopyMode &mode,const bool &ignoreMode,const QString &name);
+ int incrementId();
+ int nextId;
+ QList<int> idList;
+ QTime lastProgressionTime;
+ int indexCopySenderCopyEngine();
+ int indexCopySenderInterface();
+ void connectEngine(const int &index);
+ void connectInterfaceAndSync(const int &index);
+ void disconnectEngine(const int &index);
+ void disconnectInterface(const int &index);
+ void periodiqueSync(const int &index);
+ QTimer forUpateInformation;
+ void resetSpeedDetected(const int &index);
+ int connectCopyEngine(const CopyMode &mode,bool ignoreMode,const CopyEngineManager::returnCopyEngine &returnInformations);
+ LogThread log;
+ //temp variable
+ int index,index_sub_loop,loop_size,loop_sub_size;
+ double totTime;
+ double totSpeed;
+ signals:
+ void copyFinished(const quint32 & orderId,bool withError);
+ void copyCanceled(const quint32 & orderId);
+ public slots:
+ /** \brief do copy with sources, but ask the destination */
+ void newCopy(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources);
+ /** \brief do copy with sources and destination */
+ void newCopy(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources,const QString &protocolsUsedForTheDestination,const QString &destination);
+ /** \brief do move with sources, but ask the destination */
+ void newMove(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources);
+ /** \brief do move with sources and destination */
+ void newMove(const quint32 &orderId,const QStringList &protocolsUsedForTheSources,const QStringList &sources,const QString &protocolsUsedForTheDestination,const QString &destination);
+ /** \brief open copy/move windows with specific engine */
+ void addWindowCopyMove(const CopyMode &mode,const QString &name);
+ /** \brief open transfer (copy+move) windows with specific engine */
+ void addWindowTransfer(const QString &name);
+ private slots:
+ void copyInstanceCanceledByEngine();
+ void copyInstanceCanceledByInterface();
+ void copyInstanceCanceledByIndex(const int &index);
+ void actionInProgess(const EngineActionInProgress &action);
+ void newFolderListing(const QString &path);
+ void newCollisionAction(const QString &action);
+ void newErrorAction(const QString &action);
+ void isInPause(const bool&);
+ void periodiqueSync();
+ void resetSpeedDetectedEngine();
+ void resetSpeedDetectedInterface();
+ void loadInterface();
+ void unloadInterface();
+ //error occurred
+ void error(const QString &path,const quint64 &size,const QDateTime &mtime,const QString &error);
+ //for the extra logging
+ void rmPath(const QString &path);
+ void mkPath(const QString &path);
+ void urlDropped(const QList<QUrl> &urls);
+ void syncReady();
+ void getActionOnList(const QList<returnActionOnCopyList> & actionList);
+};
+
+#endif // CORE_H
diff --git a/DebugEngine.cpp b/DebugEngine.cpp
new file mode 100644
index 0000000..4fe6314
--- /dev/null
+++ b/DebugEngine.cpp
@@ -0,0 +1,386 @@
+/** \file DebugEngine.cpp
+\brief Define the class for the debug
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDir>
+#include <QFSFileEngine>
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QLocalSocket>
+
+#include "Variable.h"
+#include "DebugEngine.h"
+#include "ExtraSocket.h"
+
+/// \brief The local macro: ULTRACOPIER_DEBUGCONSOLE
+#if defined (__FILE__) && defined (__LINE__)
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) addDebugInformation(a,__func__,b,__FILE__,__LINE__)
+#else
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) addDebugInformation(a,__func__,b)
+#endif
+
+#ifdef ULTRACOPIER_DEBUG
+
+/// \brief initiate the ultracopier event dispatcher and check if no other session is running
+DebugEngine::DebugEngine()
+{
+ addDebugInformationCallNumber=0;
+ //Load the first content
+ debugHtmlContent+="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
+ debugHtmlContent+="<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">";
+ debugHtmlContent+="<head>";
+ debugHtmlContent+="<meta name=\"Language\" content=\"en\" />";
+ debugHtmlContent+="<meta http-equiv=\"content-language\" content=\"english\" />";
+ debugHtmlContent+="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />";
+ debugHtmlContent+="<style type=\"text/css\">";
+ debugHtmlContent+="body{font-family:\"DejaVu Sans Mono\";font-size:9pt;}";
+ debugHtmlContent+=".Information td{color:#7485df;}";
+ debugHtmlContent+=".Critical td{color:#ff0c00;background-color:#FFFE8C;}";
+ debugHtmlContent+=".Warning td{color:#efa200;}";
+ debugHtmlContent+=".Notice td{color:#999;}";
+ debugHtmlContent+=".time{font-weight:bold;}";
+ debugHtmlContent+=".Note{font-weight:bold;font-size:1.5em}";
+ debugHtmlContent+=".function{font-style:italic;text-decoration:underline}";
+ debugHtmlContent+=".location{padding-right:15px;}";
+ debugHtmlContent+="td {white-space:nowrap;}";
+ debugHtmlContent+="</style>";
+ debugHtmlContent+="<title>Ultracopier "+QString(ULTRACOPIER_VERSION)+" "+QString(ULTRACOPIER_PLATFORM_NAME)+", debug report</title>";
+ debugHtmlContent+="</head>";
+ debugHtmlContent+="<body>";
+ debugHtmlContent+="<table>";
+ //Load the start time at now
+ startTime.start();
+ //Load the log file end
+ endOfLogFile="</table></body></html>";
+ //check if other instance is running, then switch to memory backend
+ if(tryConnect())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: File because other session is runing");
+ currentBackend=Memory;
+ return;
+ }
+ //The lock and log file path is not defined
+ bool fileNameIsLoaded=false;
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ #ifdef ULTRACOPIER_VERSION_PORTABLEAPPS
+ //Load the data folder path
+ QDir dir(QCoreApplication::applicationDirPath());
+ dir.cdUp();
+ dir.cdUp();
+ dir.cd("Data");
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ fileNameIsLoaded=true;
+ #else
+ //Load the ultracopier path
+ QDir dir(QCoreApplication::applicationDirPath());
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ fileNameIsLoaded=true;
+ #endif
+ #else
+ #ifdef Q_OS_WIN32
+ #define EXTRA_HOME_PATH "\\ultracopier\\"
+ #else
+ #define EXTRA_HOME_PATH "/.config/Ultracopier/"
+ #endif
+ //Load the user path only if exists and writable
+ QDir dir(QFSFileEngine::homePath()+EXTRA_HOME_PATH);
+ bool errorFound=false;
+ //If user's directory not exists create it
+ if(!dir.exists())
+ {
+ //If failed not load the file
+ if(!dir.mkpath(dir.absolutePath()))
+ {
+ errorFound=true;
+ puts(qPrintable("Unable to make path: "+dir.absolutePath()+", disable file log"));
+ }
+ }
+ //If no error found set the file name
+ if(errorFound==false)
+ {
+ fileNameIsLoaded=true;
+ logFile.setFileName(dir.absolutePath()+QDir::separator()+"log.html");
+ lockFile.setFileName(dir.absolutePath()+QDir::separator()+"ultracopier.lock");
+ }
+ errorFound=false;
+ #endif
+ //If the file name is loaded
+ if(fileNameIsLoaded)
+ {
+ //If the previous file is here, then crash previous, ask if the user want to save
+ if(lockFile.exists() && logFile.exists())
+ {
+ //Try open the file as read only to propose save it as the user
+ //Don't ask it if unable to write, because unable to remove, then alert at all start
+ if(removeTheLockFile())
+ {
+ //Ask to the user
+ QMessageBox::StandardButton reply = QMessageBox::question(NULL,"Save the previous report","Ultracopier seam have crashed, do you want save the previous report for report it to the forum?",QMessageBox::Yes|QMessageBox::No,QMessageBox::No);
+ if(reply==QMessageBox::Yes)
+ saveBugReport();
+ }
+ else
+ puts(qPrintable(logFile.fileName()+" unable to open it as read"));
+ }
+ //Now try to create and open the log file and lock file
+ if(!lockFile.open(QIODevice::WriteOnly|QIODevice::Truncate|QIODevice::Unbuffered))
+ {
+ currentBackend=Memory;
+ puts(qPrintable(lockFile.fileName()+" unable to open it as write, log into file disabled"));
+ }
+ else
+ {
+ if(!logFile.open(QIODevice::ReadWrite|QIODevice::Truncate|QIODevice::Unbuffered))
+ {
+ currentBackend=Memory;
+ puts(qPrintable(logFile.fileName()+" unable to open it as write, log into file disabled"));
+ removeTheLockFile();
+ }
+ else
+ {
+ currentBackend=File;
+ logFile.write(debugHtmlContent.toUtf8());
+ }
+ }
+ }
+ if(currentBackend==File)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: File");
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"currentBackend: Memory");
+}
+
+/// \brief Destroy the ultracopier event dispatcher
+DebugEngine::~DebugEngine()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"start");
+ if(currentBackend==File)
+ {
+ removeTheLockFile();
+ //Finalize the log file
+ logFile.write(endOfLogFile.toUtf8());
+ logFile.close();
+ }
+}
+
+/// \brief ask to the user where save the bug report
+void DebugEngine::saveBugReport()
+{
+ bool errorFound;
+ do
+ {
+ errorFound=false;
+ //Ask where it which save it
+ QString fileName = QFileDialog::getSaveFileName(NULL,"Save file","ultracopier-bug-report.log.html","Log file (*.log.html)");
+ if(fileName!="")
+ {
+ if(QFile::exists(fileName))
+ {
+ if(!QFile::remove(fileName))
+ {
+ errorFound=true;
+ puts(qPrintable(fileName+" unable remove it"));
+ QMessageBox::critical(NULL,"Error","Unable to save the bug report");
+ }
+ }
+ if(!errorFound)
+ {
+ //Open the destination as write
+ if(!logFile.copy(fileName))
+ {
+ errorFound=true;
+ puts(qPrintable(fileName+" unable to open it as write: "+logFile.errorString()));
+ QMessageBox::critical(NULL,"Error","Unable to save the bug report"+logFile.errorString());
+ }
+ }
+ }
+ } while(errorFound!=false);
+}
+
+/// \brief Internal function to remove the lock file
+bool DebugEngine::removeTheLockFile()
+{
+ //close the file and remove it
+ lockFile.close();
+ if(!lockFile.remove())
+ {
+ puts(qPrintable(lockFile.fileName()+" unable to remove it, crash report at the next start"));
+ return false;
+ }
+ else
+ return true;
+}
+
+void DebugEngine::addDebugInformationStatic(const DebugLevel &level,const QString& function,const QString& text,const QString& file,const int& ligne,const QString& location)
+{
+ DebugEngine *debug_engine_instance=DebugEngine::getInstance();
+ DebugLevel_custom tempLevel=DebugLevel_custom_Information;
+ switch(level)
+ {
+ case DebugLevel_Information:
+ tempLevel=DebugLevel_custom_Information;
+ break;
+ case DebugLevel_Critical:
+ tempLevel=DebugLevel_custom_Critical;
+ break;
+ case DebugLevel_Warning:
+ tempLevel=DebugLevel_custom_Warning;
+ break;
+ case DebugLevel_Notice:
+ tempLevel=DebugLevel_custom_Notice;
+ break;
+ default:
+ tempLevel=DebugLevel_custom_Notice;
+ }
+ debug_engine_instance->addDebugInformation(tempLevel,function,text,file,ligne,location);
+ DebugEngine::destroyInstanceAtTheLastCall();
+}
+
+void DebugEngine::addDebugNote(const QString& text)
+{
+ DebugEngine *debug_engine_instance=DebugEngine::getInstance();
+ debug_engine_instance->addDebugInformation(DebugLevel_custom_UserNote,"",text,"",-1,"Core");
+ DebugEngine::destroyInstanceAtTheLastCall();
+}
+
+/// \brief For add message info, this function is thread safe
+void DebugEngine::addDebugInformation(const DebugLevel_custom &level,const QString& function,const QString& text,QString file,const int& ligne,const QString& location)
+{
+ //Remove the compiler extra patch generated
+ file=file.remove(QRegExp("\\.\\.?[/\\\\]([^/]+[/\\\\])?"));
+ QString addDebugInformation_lignestring=QString::number(ligne);
+ QString addDebugInformation_fileString=file;
+ if(ligne!=-1)
+ addDebugInformation_fileString+=":"+addDebugInformation_lignestring;
+ //Load the time from start
+ QString addDebugInformation_time = QString::number(startTime.elapsed());
+ QString addDebugInformation_htmlFormat;
+ switch(level)
+ {
+ case DebugLevel_custom_Information:
+ addDebugInformation_htmlFormat="<tr class=\"Information\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Critical:
+ addDebugInformation_htmlFormat="<tr class=\"Critical\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Warning:
+ addDebugInformation_htmlFormat="<tr class=\"Warning\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_Notice:
+ addDebugInformation_htmlFormat="<tr class=\"Notice\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ case DebugLevel_custom_UserNote:
+ addDebugInformation_htmlFormat="<tr class=\"Note\"><td class=\"time\">"+addDebugInformation_time+"</span></td><td>"+addDebugInformation_fileString+"</td><td class=\"function\">"+function+"()</td><td class=\"location\">"+location+"</td><td>"+htmlEntities(text)+"</td></tr>\n";
+ break;
+ }
+ //To prevent access of string in multi-thread
+ {
+ //Show the text in console
+ QString addDebugInformation_textFormat;
+ addDebugInformation_textFormat = "("+addDebugInformation_time.rightJustified(8,' ')+") ";
+ if(file!="" && ligne!=-1)
+ addDebugInformation_textFormat += file+":"+addDebugInformation_lignestring+":";
+ addDebugInformation_textFormat += function+"(), (location: "+location+"): "+text;
+ puts(qPrintable(addDebugInformation_textFormat));
+ QMutexLocker lock_mutex(&mutex);
+ if(currentBackend==File)
+ {
+ if(logFile.size()>64*1024*1024) // greater than 64MB
+ puts("File log greater than 64MB, stop to record it!");
+ else
+ logFile.write(addDebugInformation_htmlFormat.toUtf8());
+ }
+ else
+ {
+ if(debugHtmlContent.size()<64*1024*1024)
+ debugHtmlContent+=addDebugInformation_htmlFormat;
+ else
+ puts("String greater than 64MB, stop to record it!");
+ }
+ ItemOfDebug newItem;
+ newItem.time=addDebugInformation_time;
+ newItem.level=level;
+ newItem.function=function;
+ if(addDebugInformation_lignestring!="-1")
+ newItem.file=file+":"+addDebugInformation_lignestring;
+ else
+ newItem.file=file;
+ newItem.location=location;
+ newItem.text=text;
+ listItemOfDebug << newItem;
+ }
+ //Send the new line
+ if(addDebugInformationCallNumber<ULTRACOPIER_DEBUG_MAX_GUI_LINE)
+ {
+ addDebugInformationCallNumber++;
+ emit newDebugInformation();
+ }
+}
+
+QList<DebugEngine::ItemOfDebug> DebugEngine::getItemList()
+{
+ QList<DebugEngine::ItemOfDebug> returnedList;
+ {
+ QMutexLocker lock_mutex(&mutexList);
+ returnedList=listItemOfDebug;
+ listItemOfDebug.clear();
+ }
+ return returnedList;
+}
+
+/// \brief Get the html text info for re-show it
+QString DebugEngine::getTheDebugHtml()
+{
+ if(currentBackend==File)
+ {
+ logFile.seek(0);
+ if(!logFile.isOpen())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Warning,"The log file is not open");
+ return QString().fromUtf8(logFile.readAll().data())+endOfLogFile;
+ }
+ else
+ return debugHtmlContent+endOfLogFile;
+}
+
+/// \brief Get the html end
+QString DebugEngine::getTheDebugEnd()
+{
+ return endOfLogFile;
+}
+
+/// \brief Drop the html entities
+QString DebugEngine::htmlEntities(QString text)
+{
+ text.replace('&',"&amp;");
+ text.replace('"',"&quot;");
+ text.replace('\'',"&#039;");
+ text.replace('<',"&lt;");
+ text.replace('>',"&gt;");
+ return text;
+}
+
+/// \brief return the current backend
+DebugEngine::Backend DebugEngine::getCurrentBackend()
+{
+ return currentBackend;
+}
+
+bool DebugEngine::tryConnect()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_custom_Notice,"start");
+ QLocalSocket localSocket;
+ localSocket.connectToServer(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME),QIODevice::WriteOnly|QIODevice::Unbuffered);
+ if(localSocket.waitForConnected(1000))
+ {
+ localSocket.disconnectFromServer();
+ return true;
+ }
+ else
+ return false;
+}
+
+#endif
diff --git a/DebugEngine.h b/DebugEngine.h
new file mode 100644
index 0000000..d717c2e
--- /dev/null
+++ b/DebugEngine.h
@@ -0,0 +1,114 @@
+/** \file DebugEngine.h
+\brief Define the class for the debug
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\note This class don't need be thread safe because ultracopier is done with one thread, but I have implement some basic thread protection
+\licence GPL3, see the file COPYING */
+
+#ifndef DEBUG_ENGINE_H
+#define DEBUG_ENGINE_H
+
+#include <QObject>
+#include <QString>
+#include <QFile>
+#include <QMutex>
+#include <QTime>
+#include <QList>
+#include <QCoreApplication>
+
+#include "Variable.h"
+#include "PlatformMacro.h"
+#include "StructEnumDefinition.h"
+#include "StructEnumDefinition_UltracopierSpecific.h"
+#include "Singleton.h"
+
+#ifdef ULTRACOPIER_DEBUG
+
+/** \brief Define the class for the debug
+
+This class provide all needed for the debug mode of ultracopier */
+class DebugEngine : public QObject, public Singleton<DebugEngine>
+{
+ Q_OBJECT
+ friend class Singleton<DebugEngine>;
+ public:
+ /** \brief Get the html text info for re-show it
+ \note This function is thread safe */
+ QString getTheDebugHtml();
+ /// \brief Enumeration of backend
+ enum Backend
+ {
+ Memory, //Do intensive usage of memory, used only if the file backend is not available
+ File //Store all directly into file, at crash the backtrace is into the file
+ };
+ /// \brief return the current backend
+ Backend getCurrentBackend();
+ /// \brief Get the html end
+ QString getTheDebugEnd();
+ /** \brief For add message info, this function
+ \note This function is reentrant */
+ static void addDebugInformationStatic(const DebugLevel &level,const QString& function,const QString& text,const QString& file="",const int& ligne=-1,const QString& location="Core");
+ static void addDebugNote(const QString& text);
+ /** \brief structure for one debug item */
+ struct ItemOfDebug
+ {
+ DebugLevel_custom level;
+ QString time;
+ QString file;
+ QString function;
+ QString location;
+ QString text;
+ };
+ QList<ItemOfDebug> listItemOfDebug;
+ QList<ItemOfDebug> getItemList();
+ public slots:
+ /** \brief ask to the user where save the bug report
+ \warning This function can be only call by the graphical thread */
+ void saveBugReport();
+ /// \todo Put into DebugEngine the dialog to send by the net
+ void addDebugInformation(const DebugLevel_custom &level,const QString& fonction,const QString& text,QString file="",const int& ligne=-1,const QString& location="Core");
+ private:
+ /// \brief Initiate the ultracopier event dispatcher and check if no other session is running
+ DebugEngine();
+ /** \brief Destroy the ultracopier event dispatcher
+ \note This function is thread safe */
+ ~DebugEngine();
+ /// \brief Path for log file
+ QFile logFile;
+ /// \brief Path for lock file
+ QFile lockFile;
+ /// \brief Internal function to remove the lock file
+ bool removeTheLockFile();
+ /** \brief Do thread safe part for the addDebugInformation()
+ \see addDebugInformation() */
+ QMutex mutex;
+ QMutex mutexList;
+ /// \brief For record the start time
+ QTime startTime;
+ /// \brief String for the end of log file
+ QString endOfLogFile;
+ /// \brief Drop the html entities
+ QString htmlEntities(QString text);
+ /// \brief To store the debug informations
+ QString debugHtmlContent;
+ /// \brief The current backend
+ Backend currentBackend;
+ /// try connect to send to the current running instance the arguements
+ bool tryConnect();
+ //temp variable
+ /* can't because multiple thread can access at this variable
+ QString addDebugInformation_lignestring;
+ QString addDebugInformation_fileString;
+ QString addDebugInformation_time;
+ QString addDebugInformation_htmlFormat;
+ QString addDebugInformation_textFormat;*/
+ quint32 addDebugInformationCallNumber;
+ signals:
+ /// \brief Send that's when new debug info is added
+ void newDebugInformation();
+};
+
+#endif // ULTRACOPIER_DEBUG
+
+#endif // DEBUG_ENGINE_H
diff --git a/DebugEngineMacro.h b/DebugEngineMacro.h
new file mode 100644
index 0000000..9a96957
--- /dev/null
+++ b/DebugEngineMacro.h
@@ -0,0 +1,26 @@
+/** \file DebugEngineMacro.h
+\brief Define the macro for the debug
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef DEBUGENGINEMACRO_H
+#define DEBUGENGINEMACRO_H
+
+/// \brief Macro for the debug log
+#ifdef ULTRACOPIER_DEBUG
+ #include "DebugEngine.h"
+ #if defined (__FILE__) && defined (__LINE__)
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) DebugEngine::addDebugInformationStatic(a,__func__,b,__FILE__,__LINE__)
+ #else
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) DebugEngine::addDebugInformationStatic(a,__func__,b)
+ #endif
+#else // ULTRACOPIER_DEBUG
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) void()
+#endif // ULTRACOPIER_DEBUG
+
+#endif // DEBUGENGINEMACRO_H
+
+
+
diff --git a/Environment.h b/Environment.h
new file mode 100644
index 0000000..dcbea70
--- /dev/null
+++ b/Environment.h
@@ -0,0 +1,19 @@
+/** \file Environment.h
+\brief Define the environment variable and global function
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "Variable.h"
+/// \brief The global include
+#include "StructEnumDefinition.h"
+#include "StructEnumDefinition_UltracopierSpecific.h"
+#include "PlatformMacro.h"
+#include "DebugEngineMacro.h"
+
+#ifdef ULTRACOPIER_VERSION_PORTABLE
+ #define ULTRACOPIER_VERSION_PORTABLE_BOOL true
+#else
+ #define ULTRACOPIER_VERSION_PORTABLE_BOOL false
+#endif
diff --git a/EventDispatcher.cpp b/EventDispatcher.cpp
new file mode 100644
index 0000000..ba8b45c
--- /dev/null
+++ b/EventDispatcher.cpp
@@ -0,0 +1,163 @@
+/** \file EventDispatcher.cpp
+\brief Define the class of the event dispatcher
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QFSFileEngine>
+#include <QCoreApplication>
+#include <QMessageBox>
+
+#include "EventDispatcher.h"
+#include "ExtraSocket.h"
+#include "CompilerInfo.h"
+
+#ifdef Q_OS_UNIX
+ #include <unistd.h>
+ #include <sys/types.h>
+#else
+ #include <windows.h>
+#endif
+
+/// \todo group the facility engine
+
+/// \brief Initiate the ultracopier event dispatcher and check if no other session is running
+EventDispatcher::EventDispatcher()
+{
+ connect(&localListener,SIGNAL(cli(QStringList,bool)),&cliParser,SLOT(cli(QStringList,bool)),Qt::QueuedConnection);
+ connect(themes, SIGNAL(newThemeOptions(QWidget*,bool,bool)), &optionDialog, SLOT(newThemeOptions(QWidget*,bool,bool)));
+ connect(&cliParser, SIGNAL(newCopy(QStringList)), &copyServer, SLOT(newCopy(QStringList)));
+ connect(&cliParser, SIGNAL(newCopy(QStringList,QString)), &copyServer, SLOT(newCopy(QStringList,QString)));
+ connect(&cliParser, SIGNAL(newMove(QStringList)), &copyServer, SLOT(newMove(QStringList)));
+ connect(&cliParser, SIGNAL(newMove(QStringList,QString)), &copyServer, SLOT(newMove(QStringList,QString)));
+ copyMoveEventIdIndex=0;
+ backgroundIcon=NULL;
+ stopIt=false;
+ sessionloader=new SessionLoader(this);
+ copyEngineList=new CopyEngineManager(&optionDialog);
+ core=new Core(copyEngineList);
+ qRegisterMetaType<CatchState>("CatchState");
+ qRegisterMetaType<ListeningState>("ListeningState");
+ qRegisterMetaType<QList<QUrl> >("QList<QUrl>");
+ qRegisterMetaType<QList<ProgressionItem> >("QList<ProgressionItem>");
+ qRegisterMetaType<QList<returnActionOnCopyList> >("QList<returnActionOnCopyList>");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //show the ultracopier information
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,QString("ULTRACOPIER_VERSION: ")+ULTRACOPIER_VERSION);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,QString("Qt version: %1 (%2)").arg(qVersion()).arg(QT_VERSION));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,QString("ULTRACOPIER_PLATFORM_NAME: ")+ULTRACOPIER_PLATFORM_NAME);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,QString("Application path: %1 (%2)").arg(QCoreApplication::applicationFilePath()).arg(QCoreApplication::applicationPid()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,COMPILERINFO);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,QString("Local socket: ")+ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME));
+ //To lunch some initialization after QApplication::exec() to quit eventually
+ lunchInitFunction.setInterval(0);
+ lunchInitFunction.setSingleShot(true);
+ connect(&lunchInitFunction,SIGNAL(timeout()),this,SLOT(initFunction()),Qt::QueuedConnection);
+ lunchInitFunction.start();
+ //add the options to use
+ QList<QPair<QString, QVariant> > KeysList;
+ //add the options hidden, will not show in options pannel
+ KeysList.clear();
+ KeysList.append(qMakePair(QString("Last_version_used"),QVariant("na")));
+ KeysList.append(qMakePair(QString("ActionOnManualOpen"),QVariant(1)));
+ KeysList.append(qMakePair(QString("GroupWindowWhen"),QVariant(3)));
+ options->addOptionGroup("Ultracopier",KeysList);
+ if(options->getOptionValue("Ultracopier","Last_version_used")!=QVariant("na") && options->getOptionValue("Ultracopier","Last_version_used")!=QVariant(ULTRACOPIER_VERSION))
+ {
+ //then ultracopier have been updated
+ }
+ options->setOptionValue("Ultracopier","Last_version_used",QVariant(ULTRACOPIER_VERSION));
+ int a=options->getOptionValue("Ultracopier","ActionOnManualOpen").toInt();
+ if(a<0 || a>2)
+ options->setOptionValue("Ultracopier","ActionOnManualOpen",QVariant(1));
+ a=options->getOptionValue("Ultracopier","GroupWindowWhen").toInt();
+ if(a<0 || a>5)
+ options->setOptionValue("Ultracopier","GroupWindowWhen",QVariant(0));
+
+ KeysList.clear();
+ KeysList.append(qMakePair(QString("List"),QVariant(QStringList() << "Ultracopier-0.3")));
+ options->addOptionGroup("CopyEngine",KeysList);
+}
+
+/// \brief Destroy the ultracopier event dispatcher
+EventDispatcher::~EventDispatcher()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ if(core!=NULL)
+ delete core;
+ if(copyEngineList!=NULL)
+ delete copyEngineList;
+ if(sessionloader!=NULL)
+ delete sessionloader;
+ if(backgroundIcon!=NULL)
+ delete backgroundIcon;
+}
+
+/// \brief return if need be close
+bool EventDispatcher::shouldBeClosed()
+{
+ return stopIt;
+}
+
+/// \brief Quit ultracopier
+void EventDispatcher::quit()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Will quit ultracopier");
+ //disconnect(QCoreApplication::instance(),SIGNAL(aboutToQuit()),this,SLOT(quit()));
+ QCoreApplication::exit();
+}
+
+/// \brief Called when event loop is setup
+void EventDispatcher::initFunction()
+{
+ if(core==NULL || copyEngineList==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Unable to initialize correctly the software");
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Initialize the variable of event loop");
+ connect(&copyServer, SIGNAL(newCopy(quint32,QStringList,QStringList)), core, SLOT(newCopy(quint32,QStringList,QStringList)));
+ connect(&copyServer, SIGNAL(newCopy(quint32,QStringList,QStringList,QString,QString)), core, SLOT(newCopy(quint32,QStringList,QStringList,QString,QString)));
+ connect(&copyServer, SIGNAL(newMove(quint32,QStringList,QStringList)), core, SLOT(newMove(quint32,QStringList,QStringList)));
+ connect(&copyServer, SIGNAL(newMove(quint32,QStringList,QStringList,QString,QString)), core, SLOT(newMove(quint32,QStringList,QStringList,QString,QString)));
+ connect(core, SIGNAL(copyFinished(quint32,bool)), &copyServer, SLOT(copyFinished(quint32,bool)));
+ connect(core, SIGNAL(copyCanceled(quint32)), &copyServer, SLOT(copyCanceled(quint32)));
+ if(localListener.tryConnect())
+ {
+ stopIt=true;
+ return;
+ }
+ localListener.listenServer();
+ //load the systray icon
+ if(backgroundIcon==NULL)
+ {
+ backgroundIcon=new SystrayIcon();
+ //connect the slot
+ //quit is for this object
+// connect(core, SIGNAL(newCanDoOnlyCopy(bool)), backgroundIcon, SLOT(newCanDoOnlyCopy(bool)));
+ connect(backgroundIcon, SIGNAL(quit()),this,SLOT(quit()));
+ //show option is for OptionEngine object
+ connect(backgroundIcon, SIGNAL(showOptions()), &optionDialog, SLOT(show()));
+ connect(&copyServer, SIGNAL(listenerReady(ListeningState,bool,bool)), backgroundIcon, SLOT(listenerReady(ListeningState,bool,bool)));
+ connect(&copyServer, SIGNAL(pluginLoaderReady(CatchState,bool,bool)), backgroundIcon, SLOT(pluginLoaderReady(CatchState,bool,bool)));
+ connect(backgroundIcon, SIGNAL(tryCatchCopy()), &copyServer, SLOT(listen()));
+ connect(backgroundIcon, SIGNAL(tryUncatchCopy()), &copyServer, SLOT(close()));
+ if(options->getOptionValue("CopyListener","CatchCopyAsDefault").toBool())
+ copyServer.listen();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"copyServer.oneListenerIsLoaded(): "+QString::number(copyServer.oneListenerIsLoaded()));
+ //backgroundIcon->readyToListen(copyServer.oneListenerIsLoaded());
+
+ connect(backgroundIcon, SIGNAL(addWindowCopyMove(CopyMode,QString)), core, SLOT(addWindowCopyMove(CopyMode,QString)));
+ connect(backgroundIcon, SIGNAL(addWindowTransfer(QString)), core, SLOT(addWindowTransfer(QString)));
+ connect(copyEngineList, SIGNAL(addCopyEngine(QString,bool)), backgroundIcon, SLOT(addCopyEngine(QString,bool)));
+ connect(copyEngineList, SIGNAL(removeCopyEngine(QString)), backgroundIcon, SLOT(removeCopyEngine(QString)));
+ copyEngineList->setIsConnected();
+ copyServer.resendState();
+ }
+ //conntect the last chance signal before quit
+ connect(QCoreApplication::instance(),SIGNAL(aboutToQuit()),this,SLOT(quit()));
+ //connect the slot for the help dialog
+ connect(backgroundIcon,SIGNAL(showHelp()),&theHelp,SLOT(show()));
+}
+
diff --git a/EventDispatcher.h b/EventDispatcher.h
new file mode 100644
index 0000000..6f583bb
--- /dev/null
+++ b/EventDispatcher.h
@@ -0,0 +1,87 @@
+/** \file EventDispatcher.h
+\brief Define the class of the event dispatcher
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef EVENT_DISPATCHER_H
+#define EVENT_DISPATCHER_H
+
+#include <QObject>
+#include <QStringList>
+#include <QString>
+#include <QTimer>
+#include <QList>
+#include <QUrl>
+
+#include "Environment.h"
+#include "Core.h"
+#include "GlobalClass.h"
+#include "SystrayIcon.h"
+#include "OptionEngine.h"
+#include "HelpDialog.h"
+#include "SessionLoader.h"
+#include "CopyListener.h"
+#include "OptionDialog.h"
+#include "CopyEngineManager.h"
+#include "LocalListener.h"
+#include "CliParser.h"
+
+/** \brief Define the class of the event dispatcher
+
+This class provide a core for dispatch the event of signal/slot, it checks too if not other instance is running */
+class EventDispatcher : public QObject, public GlobalClass
+{
+ Q_OBJECT
+ public:
+ /// \brief Initiate the ultracopier event dispatcher and check if no other session is running
+ EventDispatcher();
+ /// \brief Destroy the ultracopier event dispatcher
+ ~EventDispatcher();
+ /// \brief return if need be close
+ bool shouldBeClosed();
+ public slots:
+ /// \brief Quit ultracopier
+ void quit();
+ signals:
+ /** \brief Send that's caught state have changed for CatchedState::Uncatched or CatchedState::Semicatched or CatchedState::Catched
+ \see CatchState
+ \see tryCatchCopy()
+ \see tryUncatchCopy()
+ \param State is the new state */
+ void catchCopyStateChanged(CatchState state);
+ /** \brief Send that's copy/move task is finished in returning the copyMoveEventId
+ \see routeCopyMoveEvent()
+ \param copyMoveEventId The task id generated by routeCopyMoveEvent() */
+ void copyMoveEventIsFinish(int copyMoveEventId);
+ private:
+ /// \brief To have counter for increment the copyMoveEventId at each request
+ int copyMoveEventIdIndex;
+ /// \brief To store windows windows session
+ struct CoreSession
+ {
+ Core * CoreWindow;
+ QList<int> copyMoveEventIdManaged;
+ };
+ /// \brief the systray icon
+ SystrayIcon *backgroundIcon;
+ /// \brief To lunch event only when the event loop is setup
+ QTimer lunchInitFunction;
+ /// \brief the help dialog
+ HelpDialog theHelp;
+ /// \brief the session loader
+ SessionLoader *sessionloader;
+ bool stopIt;
+ CopyListener copyServer;
+ Core *core;
+ OptionDialog optionDialog;
+ CopyEngineManager *copyEngineList;
+ LocalListener localListener;
+ CliParser cliParser;
+ private slots:
+ /// \brief Called when event loop is setup
+ void initFunction();
+};
+
+#endif // EVENT_DISPATCHER_H
diff --git a/ExtraSocket.cpp b/ExtraSocket.cpp
new file mode 100644
index 0000000..08b0979
--- /dev/null
+++ b/ExtraSocket.cpp
@@ -0,0 +1,32 @@
+/** \file ExtraSocket.h
+\brief Define the socket of ultracopier
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "ExtraSocket.h"
+
+QString ExtraSocket::pathSocket(const QString &name)
+{
+#ifdef Q_OS_UNIX
+ return name+"-"+QString::number(getuid());
+#else
+ QString userName;
+ DWORD size=0;
+ if(GetUserNameW(NULL,&size) || (GetLastError()!=ERROR_INSUFFICIENT_BUFFER))
+ {
+ }
+ else
+ {
+ WCHAR * userNameW=new WCHAR[size];
+ if(GetUserNameW(userNameW,&size))
+ {
+ userName.fromWCharArray(userNameW,size*2);
+ userName=QString(QByteArray((char*)userNameW,size*2-2).toHex());
+ }
+ delete userNameW;
+ }
+ return name+"-"+userName;
+#endif
+}
diff --git a/ExtraSocket.h b/ExtraSocket.h
new file mode 100644
index 0000000..56229c7
--- /dev/null
+++ b/ExtraSocket.h
@@ -0,0 +1,28 @@
+/** \file ExtraSocket.h
+\brief Define the socket for ultracopier
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef EXTRASOCKET_H
+#define EXTRASOCKET_H
+
+#include <QString>
+
+#ifdef Q_OS_UNIX
+ #include <unistd.h>
+ #include <sys/types.h>
+#else
+ #include <windows.h>
+#endif
+
+/** \brief class to have general socket options */
+class ExtraSocket
+{
+public:
+ /** \brief class to return always the same socket resolution */
+ static QString pathSocket(const QString &name);
+};
+
+#endif // EXTRASOCKET_H
diff --git a/FacilityEngine.cpp b/FacilityEngine.cpp
new file mode 100644
index 0000000..1f18894
--- /dev/null
+++ b/FacilityEngine.cpp
@@ -0,0 +1,170 @@
+/** \file FacilityEngine.cpp
+\brief To implement the facility engine, the interface is defined into FacilityInterface()
+\see FacilityInterface()
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "FacilityEngine.h"
+
+#if defined (Q_OS_WIN32)
+#include <windows.h>
+#endif
+
+FacilityEngine::FacilityEngine()
+{
+ retranslate();
+}
+
+/// \brief To force the text re-translation
+void FacilityEngine::retranslate()
+{
+ //translated string
+ Translation_Copy_engine=tr("Copy engine");
+ Translation_Copy=tr("Copy");
+ Translation_Move=tr("Move");
+ Translation_Pause=tr("Pause");
+ Translation_Resume=tr("Resume");
+ Translation_Skip=tr("Skip");
+ Translation_Unlimited=tr("Unlimited");
+ //undirect translated string
+ Translation_perSecond="/"+tr("s");
+ Translation_tooBig=tr("Too big");
+ Translation_B=tr("B");
+ Translation_KB=tr("KB");
+ Translation_MB=tr("MB");
+ Translation_GB=tr("GB");
+ Translation_TB=tr("TB");
+ Translation_PB=tr("PB");
+ Translation_EB=tr("EB");
+ Translation_ZB=tr("ZB");
+ Translation_YB=tr("YB");
+}
+
+/// \brief convert size in Byte to String
+QString FacilityEngine::sizeToString(const double &size)
+{
+ double size_temp=size;
+ if(size_temp<1024)
+ return QString::number(size_temp)+sizeUnitToString(SizeUnit_byte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_KiloByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_MegaByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_GigaByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_TeraByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_PetaByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_ExaByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_ZettaByte);
+ if((size_temp=size_temp/1024)<1024)
+ return adaptString(size_temp)+sizeUnitToString(SizeUnit_YottaByte);
+ return Translation_tooBig;
+}
+
+QString FacilityEngine::adaptString(const float &size)
+{
+ if(size>=100)
+ return QString::number(size,'f',0);
+ else
+ return QString::number(size,'g',3);
+}
+
+
+/// \brief convert size unit to String
+QString FacilityEngine::sizeUnitToString(const SizeUnit &sizeUnit)
+{
+ switch(sizeUnit)
+ {
+ case SizeUnit_byte:
+ return Translation_B;
+ case SizeUnit_KiloByte:
+ return Translation_KB;
+ case SizeUnit_MegaByte:
+ return Translation_MB;
+ case SizeUnit_GigaByte:
+ return Translation_GB;
+ case SizeUnit_TeraByte:
+ return Translation_TB;
+ case SizeUnit_PetaByte:
+ return Translation_PB;
+ case SizeUnit_ExaByte:
+ return Translation_EB;
+ case SizeUnit_ZettaByte:
+ return Translation_ZB;
+ case SizeUnit_YottaByte:
+ return Translation_YB;
+ default:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"sizeUnit: "+QString::number(sizeUnit));
+ return "???";
+ }
+}
+
+/// \brief translate the text
+QString FacilityEngine::translateText(const QString &text)
+{
+ if(text=="Copy engine")
+ return Translation_Copy_engine;
+ if(text=="Copy")
+ return Translation_Copy;
+ if(text=="Move")
+ return Translation_Move;
+ if(text=="Pause")
+ return Translation_Pause;
+ if(text=="Resume")
+ return Translation_Resume;
+ if(text=="Skip")
+ return Translation_Skip;
+ if(text=="Unlimited")
+ return Translation_Unlimited;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"text: "+text);
+ return text;
+}
+
+/// \brief speed to string in byte per seconds
+QString FacilityEngine::speedToString(const double &speed)
+{
+ return sizeToString(speed)+Translation_perSecond;
+}
+/// \brief Decompose the time in second
+TimeDecomposition FacilityEngine::secondsToTimeDecomposition(const quint32 &seconds)
+{
+ quint32 seconds_temp=seconds;
+ TimeDecomposition returnValue;
+ returnValue.second=seconds_temp%60;
+ seconds_temp-=returnValue.second;
+ seconds_temp/=60;
+ returnValue.minute=seconds_temp%60;
+ seconds_temp-=returnValue.minute;
+ seconds_temp/=60;
+ returnValue.hour=seconds_temp;
+ return returnValue;
+}
+
+/// \brief have the functionality
+bool FacilityEngine::haveFunctionality(const QString &fonctionnality)
+{
+ #if defined (Q_OS_WIN32)
+ if(fonctionnality=="shutdown")
+ return true;
+ #endif
+ Q_UNUSED(fonctionnality);
+ return false;
+}
+
+/// \brief call the fonctionnality
+QVariant FacilityEngine::callFunctionality(const QString &fonctionnality,const QStringList &args)
+{
+ #if defined (Q_OS_WIN32)
+ ExitWindowsEx(EWX_POWEROFF | EWX_FORCE,0);
+ system("shutdown /s /f /t 0");
+ #endif
+ Q_UNUSED(fonctionnality);
+ Q_UNUSED(args);
+ return QVariant();
+}
diff --git a/FacilityEngine.h b/FacilityEngine.h
new file mode 100644
index 0000000..221f801
--- /dev/null
+++ b/FacilityEngine.h
@@ -0,0 +1,70 @@
+/** \file FacilityEngine.h
+\brief To implement the facility engine, the interface is defined into FacilityInterface()
+\see FacilityInterface()
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef FACILITYENGINE_H
+#define FACILITYENGINE_H
+
+#include <QVariant>
+#include <QString>
+#include <QStringList>
+
+#include "interface/FacilityInterface.h"
+#include "Environment.h"
+
+/** \brief Class to group general function for the plugin
+
+This class is used into some plugin like copy engine plugin, to all into one place all common function, group the traduction, and all what it can grouped across all plugin into Ultracopier core application.
+*/
+class FacilityEngine : public FacilityInterface
+{
+ Q_OBJECT
+public:
+ explicit FacilityEngine();
+ /// \brief convert size in Byte to String
+ QString sizeToString(const double &size);
+ /// \brief convert size unit to String
+ QString sizeUnitToString(const SizeUnit &sizeUnit);
+ /// \brief translate the text
+ QString translateText(const QString &text);
+ /// \brief speed to string in byte per seconds
+ QString speedToString(const double &speed);
+ /// \brief Decompose the time in second
+ TimeDecomposition secondsToTimeDecomposition(const quint32 &seconds);
+ /// \brief have the fonctionnality
+ bool haveFunctionality(const QString &fonctionnality);
+ /// \brief call the fonctionnality
+ QVariant callFunctionality(const QString &fonctionnality,const QStringList &args=QStringList());
+private:
+ //translated string
+ QString Translation_Copy_engine;
+ QString Translation_Copy;
+ QString Translation_Move;
+ QString Translation_Pause;
+ QString Translation_Resume;
+ QString Translation_Skip;
+ QString Translation_Unlimited;
+ //undirect translated string
+ QString Translation_perSecond;
+ QString Translation_tooBig;
+ QString Translation_B;
+ QString Translation_KB;
+ QString Translation_MB;
+ QString Translation_GB;
+ QString Translation_TB;
+ QString Translation_PB;
+ QString Translation_EB;
+ QString Translation_ZB;
+ QString Translation_YB;
+ //internal fonction
+ QString adaptString(const float &nb);
+public slots:
+ /// \brief To force the text re-translation
+ void retranslate();
+};
+
+#endif // FACILITYENGINE_H
diff --git a/GlobalClass.cpp b/GlobalClass.cpp
new file mode 100644
index 0000000..0f1c52a
--- /dev/null
+++ b/GlobalClass.cpp
@@ -0,0 +1,40 @@
+/** \file GlobalClass.cpp
+\brief Define the class for all the class different of ResourcesManager, DebugEngine, ThemesManager, OptionEngine can have object of this class at the global scope
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "GlobalClass.h"
+
+/// \brief The constructor where set the global variable to the good pointer
+GlobalClass::GlobalClass()
+{
+ //load the debug engine, themes and resources, after reused in all the program and all class derive from GlobalClass
+ #ifdef ULTRACOPIER_DEBUG
+ debug_engine_instance=DebugEngine::getInstance();
+ #endif // ULTRACOPIER_DEBUG
+ resources=ResourcesManager::getInstance();
+ plugins=PluginsManager::getInstance();
+ options=OptionEngine::getInstance();
+ themes=ThemesManager::getInstance();
+ languages=LanguagesManager::getInstance();
+}
+
+/// \brief The destructor where destroy the variable if the object no more longer used
+GlobalClass::~GlobalClass()
+{
+ //destroy the resources variable if not more used
+ LanguagesManager::destroyInstanceAtTheLastCall();
+ ThemesManager::destroyInstanceAtTheLastCall();
+ OptionEngine::destroyInstanceAtTheLastCall();
+ PluginsManager::destroyInstanceAtTheLastCall();
+ ResourcesManager::destroyInstanceAtTheLastCall();
+ #ifdef ULTRACOPIER_DEBUG
+ DebugEngine::destroyInstanceAtTheLastCall();
+ #endif // ULTRACOPIER_DEBUG
+}
+
+
+
+
diff --git a/GlobalClass.h b/GlobalClass.h
new file mode 100644
index 0000000..21dd12e
--- /dev/null
+++ b/GlobalClass.h
@@ -0,0 +1,44 @@
+/** \file GlobalClass.h
+\brief Define the class for all the class different of ResourcesManager, DebugEngine, ThemesManager, OptionEngine have object of this class at the global scope
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef GLOBAL_CLASS_H
+#define GLOBAL_CLASS_H
+
+#include "Environment.h"
+#include "ThemesManager.h"
+#include "ResourcesManager.h"
+#include "OptionEngine.h"
+#include "LanguagesManager.h"
+#include "PluginsManager.h"
+
+#include "interface/OptionInterface.h"
+
+/// \brief Define the class for the debug and global variables heritage
+class GlobalClass
+{
+ public:
+ /// \brief The constructor where set the global variable to the good pointer
+ GlobalClass();
+ /// \brief The destructor where destroy the variable if the unique instance is no more longer used
+ ~GlobalClass();
+ protected:
+ //for the themes
+ ThemesManager *themes;
+ //for the resources linked with the themes
+ ResourcesManager *resources;
+ //for the options
+ OptionEngine *options;
+ //for the languages
+ LanguagesManager *languages;
+ //for the plugins
+ PluginsManager *plugins;
+ #ifdef ULTRACOPIER_DEBUG
+ DebugEngine *debug_engine_instance;
+ #endif // ULTRACOPIER_DEBUG
+};
+
+#endif // GLOBAL_CLASS_H
diff --git a/HelpDialog.cpp b/HelpDialog.cpp
new file mode 100644
index 0000000..c9137e9
--- /dev/null
+++ b/HelpDialog.cpp
@@ -0,0 +1,175 @@
+/** \file HelpDialog.cpp
+\brief Define the help dialog
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "HelpDialog.h"
+
+#include <QTreeWidgetItem>
+#include <QApplication>
+
+/// \brief Construct the object
+HelpDialog::HelpDialog() :
+ ui(new Ui::HelpDialog)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ ui->setupUi(this);
+ reloadTextValue();
+ #ifdef ULTRACOPIER_DEBUG
+ connect(debug_engine_instance,SIGNAL(newDebugInformation()),this,SLOT(addDebugText()));
+ connect(ui->pushButtonSaveBugReport,SIGNAL(clicked()),debug_engine_instance,SLOT(saveBugReport()));
+ #else // ULTRACOPIER_DEBUG
+ ui->lineEditInsertDebug->hide();
+ ui->debugView->hide();
+ ui->pushButtonSaveBugReport->hide();
+ ui->pushButtonCrash->hide();
+ this->setMaximumSize(QSize(500,128));
+ /*timeToSetText.setInterval(250);
+ timeToSetText.setSingleShot(true);
+ connect(&timeToSetText,SIGNAL(timeout()),this,SLOT(showDebugText()));*/
+ ui->pushButtonClose->hide();
+ #endif // ULTRACOPIER_DEBUG
+ //connect the about Qt
+ connect(ui->pushButtonAboutQt,SIGNAL(toggled(bool)),qApp,SLOT(aboutQt()));
+}
+
+/// \brief Destruct the object
+HelpDialog::~HelpDialog()
+{
+ delete ui;
+}
+
+/// \brief To re-translate the ui
+void HelpDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ ui->retranslateUi(this);
+ reloadTextValue();
+ break;
+ default:
+ break;
+ }
+}
+
+/// \brief To reload the text value
+void HelpDialog::reloadTextValue()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QString text=ui->label_ultracopier->text();
+ text=text.replace("%1",ULTRACOPIER_VERSION);
+ ui->label_ultracopier->setText(text);
+
+ text=ui->label_description->text();
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ #ifdef ULTRACOPIER_VERSION_PORTABLEAPPS
+ text=text.replace("%1",tr("For http://portableapps.com/"));
+ #else
+ text=text.replace("%1",tr("Portable version"));
+ #endif
+ #else
+ text=text.replace("%1",tr("Normal version"));
+ #endif
+ ui->label_description->setText(text);
+
+ text=ui->label_site->text();
+ text=text.replace("%1",tr("http://ultracopier.first-world.info/"));
+ ui->label_site->setText(text);
+
+ text=ui->label_platform->text();
+ text=text.replace("%1",ULTRACOPIER_PLATFORM_NAME);
+ ui->label_platform->setText(text);
+}
+
+#ifdef ULTRACOPIER_DEBUG
+/// \brief Add debug text
+void HelpDialog::addDebugText()
+{
+ QList<DebugEngine::ItemOfDebug> returnedList=debug_engine_instance->getItemList();
+ QTreeWidgetItem * item;
+ QBrush brush;
+ QFont functionFont;
+ functionFont.setItalic(true);
+ functionFont.setUnderline(true);
+ QFont timeFont;
+ timeFont.setBold(true);
+ QFont noteFont;
+ noteFont.setBold(true);
+ noteFont.setPointSize(15);
+ int index=0;
+ int loop_size=returnedList.size();
+ while(index<loop_size)
+ {
+ item=new QTreeWidgetItem(ui->debugView,QStringList()
+ << returnedList.at(index).time
+ << returnedList.at(index).file
+ << returnedList.at(index).function
+ << returnedList.at(index).location
+ << returnedList.at(index).text);
+ switch(returnedList.at(index).level)
+ {
+ case DebugLevel_custom_Information:
+ brush=QBrush(QColor(94,165,255));
+ break;
+ case DebugLevel_custom_Critical:
+ brush=QBrush(QColor(255,0,0));
+ break;
+ case DebugLevel_custom_Warning:
+ brush=QBrush(QColor(255,178,0));
+ break;
+ case DebugLevel_custom_Notice:
+ brush=QBrush(QColor(128,128,128));
+ break;
+ case DebugLevel_custom_UserNote:
+ brush=QBrush(QColor(0,0,0));
+ break;
+ }
+ item->setForeground(0,brush);
+ item->setFont(0,timeFont);
+ item->setForeground(1,brush);
+ item->setForeground(2,brush);
+ item->setFont(2,functionFont);
+ item->setForeground(3,brush);
+ item->setForeground(4,brush);
+ if(returnedList.at(index).level==DebugLevel_custom_UserNote)
+ {
+ item->setFont(0,noteFont);
+ item->setFont(1,noteFont);
+ item->setFont(2,noteFont);
+ item->setFont(3,noteFont);
+ item->setFont(4,noteFont);
+ }
+ ui->debugView->insertTopLevelItem(ui->debugView->columnCount(),item);
+ index++;
+ }
+ if(loop_size==ULTRACOPIER_DEBUG_MAX_GUI_LINE)
+ {
+ item=new QTreeWidgetItem(ui->debugView,QStringList() << "...");
+ ui->debugView->insertTopLevelItem(ui->debugView->columnCount(),item);
+ }
+}
+
+void HelpDialog::on_lineEditInsertDebug_returnPressed()
+{
+ DebugEngine::addDebugNote(ui->lineEditInsertDebug->text());
+ ui->lineEditInsertDebug->clear();
+ ui->debugView->scrollToBottom();
+}
+
+#endif // ULTRACOPIER_DEBUG
+
+void HelpDialog::on_pushButtonAboutQt_clicked()
+{
+ QApplication::aboutQt();
+}
+
+void HelpDialog::on_pushButtonCrash_clicked()
+{
+ int a=0;
+ int *b=NULL;
+ *b=3/a;
+}
diff --git a/HelpDialog.h b/HelpDialog.h
new file mode 100644
index 0000000..43cbc7f
--- /dev/null
+++ b/HelpDialog.h
@@ -0,0 +1,50 @@
+/** \file HelpDialog.h
+\brief Define the help dialog
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef DIALOG_H
+#define DIALOG_H
+
+#include <QDialog>
+#include <QString>
+#include <QTimer>
+#include <QColor>
+#include <QBrush>
+
+#include "ui_HelpDialog.h"
+#include "Environment.h"
+#include "GlobalClass.h"
+
+namespace Ui {
+ class HelpDialog;
+}
+
+/** \brief Help dialog, and some user oriented repport/debug function */
+class HelpDialog : public QDialog, public GlobalClass {
+ Q_OBJECT
+ public:
+ /// \brief Construct the object
+ HelpDialog();
+ /// \brief Destruct the object
+ ~HelpDialog();
+ protected:
+ /// \brief To re-translate the ui
+ void changeEvent(QEvent *e);
+ private:
+ Ui::HelpDialog *ui;
+ /// \brief To reload the text value
+ void reloadTextValue();
+ private slots:
+ #ifdef ULTRACOPIER_DEBUG
+ /// \brief Add debug text
+ void addDebugText();
+ void on_lineEditInsertDebug_returnPressed();
+ #endif // ULTRACOPIER_DEBUG
+ void on_pushButtonAboutQt_clicked();
+ void on_pushButtonCrash_clicked();
+};
+
+#endif // DIALOG_H
diff --git a/HelpDialog.ui b/HelpDialog.ui
new file mode 100644
index 0000000..0707ab0
--- /dev/null
+++ b/HelpDialog.ui
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HelpDialog</class>
+ <widget class="QDialog" name="HelpDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>681</width>
+ <height>389</height>
+ </rect>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777214</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>About ultracopier</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="resources/resources.qrc">
+ <normaloff>:/ultracopier-16x16.png</normaloff>:/ultracopier-16x16.png</iconset>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="minimumSize">
+ <size>
+ <width>128</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>128</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="resources/resources.qrc">:/ultracopier-128x128.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_ultracopier">
+ <property name="font">
+ <font>
+ <pointsize>12</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Ultracopier %1</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_description">
+ <property name="text">
+ <string>Based on Qt. It provide advanced copier with more advanced feature. It's under GPL3.
+This version is compiled as version: %1.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_site">
+ <property name="text">
+ <string>For more informations see the website &lt;a href=&quot;%1&quot; rel=&quot;%1&quot; title=&quot;%1&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0057ae;&quot;&gt;%1&lt;/span&gt;&lt;/a&gt;</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_platform">
+ <property name="text">
+ <string>Platform: %1</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditInsertDebug">
+ <property name="toolTip">
+ <string notr="true">Insert debug note to annotate some special action at current time</string>
+ </property>
+ <property name="statusTip">
+ <string notr="true">Insert debug note to annotate some special action at current time</string>
+ </property>
+ <property name="placeholderText">
+ <string notr="true">Insert debug note to annotate some special action at current time</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="debugView">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string notr="true">Time</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">File</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">Function</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">Location</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">Text</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutButton">
+ <item>
+ <widget class="QPushButton" name="pushButtonAboutQt">
+ <property name="text">
+ <string>About Qt</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonCrash">
+ <property name="text">
+ <string>Do a crash</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonSaveBugReport">
+ <property name="text">
+ <string>Save bug report</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonClose">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>debugView</tabstop>
+ <tabstop>lineEditInsertDebug</tabstop>
+ <tabstop>pushButtonAboutQt</tabstop>
+ <tabstop>pushButtonSaveBugReport</tabstop>
+ <tabstop>pushButtonClose</tabstop>
+ </tabstops>
+ <resources>
+ <include location="resources/resources.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>pushButtonClose</sender>
+ <signal>clicked()</signal>
+ <receiver>HelpDialog</receiver>
+ <slot>hide()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>387</x>
+ <y>216</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>329</x>
+ <y>212</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/LanguagesManager.cpp b/LanguagesManager.cpp
new file mode 100755
index 0000000..a5be40d
--- /dev/null
+++ b/LanguagesManager.cpp
@@ -0,0 +1,284 @@
+/** \file LanguagesManager.cpp
+\brief Define the class to manage and load the languages
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDir>
+#include <QLibraryInfo>
+
+#include "LanguagesManager.h"
+
+/// \brief Create the manager and load the defaults variables
+LanguagesManager::LanguagesManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the overall instance
+ resources=ResourcesManager::getInstance();
+ options=OptionEngine::getInstance();
+ plugins=PluginsManager::getInstance();
+ //load the rest
+ QStringList resourcesPaths=resources->getReadPath();
+ int index=0;
+ while(index<resourcesPaths.size())
+ {
+ QString composedTempPath=resourcesPaths.at(index)+"Languages"+QDir::separator();
+ QDir LanguagesConfiguration(composedTempPath);
+ if(LanguagesConfiguration.exists())
+ languagePath<<composedTempPath;
+ index++;
+ }
+ //load the plugins
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_Languages);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ qRegisterMetaType<PluginsAvailable>("PluginsAvailable");
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this, SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this, SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins,SIGNAL(pluginListingIsfinish()), this, SLOT(allPluginIsLoaded()));
+ plugins->unlockPluginListEdition();
+ //load the GUI option
+ QList<QPair<QString, QVariant> > KeysList;
+ KeysList.append(qMakePair(QString("Language"),QVariant("en")));
+ KeysList.append(qMakePair(QString("Language_autodetect"),QVariant(true)));
+ options->addOptionGroup("Language",KeysList);
+// connect(this, SIGNAL(newLanguageLoaded(QString)), plugins,SLOT(refreshPluginList(QString)));
+// connect(this, SIGNAL(newLanguageLoaded(QString)), this,SLOT(retranslateTheUI()));
+ connect(options,SIGNAL(newOptionValue(QString,QString,QVariant)), this, SLOT(newOptionValue(QString)));
+ connect(this, SIGNAL(newLanguageLoaded(QString)), plugins,SIGNAL(newLanguageLoaded()));
+}
+
+/// \brief Destroy the language manager
+LanguagesManager::~LanguagesManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ PluginsManager::destroyInstanceAtTheLastCall();
+ OptionEngine::destroyInstanceAtTheLastCall();
+ ResourcesManager::destroyInstanceAtTheLastCall();
+}
+
+/// \brief load the language selected, return the main short code like en, fr, ..
+QString LanguagesManager::getTheRightLanguage()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ if(LanguagesAvailableList.size()==0)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"empty combobox list, failing back to english");
+ return "en";
+ }
+ else
+ {
+ if(options->getOptionValue("Language","Language_autodetect").toBool())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"language auto-detection, QLocale::system().name(): "+QLocale::system().name()+", QLocale::languageToString(QLocale::system().language()): "+QLocale::languageToString(QLocale::system().language()));
+ QString tempLanguage=getMainShortName(QLocale::languageToString(QLocale::system().language()));
+ if(tempLanguage!="")
+ return tempLanguage;
+ else
+ {
+ tempLanguage=getMainShortName(QLocale::system().name());
+ if(tempLanguage!="")
+ return tempLanguage;
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Autodetection of the language failed, QLocale::languageToString(QLocale::system().language()): "+QLocale::languageToString(QLocale::system().language())+", QLocale::system().name(): "+QLocale::system().name()+", failing back to english");
+ return options->getOptionValue("Language","Language").toString();
+ }
+ }
+ }
+ else
+ return options->getOptionValue("Language","Language").toString();
+ }
+}
+
+/* \brief To set the current language
+\param newLanguage Should be short name code found into informations.xml of language file */
+void LanguagesManager::setCurrentLanguage(const QString &newLanguage)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+newLanguage);
+ //protection for re-set the same language
+ if(currentLanguage==newLanguage)
+ return;
+ //store the language
+ plugins->setLanguage(newLanguage);
+ //unload the old language
+ if(currentLanguage!="en")
+ {
+ int indexTranslator=0;
+ while(indexTranslator<installedTranslator.size())
+ {
+ QCoreApplication::removeTranslator(installedTranslator[indexTranslator]);
+ delete installedTranslator[indexTranslator];
+ indexTranslator++;
+ }
+ installedTranslator.clear();
+ }
+ if(newLanguage=="en")
+ {
+ currentLanguage="en";
+ emit newLanguageLoaded(currentLanguage);
+ }
+ else
+ {
+ int index=0;
+ while(index<LanguagesAvailableList.size())
+ {
+ if(LanguagesAvailableList.at(index).mainShortName==newLanguage)
+ {
+ //load the new language
+ if(newLanguage!="en")
+ {
+ QTranslator *temp;
+ QStringList fileToLoad;
+ //load the language main
+ fileToLoad<<LanguagesAvailableList.at(index).path+"translation.qm";
+ //load the language plugin
+ QList<PluginsAvailable> listLoadedPlugins=plugins->getPlugins();
+ int indexPluginIndex=0;
+ while(indexPluginIndex<listLoadedPlugins.size())
+ {
+ if(listLoadedPlugins.at(indexPluginIndex).category!=PluginType_Languages)
+ {
+ QString tempPath=listLoadedPlugins.at(indexPluginIndex).path+"Languages"+QDir::separator()+LanguagesAvailableList.at(index).mainShortName+QDir::separator()+"translation.qm";
+ if(QFile::exists(tempPath))
+ fileToLoad<<tempPath;
+ }
+ indexPluginIndex++;
+ }
+ int indexTranslationFile=0;
+ while(indexTranslationFile<fileToLoad.size())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Translation to load: "+fileToLoad.at(indexTranslationFile));
+ temp=new QTranslator();
+ if(!temp->load(fileToLoad.at(indexTranslationFile)) || temp->isEmpty())
+ {
+ delete temp;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to load the translation file: "+fileToLoad.at(indexTranslationFile));
+ }
+ else
+ {
+ QCoreApplication::installTranslator(temp);
+ installedTranslator<<temp;
+ }
+ indexTranslationFile++;
+ }
+ temp=new QTranslator();
+ if(temp->load(QString("qt_")+newLanguage, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) && !temp->isEmpty())
+ {
+ QCoreApplication::installTranslator(temp);
+ installedTranslator<<temp;
+ }
+ else
+ {
+ if(!temp->load(LanguagesAvailableList.at(index).path+"qt.qm") || temp->isEmpty())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Unable to load the translation file: qt.qm, into: "+LanguagesAvailableList.at(index).path);
+ delete temp;
+ }
+ else
+ {
+ QCoreApplication::installTranslator(temp);
+ installedTranslator<<temp;
+ }
+ }
+ }
+ currentLanguage=newLanguage;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"emit newLanguageLoaded()");
+ emit newLanguageLoaded(currentLanguage);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to found language: "+newLanguage+", LanguagesAvailableList.size(): "+QString::number(LanguagesAvailableList.size()));
+ }
+}
+
+/// \brief check if short name is found into language
+QString LanguagesManager::getMainShortName(const QString &shortName)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<LanguagesAvailableList.size())
+ {
+ if(LanguagesAvailableList.at(index).shortName.contains(shortName) || LanguagesAvailableList.at(index).fullName.contains(shortName))
+ return LanguagesAvailableList.at(index).mainShortName;
+ index++;
+ }
+ return "";
+}
+
+/// \brief load the language in languagePath
+void LanguagesManager::allPluginIsLoaded()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ setCurrentLanguage(getTheRightLanguage());
+}
+
+/*QString LanguagesManager::getMainShortName()
+{
+ return currentLanguage;
+}*/
+
+void LanguagesManager::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_Languages)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QDomElement child = plugin.categorySpecific.firstChildElement("fullName");
+ LanguagesAvailable temp;
+ if(!child.isNull() && child.isElement())
+ temp.fullName=child.text();
+ child = plugin.categorySpecific.firstChildElement("shortName");
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ {
+ if(child.hasAttribute("mainCode") && child.attribute("mainCode")=="true")
+ temp.mainShortName=child.text();
+ temp.shortName<<child.text();
+ }
+ child = child.nextSiblingElement("shortName");
+ }
+ temp.path=plugin.path;
+ if(temp.fullName.isEmpty())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"fullName empty for: "+plugin.path);
+ else if(temp.path.isEmpty())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"path empty for: "+plugin.path);
+ else if(temp.mainShortName.isEmpty())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"mainShortName empty for: "+plugin.path);
+ else if(temp.shortName.size()<=0)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"temp.shortName.size()<=0 for: "+plugin.path);
+ else if(!QFile::exists(temp.path+"flag.png"))
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"flag file not found for: "+plugin.path);
+ else if(!QFile::exists(temp.path+"translation.qm") && temp.mainShortName!="en")
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"translation not found for: "+plugin.path);
+ else
+ LanguagesAvailableList<<temp;
+ if(plugins->allPluginHaveBeenLoaded())
+ setCurrentLanguage(getTheRightLanguage());
+}
+
+void LanguagesManager::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<LanguagesAvailableList.size())
+ {
+ if(plugin.path==LanguagesAvailableList.at(index).path)
+ {
+ return;
+ }
+ index++;
+ }
+}
+
+void LanguagesManager::newOptionValue(const QString &group)
+{
+ if(group=="Language")
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"group: "+group);
+ setCurrentLanguage(getTheRightLanguage());
+ }
+}
diff --git a/LanguagesManager.h b/LanguagesManager.h
new file mode 100644
index 0000000..6d59284
--- /dev/null
+++ b/LanguagesManager.h
@@ -0,0 +1,81 @@
+/** \file LanguagesManager.h
+\brief Define the class to manage and load the languages
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef LANGUAGES_MANAGER_H
+#define LANGUAGES_MANAGER_H
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QLocale>
+#include <QTranslator>
+#include <QByteArray>
+#include <QCoreApplication>
+#include <QDir>
+
+#include "Environment.h"
+#include "Singleton.h"
+#include "OptionEngine.h"
+#include "ResourcesManager.h"
+#include "PluginsManager.h"
+
+/** \brief Define the class to manage and load the resources linked with the themes
+
+This class provide a core load and manage the resources */
+class LanguagesManager : public QObject, public Singleton<LanguagesManager>
+{
+ Q_OBJECT
+ friend class Singleton<LanguagesManager>;
+ //public:
+ // QString getMainShortName();
+ private:
+ /// \brief Create the manager and load the defaults variables
+ LanguagesManager();
+ /// \brief Destroy the language manager
+ ~LanguagesManager();
+ //for the options
+ OptionEngine *options;
+ /** \brief To set the current language
+ \param newLanguage Should be short name code found into informations.xml of language file */
+ void setCurrentLanguage(const QString &newLanguage);
+ /// \brief Structure of language
+ struct LanguagesAvailable
+ {
+ QString path;
+ QString fullName;
+ QString mainShortName;
+ QStringList shortName;
+ };
+ /// \brief To store the language path
+ QStringList languagePath;
+ /// \brief To store the language detected
+ QList<LanguagesAvailable> LanguagesAvailableList;
+ /// \brief check if short name is found into language
+ QString getMainShortName(const QString &shortName);
+ /// \brief Store the object of resources manager
+ ResourcesManager *resources;
+ /// \brief Store the object of plugin manager
+ PluginsManager *plugins;
+ /// \brief list of installed translator
+ QList<QTranslator *> installedTranslator;
+ QString currentLanguage;
+ /// \brief load the language selected
+ QString getTheRightLanguage();
+ private slots:
+ /// \brief load the language in languagePath
+ void allPluginIsLoaded();
+ //plugin management
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ void newOptionValue(const QString &group);
+ signals:
+ //send the language is loaded or the new language is loaded
+ void newLanguageLoaded(const QString &mainShortName);
+};
+
+#endif // LANGUAGES_MANAGER_H
diff --git a/LocalListener.cpp b/LocalListener.cpp
new file mode 100644
index 0000000..d76b505
--- /dev/null
+++ b/LocalListener.cpp
@@ -0,0 +1,265 @@
+/** \file LocalListener.cpp
+\brief The have local server, to have unique instance, and send arguments to the current running instance
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "LocalListener.h"
+
+LocalListener::LocalListener(QObject *parent) :
+ QObject(parent)
+{
+ //for detect the timeout on QLocalSocket
+ TimeOutQLocalSocket.setInterval(500);
+ TimeOutQLocalSocket.setSingleShot(true);
+ connect(&TimeOutQLocalSocket, SIGNAL(timeout()), this, SLOT(timeoutDectected()));
+}
+
+LocalListener::~LocalListener()
+{
+ if(localServer.isListening())
+ {
+ localServer.close();
+ if(!QLocalServer::removeServer(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME)))
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Unable to remove the listening server"));
+ }
+}
+
+bool LocalListener::tryConnect()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QStringList ultracopierArguments=QCoreApplication::arguments();
+ //remove excutable path because is useless (unsafe to use)
+ ultracopierArguments.removeFirst();
+ //add the current path to file full path resolution if needed
+ ultracopierArguments.insert(0,QFSFileEngine::currentPath());
+ QLocalSocket localSocket;
+ localSocket.connectToServer(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME),QIODevice::WriteOnly);
+ if(localSocket.waitForConnected(1000))
+ {
+ if(!localSocket.isValid())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"localSocket is not valid!");
+ return false;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"connection succes, number arguments given: "+QString::number(ultracopierArguments.size()));
+ #ifdef ULTRACOPIER_DEBUG
+ for (int i = 0; i < ultracopierArguments.size(); ++i) {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"argument["+QString::number(i)+"]: "+ultracopierArguments.at(i));
+ }
+ #endif // ULTRACOPIER_DEBUG
+ //cut string list and send it as block of 32KB
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ //for total size
+ out << int(0);
+ //send the arguments
+ out << ultracopierArguments;
+ //write the size content
+ out.device()->seek(0);
+ out << block.size();
+ do
+ {
+ QByteArray blockToSend;
+ int byteWriten;
+ blockToSend=block.left(32*1024);//32KB
+ block.remove(0,blockToSend.size());
+ byteWriten = localSocket.write(blockToSend);
+ #ifdef ULTRACOPIER_DEBUG
+ if(!localSocket.isValid())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"localSocket is not valid!");
+ if(localSocket.errorString()!="Unknown error" && localSocket.errorString()!="")
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"localSocket->errorString(): "+localSocket.errorString());
+ if(blockToSend.size()!=byteWriten)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"blockToSend("+QString::number(blockToSend.size())+")!=byteWriten("+QString::number(byteWriten)+")");
+ #endif // ULTRACOPIER_DEBUG
+ if(localSocket.waitForBytesWritten(200))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Block send correctly");
+ }
+ else
+ {
+ QMessageBox::critical(NULL,"Alert","No arguments send because timeout detected!");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Block not send correctly");
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"blockToSend: "+QString(blockToSend.toHex()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"byteWriten: "+QString::number(byteWriten)+", size sending: "+QString::number(blockToSend.size()));
+ }
+ while(block.size());
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"disconnect the socket");
+ localSocket.disconnectFromServer();
+ return true;
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"connection failed, continu...");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"ultracopierArguments: "+ultracopierArguments.join(";"));
+ emit cli(ultracopierArguments,false);
+ return false;
+ }
+}
+
+/// the listen server
+void LocalListener::listenServer()
+{
+ if(!QLocalServer::removeServer(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME)))
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Unable to remove the listening server"));
+ if(!localServer.listen(ExtraSocket::pathSocket(ULTRACOPIER_SOCKETNAME)))
+ {
+ QMessageBox::critical(NULL,"Alert",QString("Ultracopier have not able to lock unique instance: %1").arg(localServer.errorString()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Ultracopier have not able to lock unique instance: %1").arg(localServer.errorString()));
+ }
+ else
+ connect(&localServer, SIGNAL(newConnection()), this, SLOT(newConnexion()));
+}
+
+//the time is done
+void LocalListener::timeoutDectected()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"start");
+ while(clientList.size()>0)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"clientList.first().size: "+QString::number(clientList.first().size));
+ clientList.removeFirst();
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Timeout while recomposing data from connected clients");
+ QMessageBox::warning(NULL,tr("Warning"),tr("Timeout while recomposing data from connected clients"));
+}
+
+/// \brief Data is incomming
+void LocalListener::dataIncomming()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"start");
+ // 1 : we get packets from client
+
+ //Which client send the message (Search of the QLocalSocket of client)
+ QLocalSocket *socket = qobject_cast<QLocalSocket *>(sender());
+ if (socket == 0) // If not found
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"bad socket");
+ return;
+ }
+
+ int index=-1;
+ for (int i=0;i<clientList.size(); ++i) {
+ if(clientList.at(i).socket==socket)
+ index=i;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"socket->bytesAvailable() "+QString::number(socket->bytesAvailable()));
+ if(index!=-1)
+ {
+ if(!clientList.at(index).haveData)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"tempComposed index found, but no have data, create new entry");
+ // If all is ok we get the message
+ QDataStream in(socket);
+ in.setVersion(QDataStream::Qt_4_4);
+
+ if (socket->bytesAvailable() < (int)sizeof(quint32)*2) // We have not receveive all the message, ignore because first int is cuted!
+ {
+ /*socket->readAll();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"wrong size for set the message size");*/
+ return;
+ }
+ in >> clientList[index].size; // Store the size of the message
+ clientList[index].size-=sizeof(int);
+
+ // Check if all the message size is the same as the size given
+ if(socket->bytesAvailable() < clientList.at(index).size) // If not all get then stop it
+ {
+ clientList[index].haveData=true;
+ clientList[index].data.append(socket->readAll());
+ TimeOutQLocalSocket.start();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Need wait to recomposite: "+QString::number(clientList.at(index).data.size())+", targeted: "+QString::number(clientList.at(index).size));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"tempComposed.data: "+QString(clientList.at(index).data.toHex()));
+ }
+ else if(socket->bytesAvailable() == clientList.at(index).size) //if the size match
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"socket->bytesAvailable(): "+QString::number(socket->bytesAvailable())+", for total of: "+QString::number(socket->bytesAvailable()+sizeof(quint32)));
+ QStringList ultracopierArguments;
+ in >> ultracopierArguments;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"ultracopierArguments: "+ultracopierArguments.join(";"));
+ emit cli(ultracopierArguments,true);
+ clientList[index].data.clear();
+ clientList[index].haveData=false;
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"socket->bytesAvailable(): "+QString::number(socket->bytesAvailable())+" > clientList.at(index).size!: "+QString::number(clientList.at(index).size));
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Query recomposed with this size: "+QString::number(clientList.at(index).data.size()));
+ clientList[index].data.append(socket->readAll());
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Query recomposed with this size: "+QString::number(clientList.at(index).data.size()));
+ if(clientList.at(index).data.size()==clientList.at(index).size)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"QByteArray reconstruction finished");
+ QDataStream in(clientList.at(index).data);
+ QStringList ultracopierArguments;
+ in >> ultracopierArguments;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"ultracopierArguments: "+ultracopierArguments.join(";"));
+ emit cli(ultracopierArguments,true);
+ clientList[index].data.clear();
+ clientList[index].haveData=false;
+ }
+ else
+ {
+ TimeOutQLocalSocket.start();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Need wait to recomposite: "+QString::number(clientList.at(index).data.size())+", targeted: "+QString::number(clientList.at(index).size));
+ return;
+ }
+ }
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Socket not found???");
+}
+
+/// \brief Deconnexion client
+/// \todo Remove the data in wait linker with this socket
+void LocalListener::deconnectClient()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+
+ // Wich client leave
+ QLocalSocket *socket = qobject_cast<QLocalSocket *>(sender());
+ if (socket == 0) // If not found
+ return;
+ for (int i = 0; i < clientList.size(); ++i) {
+ if(clientList.at(i).socket==socket)
+ clientList.removeAt(i);
+ }
+ socket->deleteLater();
+}
+
+/// LocalListener New connexion
+void LocalListener::newConnexion()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"start");
+ composedData newClient;
+ newClient.socket = localServer.nextPendingConnection();
+ #ifdef ULTRACOPIER_DEBUG
+ connect(newClient.socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(error(QLocalSocket::LocalSocketError)));
+ #endif
+ connect(newClient.socket, SIGNAL(readyRead()), this, SLOT(dataIncomming()));
+ connect(newClient.socket, SIGNAL(disconnected()), this, SLOT(deconnectClient()));
+ newClient.size=-1;
+ newClient.haveData=false;
+ clientList << newClient;
+}
+
+#ifdef ULTRACOPIER_DEBUG
+/** \brief If error occured at socket
+\param theErrorDefine The error define */
+void LocalListener::error(QLocalSocket::LocalSocketError theErrorDefine)
+{
+ if(theErrorDefine!=QLocalSocket::PeerClosedError)
+ {
+ QLocalSocket *client=qobject_cast<QLocalSocket *>(QObject::sender());
+ if(client!=NULL)
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Value:"+QString::number(theErrorDefine)+", Error message: "+client->errorString());
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Value:"+QString::number(theErrorDefine));
+ }
+}
+#endif
diff --git a/LocalListener.h b/LocalListener.h
new file mode 100644
index 0000000..50905a9
--- /dev/null
+++ b/LocalListener.h
@@ -0,0 +1,65 @@
+/** \file LocalListener.h
+\brief The have local server, to have unique instance, and send arguments to the current running instance
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef LOCALLISTENER_H
+#define LOCALLISTENER_H
+
+#include <QObject>
+#include <QLocalServer>
+#include <QLocalSocket>
+#include <QStringList>
+#include <QString>
+#include <QCoreApplication>
+#include <QFSFileEngine>
+#include <QMessageBox>
+#include <QTimer>
+#include <QList>
+
+#include "Environment.h"
+#include "ExtraSocket.h"
+
+/** \brief To have unique instance, and pass arguments to the existing instance if needed */
+class LocalListener : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LocalListener(QObject *parent = 0);
+ ~LocalListener();
+public slots:
+ /// try connect to existing server
+ bool tryConnect();
+ /// the listen server
+ void listenServer();
+private:
+ QLocalServer localServer;
+ QTimer TimeOutQLocalSocket;
+ typedef struct {
+ QLocalSocket * socket;
+ QByteArray data;
+ int size;
+ bool haveData;
+ } composedData;
+ QList<composedData> clientList;
+private slots:
+ //the time is done
+ void timeoutDectected();
+ /// \brief Data is incomming
+ void dataIncomming();
+ /// \brief Deconnexion client
+ void deconnectClient();
+ /// LocalListener New connexion
+ void newConnexion();
+ #ifdef ULTRACOPIER_DEBUG
+ /** \brief If error occured at socket
+ \param theErrorDefine The error define */
+ void error(QLocalSocket::LocalSocketError theErrorDefine);
+ #endif
+signals:
+ void cli(const QStringList &ultracopierArguments,const bool &external);
+};
+
+#endif // LOCALLISTENER_H
diff --git a/LocalPluginOptions.cpp b/LocalPluginOptions.cpp
new file mode 100644
index 0000000..b81e880
--- /dev/null
+++ b/LocalPluginOptions.cpp
@@ -0,0 +1,63 @@
+/** \file LocalPluginOptions.cpp
+\brief To bind the options of the plugin, into unique group options
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "LocalPluginOptions.h"
+
+LocalPluginOptions::LocalPluginOptions(const QString &group)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start(\""+group+"\",[...])");
+ groupOptionAdded=false;
+ this->group=group;
+ options=OptionEngine::getInstance();
+ connect(options,SIGNAL(resetOptions()),this,SIGNAL(resetOptions()));
+}
+
+LocalPluginOptions::~LocalPluginOptions()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start(\""+group+"\",[...])");
+ if(groupOptionAdded)
+ options->removeOptionGroup(group);
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"option not used");
+ OptionEngine::destroyInstanceAtTheLastCall();
+}
+
+/// \brief To add option group to options
+bool LocalPluginOptions::addOptionGroup(const QList<QPair<QString, QVariant> > &KeysList)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start(\""+group+"\",[...])");
+ if(groupOptionAdded)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Group already added!");
+ return false;
+ }
+ else
+ {
+ groupOptionAdded=true;
+ return options->addOptionGroup(group,KeysList);
+ }
+}
+
+/// \brief To get option value
+QVariant LocalPluginOptions::getOptionValue(const QString &variableName)
+{
+ return options->getOptionValue(group,variableName);
+}
+
+/// \brief To set option value
+void LocalPluginOptions::setOptionValue(const QString &variableName,const QVariant &value)
+{
+ options->setOptionValue(group,variableName,value);
+}
+
+/*-> disabled because the value will not externaly changed, then useless notification
+void LocalPluginOptions::newOptionValue(QString group,QString variable,QVariant value)
+{
+ if(group==this->group)
+ emit newOptionValue(variable,value);
+}*/
+
diff --git a/LocalPluginOptions.h b/LocalPluginOptions.h
new file mode 100644
index 0000000..f5ee463
--- /dev/null
+++ b/LocalPluginOptions.h
@@ -0,0 +1,45 @@
+/** \file LocalPluginOptions.h
+\brief To bind the options of the plugin, into unique group options
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef LOCALPLUGINOPTIONS_H
+#define LOCALPLUGINOPTIONS_H
+
+#include <QObject>
+
+#include "interface/OptionInterface.h"
+#include "OptionEngine.h"
+
+/** \brief To store the options
+
+ That's allow to have mutualised way to store the options. Then the plugins just keep Ultracopier manage it, the portable version will store on the disk near the application, and the normal version will keep at the normal location.
+
+ \see OptionEngine::OptionEngine()
+*/
+class LocalPluginOptions : public OptionInterface
+{
+ Q_OBJECT
+public:
+ explicit LocalPluginOptions(const QString &group);
+ ~LocalPluginOptions();
+ /// \brief To add option group to options
+ bool addOptionGroup(const QList<QPair<QString, QVariant> > &KeysList);
+ /*/// \brief To remove option group to options, removed to the load plugin
+ bool removeOptionGroup();*/
+ /// \brief To get option value
+ QVariant getOptionValue(const QString &variableName);
+ /// \brief To set option value
+ void setOptionValue(const QString &variableName,const QVariant &value);
+protected:
+ //for the options
+ OptionEngine *options;
+ QString group;
+ bool groupOptionAdded;
+/*public slots:-> disabled because the value will not externaly changed, then useless notification
+ void newOptionValue(QString group,QString variable,QVariant value);*/
+};
+
+#endif // LOCALPLUGINOPTIONS_H
diff --git a/LogThread.cpp b/LogThread.cpp
new file mode 100644
index 0000000..0255905
--- /dev/null
+++ b/LogThread.cpp
@@ -0,0 +1,222 @@
+/** \file LogThread.cpp
+\brief The thread to do the log but not block the main thread
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "LogThread.h"
+
+#include <QMessageBox>
+
+LogThread::LogThread()
+{
+ sync=false;
+
+ //load the GUI option
+ QString defaultLogFile="";
+ if(resources->getWritablePath()!="")
+ defaultLogFile=resources->getWritablePath()+"ultracopier-files.log";
+ QList<QPair<QString, QVariant> > KeysList;
+ KeysList.append(qMakePair(QString("enabled"),QVariant(false)));
+ KeysList.append(qMakePair(QString("file"),QVariant(defaultLogFile)));
+ KeysList.append(qMakePair(QString("transfer"),QVariant(true)));
+ KeysList.append(qMakePair(QString("error"),QVariant(true)));
+ KeysList.append(qMakePair(QString("folder"),QVariant(true)));
+ KeysList.append(qMakePair(QString("sync"),QVariant(true)));
+ KeysList.append(qMakePair(QString("transfer_format"),QVariant("[%time%] %source% (%size%) %destination%")));
+ KeysList.append(qMakePair(QString("error_format"),QVariant("[%time%] %path%, %error%")));
+ KeysList.append(qMakePair(QString("folder_format"),QVariant("[%time%] %operation% %path%")));
+ options->addOptionGroup("Write_log",KeysList);
+
+ connect(options,SIGNAL(newOptionValue(QString,QString,QVariant)), this, SLOT(newOptionValue(QString,QString,QVariant)));
+
+ enabled=false;
+
+ moveToThread(this);
+ start(QThread::IdlePriority);
+
+ connect(this, SIGNAL(newData(QString)), this,SLOT(realDataWrite(QString)),Qt::QueuedConnection);
+
+ newOptionValue("Write_log", "transfer", options->getOptionValue("Write_log","transfer"));
+ newOptionValue("Write_log", "error", options->getOptionValue("Write_log","error"));
+ newOptionValue("Write_log", "folder", options->getOptionValue("Write_log","folder"));
+ newOptionValue("Write_log", "sync", options->getOptionValue("Write_log","sync"));
+ newOptionValue("Write_log", "transfer_format", options->getOptionValue("Write_log","transfer_format"));
+ newOptionValue("Write_log", "error_format", options->getOptionValue("Write_log","error_format"));
+ newOptionValue("Write_log", "folder_format", options->getOptionValue("Write_log","folder_format"));
+ newOptionValue("Write_log", "sync", options->getOptionValue("Write_log","sync"));
+ newOptionValue("Write_log", "enabled", options->getOptionValue("Write_log","enabled"));
+}
+
+LogThread::~LogThread()
+{
+ closeLogs();
+ quit();
+ wait();
+}
+
+void LogThread::openLogs()
+{
+ if(options->getOptionValue("Write_log","enabled").toBool()==false)
+ return;
+ if(log.isOpen())
+ {
+ QMessageBox::critical(NULL,tr("Error"),tr("log file already open, error: %1").arg(log.errorString()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("log file already open, error: %1").arg(log.errorString()));
+ return;
+ }
+ log.setFileName(options->getOptionValue("Write_log","file").toString());
+ if(sync)
+ {
+ if(!log.open(QIODevice::WriteOnly|QIODevice::Unbuffered))
+ {
+ QMessageBox::critical(NULL,tr("Error"),tr("Unable to open file to keep the log file, error: %1").arg(log.errorString()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Unable to open file to keep the log file, error: %1").arg(log.errorString()));
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"opened log: "+options->getOptionValue("Write_log","file").toString());
+ }
+ else
+ {
+ if(!log.open(QIODevice::WriteOnly))
+ {
+ QMessageBox::critical(NULL,tr("Error"),tr("Unable to open file to keep the log file, error: %1").arg(log.errorString()));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Unable to open file to keep the log file, error: %1").arg(log.errorString()));
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"opened log: "+options->getOptionValue("Write_log","file").toString());
+ }
+}
+
+void LogThread::closeLogs()
+{
+ if(log.isOpen() && data.size()>0)
+ log.write(data.toUtf8());
+ log.close();
+}
+
+void LogThread::newTransferStart(const ItemOfCopyList &item)
+{
+ if(!log_enable_transfer)
+ return;
+ QString text=transfer_format+"\n";
+ text=replaceBaseVar(text);
+ //Variable is %source%, %size%, %destination%
+ text=text.replace("%source%",item.sourceFullPath);
+ text=text.replace("%size%",QString::number(item.size));
+ text=text.replace("%destination%",item.destinationFullPath);
+ emit newData(text);
+}
+
+void LogThread::newTransferStop(const quint64 &id)
+{
+ if(!log_enable_transfer)
+ return;
+ Q_UNUSED(id)
+}
+
+void LogThread::error(const QString &path,const quint64 &size,const QDateTime &mtime,const QString &error)
+{
+ if(!log_enable_error)
+ return;
+ QString text=error_format+"\n";
+ text=replaceBaseVar(text);
+ //Variable is %path%, %size%, %mtime%, %error%
+ text=text.replace("%path%",path);
+ text=text.replace("%size%",QString::number(size));
+ text=text.replace("%mtime%",mtime.toString(Qt::ISODate));
+ text=text.replace("%error%",error);
+ emit newData(text);
+}
+
+void LogThread::run()
+{
+ exec();
+}
+
+void LogThread::realDataWrite(const QString &text)
+{
+ #ifdef ULTRACOPIER_DEBUG
+ if(!log.isOpen())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"transfer log not open");
+ return;
+ }
+ #endif // ULTRACOPIER_DEBUG
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ if(log.write(text.toUtf8())==-1)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to write into transfer log: %1").arg(log.errorString()));
+ return;
+ }
+ if(sync)
+ log.flush();
+}
+
+void LogThread::newOptionValue(const QString &group,const QString &name,const QVariant &value)
+{
+ if(group!="Write_log")
+ return;
+
+ if(name=="transfer_format")
+ transfer_format=value.toString();
+ else if(name=="error_format")
+ error_format=value.toString();
+ else if(name=="folder_format")
+ folder_format=value.toString();
+ else if(name=="sync")
+ {
+ sync=value.toBool();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("sync flag is set on: %1").arg(sync));
+ if(sync)
+ {
+ if(log.isOpen())
+ log.flush();
+ }
+ }
+ else if(name=="transfer")
+ log_enable_transfer=options->getOptionValue("Write_log","enabled").toBool() && value.toBool();
+ else if(name=="error")
+ log_enable_error=options->getOptionValue("Write_log","enabled").toBool() && value.toBool();
+ else if(name=="folder")
+ log_enable_folder=options->getOptionValue("Write_log","enabled").toBool() && value.toBool();
+ if(name=="enabled")
+ {
+ enabled=value.toBool();
+ if(enabled)
+ openLogs();
+ else
+ closeLogs();
+ }
+}
+
+QString LogThread::replaceBaseVar(QString text)
+{
+ text=text.replace("%time%",QDateTime::currentDateTime().toString("dd.MM.yyyy h:m:s"));
+ return text;
+}
+
+void LogThread::rmPath(const QString &path)
+{
+ if(!log_enable_folder)
+ return;
+ QString text=folder_format+"\n";
+ text=replaceBaseVar(text);
+ //Variable is %operation% %path%
+ text=text.replace("%path%",path);
+ text=text.replace("%operation%","rmPath");
+ emit newData(text);
+}
+
+void LogThread::mkPath(const QString &path)
+{
+ if(!log_enable_folder)
+ return;
+ QString text=folder_format+"\n";
+ text=replaceBaseVar(text);
+ //Variable is %operation% %path%
+ text=text.replace("%path%",path);
+ text=text.replace("%operation%","mkPath");
+ emit newData(text);
+}
diff --git a/LogThread.h b/LogThread.h
new file mode 100644
index 0000000..2366e3e
--- /dev/null
+++ b/LogThread.h
@@ -0,0 +1,68 @@
+/** \file LogThread.h
+\brief The thread to do the log but not block the main thread
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef LOGTHREAD_H
+#define LOGTHREAD_H
+
+#include <QThread>
+#include <QString>
+#include <QDateTime>
+#include <QVariant>
+
+#include "GlobalClass.h"
+#include "Environment.h"
+#include "StructEnumDefinition.h"
+
+/** \brief Log all the user oriented activity
+
+It use thread based storage to prevent gui thread freeze on log file writing when is out of the disk buffer. That's allow to async the event.
+*/
+class LogThread : public QThread, public GlobalClass
+{
+ Q_OBJECT
+public:
+ explicit LogThread();
+ ~LogThread();
+public slots:
+ /** method called when new transfer is started */
+ void newTransferStart(const ItemOfCopyList &item);
+ /** method called when transfer is stopped */
+ void newTransferStop(const quint64 &id);
+ /** method called when new error is occurred */
+ void error(const QString &path,const quint64 &size,const QDateTime &mtime,const QString &error);
+ /** method called when the log file need be created */
+ void openLogs();
+ /** method called when the log file need be closed */
+ void closeLogs();
+ /** method called when one folder is removed */
+ void rmPath(const QString &path);
+ /** method called when one folder is created */
+ void mkPath(const QString &path);
+private slots:
+ /** \to write the data into the file */
+ void realDataWrite(const QString &text);
+ /** \to update the options value */
+ void newOptionValue(const QString &group,const QString &name,const QVariant &value);
+signals:
+ void newData(const QString &text);
+private:
+ QString data;
+ QString transfer_format;
+ QString error_format;
+ QString folder_format;
+ QFile log;
+ QString replaceBaseVar(QString text);
+ bool sync;
+ bool enabled;
+ bool log_enable_transfer;
+ bool log_enable_error;
+ bool log_enable_folder;
+protected:
+ void run();
+};
+
+#endif // LOGTHREAD_H
diff --git a/OptionDialog.cpp b/OptionDialog.cpp
new file mode 100755
index 0000000..ebc76a7
--- /dev/null
+++ b/OptionDialog.cpp
@@ -0,0 +1,724 @@
+/** \file OptionDialog.cpp
+\brief To have an interface to control the options
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "OptionDialog.h"
+#include "ui_OptionDialog.h"
+
+#include <QDomElement>
+#include <QFileDialog>
+
+OptionDialog::OptionDialog() :
+ ui(new Ui::OptionDialog)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ ignoreCopyEngineListEdition=false;
+ ui->setupUi(this);
+ ui->treeWidget->topLevelItem(0)->setSelected(true);
+ ui->treeWidget->topLevelItem(2)->setExpanded(true);
+ ui->pluginList->topLevelItem(0)->setExpanded(true);
+ ui->pluginList->topLevelItem(1)->setExpanded(true);
+ ui->pluginList->topLevelItem(2)->setExpanded(true);
+ ui->pluginList->topLevelItem(3)->setExpanded(true);
+ ui->pluginList->topLevelItem(4)->setExpanded(true);
+ ui->pluginList->topLevelItem(5)->setExpanded(true);
+ on_treeWidget_itemSelectionChanged();
+
+ //load the plugins
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPlugins();
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ qRegisterMetaType<PluginsAvailable>("PluginsAvailable");
+ connect(plugins, SIGNAL(onePluginAdded(PluginsAvailable)), this, SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins, SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this, SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins, SIGNAL(pluginListingIsfinish()), this, SLOT(loadOption()));
+ connect(options, SIGNAL(newOptionValue(QString,QString,QVariant)), this, SLOT(newOptionValue(QString,QString,QVariant)));
+ plugins->unlockPluginListEdition();
+ defaultImportBackend=PluginsManager::ImportBackend_File;
+ #ifndef ULTRACOPIER_PLUGIN_SUPPORT
+ ui->pluginAdd->show();
+ ui->pluginRemove->show();
+ #endif
+}
+
+OptionDialog::~OptionDialog()
+{
+ delete ui;
+}
+
+//plugin management
+void OptionDialog::onePluginAdded(PluginsAvailable plugin)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+plugin.name+" ("+QString::number(plugin.category)+")");
+ pluginStore newItem;
+ newItem.path=plugin.path;
+ newItem.item=new QTreeWidgetItem(QStringList() << plugin.name << plugin.version);
+ newItem.isWritable=plugin.isWritable;
+ pluginLink<<newItem;
+ switch(plugin.category)
+ {
+ case PluginType_CopyEngine:
+ ui->pluginList->topLevelItem(0)->addChild(newItem.item);
+ break;
+ case PluginType_Languages:
+ ui->pluginList->topLevelItem(1)->addChild(newItem.item);
+ addLanguage(plugin);
+ break;
+ case PluginType_Listener:
+ ui->pluginList->topLevelItem(2)->addChild(newItem.item);
+ break;
+ case PluginType_PluginLoader:
+ ui->pluginList->topLevelItem(3)->addChild(newItem.item);
+ break;
+ case PluginType_SessionLoader:
+ ui->pluginList->topLevelItem(4)->addChild(newItem.item);
+ break;
+ case PluginType_Themes:
+ ui->pluginList->topLevelItem(5)->addChild(newItem.item);
+ addTheme(plugin);
+ break;
+ default:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"category not found for: "+plugin.path);
+ }
+}
+
+void OptionDialog::onePluginWillBeRemoved(PluginsAvailable plugin)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ index=0;
+ loop_size=pluginLink.size();
+ while(index<loop_size)
+ {
+ if(pluginLink.at(index).path==plugin.path)
+ {
+ delete pluginLink.at(index).item;
+ if(plugin.category==PluginType_Languages)
+ removeLanguage(plugin);
+ else if(plugin.category==PluginType_Themes)
+ removeTheme(plugin);
+ else if(plugin.category==PluginType_CopyEngine)
+ removeCopyEngine(plugin);
+ pluginLink.removeAt(index);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"not found!");
+}
+
+void OptionDialog::addLanguage(PluginsAvailable plugin)
+{
+ QList<QPair<QString,QString> > listChildAttribute;
+ QPair<QString,QString> temp;
+ temp.first = "mainCode";
+ temp.second = "true";
+ listChildAttribute << temp;
+ ui->Language->addItem(QIcon(plugin.path+"flag.png"),plugins->getDomSpecific(plugin.categorySpecific,"fullName"),plugins->getDomSpecific(plugin.categorySpecific,"shortName",listChildAttribute));
+}
+
+void OptionDialog::removeLanguage(PluginsAvailable plugin)
+{
+ QList<QPair<QString,QString> > listChildAttribute;
+ QPair<QString,QString> temp;
+ temp.first = "mainCode";
+ temp.second = "true";
+ listChildAttribute << temp;
+ int index=ui->Language->findData(plugins->getDomSpecific(plugin.categorySpecific,"shortName",listChildAttribute));
+ if(index!=-1)
+ ui->Language->removeItem(index);
+}
+
+void OptionDialog::addTheme(PluginsAvailable plugin)
+{
+ ui->Ultracopier_current_theme->addItem(plugin.name,plugin.name);
+}
+
+void OptionDialog::removeTheme(PluginsAvailable plugin)
+{
+ int index=ui->Ultracopier_current_theme->findData(plugin.name);
+ if(index!=-1)
+ ui->Ultracopier_current_theme->removeItem(index);
+}
+
+void OptionDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"retranslate the ui");
+ ui->retranslateUi(this);
+ index=0;
+ loop_size=copyEngineList.size();
+ while(index<loop_size)
+ {
+ if(copyEngineList.at(index).options!=NULL)
+ ui->treeWidget->topLevelItem(2)->addChild(copyEngineList.at(index).item);
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("the copy engine %1 have not the options").arg(index));
+ index++;
+ }
+ ui->labelLoadAtSession->setToolTip(tr("Disabled because you have any SessionLoader plugin"));
+ ui->LoadAtSessionStarting->setToolTip(tr("Disabled because you have any SessionLoader plugin"));
+ ui->ActionOnManualOpen->setItemText(0,tr("Do nothing"));
+ ui->ActionOnManualOpen->setItemText(1,tr("Ask source as folder"));
+ ui->ActionOnManualOpen->setItemText(2,tr("Ask sources as files"));
+ ui->GroupWindowWhen->setItemText(0,tr("Never"));
+ ui->GroupWindowWhen->setItemText(1,tr("When source is same"));
+ ui->GroupWindowWhen->setItemText(2,tr("When destination is same"));
+ ui->GroupWindowWhen->setItemText(3,tr("When source and destination are same"));
+ ui->GroupWindowWhen->setItemText(4,tr("When source or destination are same"));
+ ui->GroupWindowWhen->setItemText(5,tr("Always"));
+ break;
+ default:
+ break;
+ }
+}
+
+void OptionDialog::on_treeWidget_itemSelectionChanged()
+{
+ QList<QTreeWidgetItem *> listSelectedItem=ui->treeWidget->selectedItems();
+ if(listSelectedItem.size()!=1)
+ return;
+ QTreeWidgetItem * selectedItem=listSelectedItem.first();
+ if(selectedItem==ui->treeWidget->topLevelItem(0))
+ ui->stackedWidget->setCurrentIndex(0);
+ else if(selectedItem==ui->treeWidget->topLevelItem(1))
+ ui->stackedWidget->setCurrentIndex(1);
+ else if(selectedItem==ui->treeWidget->topLevelItem(2))
+ ui->stackedWidget->setCurrentIndex(2);
+ else if(selectedItem==ui->treeWidget->topLevelItem(3))
+ ui->stackedWidget->setCurrentIndex(3);
+ else if(selectedItem==ui->treeWidget->topLevelItem(4))
+ ui->stackedWidget->setCurrentIndex(4);
+ else
+ {
+ loadedCopyEnginePlugin=0;
+ index=0;
+ loop_size=copyEngineList.size();
+ while(index<loop_size)
+ {
+ if(copyEngineList.at(index).options!=NULL)
+ loadedCopyEnginePlugin++;
+ if(copyEngineList.at(index).item->isSelected())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"ui->stackedWidget->setCurrentIndex("+QString::number(3+loadedCopyEnginePlugin)+")");
+ ui->stackedWidget->setCurrentIndex(4+loadedCopyEnginePlugin);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"selection into option list cat not found");
+ }
+}
+
+void OptionDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+ if(ui->buttonBox->buttonRole(button)==QDialogButtonBox::ResetRole)
+ options->queryResetOptions();
+ else
+ this->close();
+}
+
+void OptionDialog::loadOption()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ newOptionValue("Themes", "Ultracopier_current_theme", options->getOptionValue("Themes","Ultracopier_current_theme"));
+ newOptionValue("Ultracopier", "ActionOnManualOpen", options->getOptionValue("Ultracopier","ActionOnManualOpen"));
+ newOptionValue("Ultracopier", "GroupWindowWhen", options->getOptionValue("Ultracopier","GroupWindowWhen"));
+ newOptionValue("Language", "Language", options->getOptionValue("Language","Language"));
+ newOptionValue("Language", "Language_autodetect", options->getOptionValue("Language","Language_autodetect"));
+ newOptionValue("SessionLoader", "LoadAtSessionStarting", options->getOptionValue("SessionLoader","LoadAtSessionStarting"));
+ newOptionValue("CopyListener", "CatchCopyAsDefault", options->getOptionValue("CopyListener","CatchCopyAsDefault"));
+ newOptionValue("CopyEngine", "List", options->getOptionValue("CopyEngine","List"));
+ if(resources->getWritablePath()=="")
+ ui->checkBox_Log->setEnabled(false);
+ else
+ {
+ newOptionValue("Write_log", "enabled", options->getOptionValue("Write_log","enabled"));
+ newOptionValue("Write_log", "file", options->getOptionValue("Write_log","file"));
+ newOptionValue("Write_log", "transfer", options->getOptionValue("Write_log","transfer"));
+ newOptionValue("Write_log", "error", options->getOptionValue("Write_log","error"));
+ newOptionValue("Write_log", "folder", options->getOptionValue("Write_log","folder"));
+ newOptionValue("Write_log", "transfer_format", options->getOptionValue("Write_log","transfer_format"));
+ newOptionValue("Write_log", "error_format", options->getOptionValue("Write_log","error_format"));
+ newOptionValue("Write_log", "folder_format", options->getOptionValue("Write_log","folder_format"));
+ newOptionValue("Write_log", "sync", options->getOptionValue("Write_log","sync"));
+ }
+ on_checkBox_Log_clicked();
+ if(plugins->getPluginsByCategory(PluginType_SessionLoader).size()>0)
+ {
+ ui->labelLoadAtSession->setToolTip("");
+ ui->LoadAtSessionStarting->setToolTip("");
+ ui->labelLoadAtSession->setEnabled(true);
+ ui->LoadAtSessionStarting->setEnabled(true);
+ }
+ else
+ {
+ ui->labelLoadAtSession->setToolTip(tr("Disabled because you have any SessionLoader plugin"));
+ ui->LoadAtSessionStarting->setToolTip(tr("Disabled because you have any SessionLoader plugin"));
+ ui->labelLoadAtSession->setEnabled(false);
+ ui->LoadAtSessionStarting->setEnabled(false);
+ }
+}
+
+void OptionDialog::newOptionValue(QString group,QString name,QVariant value)
+{
+ if(group=="Themes")
+ {
+ if(name=="Ultracopier_current_theme")
+ {
+ int index=ui->Ultracopier_current_theme->findData(value.toString());
+ if(index!=-1)
+ ui->Ultracopier_current_theme->setCurrentIndex(index);
+ else if(ui->Ultracopier_current_theme->count()>0)
+ options->setOptionValue("Themes","Ultracopier_current_theme",ui->Ultracopier_current_theme->itemData(ui->Ultracopier_current_theme->currentIndex()));
+ }
+ }
+ else if(group=="Language")
+ {
+ if(name=="Language")
+ {
+ int index=ui->Language->findData(value.toString());
+ if(index!=-1)
+ ui->Language->setCurrentIndex(index);
+ else if(ui->Language->count()>0)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Language in settings: "+value.toString());
+ options->setOptionValue("Language","Language",ui->Language->itemData(ui->Language->currentIndex()));
+ }
+ }
+ else if(name=="Language_autodetect")
+ {
+ ui->Language_autodetect->setChecked(value.toBool());
+ ui->Language->setDisabled(value.toBool());
+ }
+ }
+ else if(group=="SessionLoader")
+ {
+ if(name=="LoadAtSessionStarting")
+ {
+ ui->LoadAtSessionStarting->setChecked(value.toBool());
+ }
+ }
+ else if(group=="CopyListener")
+ {
+ if(name=="CatchCopyAsDefault")
+ {
+ ui->CatchCopyAsDefault->setChecked(value.toBool());
+ }
+ }
+ else if(group=="CopyEngine")
+ {
+ if(name=="List")
+ {
+ if(!ignoreCopyEngineListEdition)
+ ui->CopyEngineList->addItems(value.toStringList());
+ }
+ }
+ else if(group=="Write_log")
+ {
+ if(name=="enabled")
+ {
+ ui->checkBox_Log->setChecked(value.toBool());
+ }
+ else if(name=="file")
+ {
+ ui->lineEditLog_File->setText(value.toString());
+ }
+ else if(name=="transfer")
+ {
+ ui->checkBoxLog_transfer->setChecked(value.toBool());
+ }
+ else if(name=="sync")
+ {
+ ui->checkBoxLog_sync->setChecked(value.toBool());
+ }
+ else if(name=="error")
+ {
+ ui->checkBoxLog_error->setChecked(value.toBool());
+ }
+ else if(name=="folder")
+ {
+ ui->checkBoxLog_folder->setChecked(value.toBool());
+ }
+ else if(name=="transfer_format")
+ {
+ ui->lineEditLog_transfer_format->setText(value.toString());
+ }
+ else if(name=="error_format")
+ {
+ ui->lineEditLog_error_format->setText(value.toString());
+ }
+ else if(name=="folder_format")
+ {
+ ui->lineEditLog_folder_format->setText(value.toString());
+ }
+ }
+ else if(group=="Ultracopier")
+ {
+ if(name=="ActionOnManualOpen")
+ {
+ ui->ActionOnManualOpen->setCurrentIndex(value.toInt());
+ }
+ if(name=="GroupWindowWhen")
+ {
+ ui->GroupWindowWhen->setCurrentIndex(value.toInt());
+ }
+ }
+}
+
+void OptionDialog::on_Ultracopier_current_theme_currentIndexChanged(int index)
+{
+ if(index!=-1 && plugins->allPluginHaveBeenLoaded())
+ options->setOptionValue("Themes","Ultracopier_current_theme",ui->Ultracopier_current_theme->itemData(index));
+}
+
+void OptionDialog::on_Language_currentIndexChanged(int index)
+{
+ if(index!=-1 && plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"data value: "+ui->Language->itemData(index).toString()+", string value: "+ui->Language->itemText(index)+", index: "+QString::number(index));
+ options->setOptionValue("Language","Language",ui->Language->itemData(index));
+ }
+}
+
+void OptionDialog::on_Language_autodetect_toggled(bool checked)
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Language","Language_autodetect",checked);
+ }
+}
+
+void OptionDialog::on_CatchCopyAsDefault_toggled(bool checked)
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("CopyListener","CatchCopyAsDefault",checked);
+ }
+}
+
+void OptionDialog::on_LoadAtSessionStarting_toggled(bool checked)
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("SessionLoader","LoadAtSessionStarting",checked);
+ }
+}
+
+void OptionDialog::on_CopyEngineList_itemSelectionChanged()
+{
+ if(ui->CopyEngineList->selectedItems().size()!=0)
+ {
+ ui->toolButtonUp->setEnabled(true);
+ ui->toolButtonDown->setEnabled(true);
+ }
+ else
+ {
+ ui->toolButtonUp->setEnabled(false);
+ ui->toolButtonDown->setEnabled(false);
+ }
+}
+
+void OptionDialog::on_toolButtonDown_clicked()
+{
+ QListWidgetItem *item=ui->CopyEngineList->selectedItems().first();
+ int position=ui->CopyEngineList->row(item);
+ if((position+1)<ui->CopyEngineList->count())
+ {
+ QString text=item->text();
+ item->setSelected(false);
+ delete item;
+ ui->CopyEngineList->insertItem(position+1,text);
+ ui->CopyEngineList->item(position+1)->setSelected(true);
+ ignoreCopyEngineListEdition=true;
+ options->setOptionValue("CopyEngine","List",copyEngineStringList());
+ ignoreCopyEngineListEdition=false;
+ }
+}
+
+void OptionDialog::on_toolButtonUp_clicked()
+{
+ QListWidgetItem *item=ui->CopyEngineList->selectedItems().first();
+ int position=ui->CopyEngineList->row(item);
+ if(position>0)
+ {
+ QString text=item->text();
+ item->setSelected(false);
+ delete item;
+ ui->CopyEngineList->insertItem(position-1,text);
+ ui->CopyEngineList->item(position-1)->setSelected(true);
+ ignoreCopyEngineListEdition=true;
+ options->setOptionValue("CopyEngine","List",copyEngineStringList());
+ ignoreCopyEngineListEdition=false;
+ }
+}
+
+QStringList OptionDialog::copyEngineStringList()
+{
+ QStringList newList;
+ int index=0;
+ while(index<ui->CopyEngineList->count())
+ {
+ newList << ui->CopyEngineList->item(index)->text();
+ index++;
+ }
+ return newList;
+}
+
+void OptionDialog::newThemeOptions(QWidget* theNewOptionsWidget,bool isLoaded,bool havePlugin)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ while(ui->stackedWidgetThemes->count()>3)
+ ui->stackedWidgetThemes->removeWidget(ui->stackedWidgetThemes->widget(3));
+ if(theNewOptionsWidget!=NULL)
+ {
+ ui->stackedWidgetThemes->addWidget(theNewOptionsWidget);
+ ui->stackedWidgetThemes->setCurrentWidget(theNewOptionsWidget);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"set the last page");
+ }
+ else
+ {
+ if(isLoaded)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"set the page, no option for this plugin");
+ ui->stackedWidgetThemes->setCurrentIndex(1);
+ }
+ else if(!havePlugin)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"set the page, no plugin");
+ ui->stackedWidgetThemes->setCurrentIndex(2);
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"set the page, unable to load plugin options");
+ ui->stackedWidgetThemes->setCurrentIndex(0);
+ }
+ }
+}
+
+void OptionDialog::removeCopyEngine(PluginsAvailable plugin)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ removeCopyEngineWidget(plugin.name);
+}
+
+void OptionDialog::addCopyEngineWidget(QString name,QWidget * options)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start: %1").arg(name));
+ index=0;
+ loop_size=copyEngineList.size();
+ while(index<loop_size)
+ {
+ if(copyEngineList.at(index).name==name)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"already found: "+name);
+ return;
+ }
+ index++;
+ }
+ pluginCopyEngine temp;
+ temp.item=new QTreeWidgetItem(QStringList() << name);
+ temp.name=name;
+ temp.options=options;
+ copyEngineList << temp;
+ ui->treeWidget->topLevelItem(2)->addChild(copyEngineList.at(index).item);
+ ui->stackedWidget->addWidget(options);
+}
+
+void OptionDialog::removeCopyEngineWidget(QString name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ index=0;
+ loop_size=copyEngineList.size();
+ while(index<loop_size)
+ {
+ if(copyEngineList.at(index).name==name)
+ {
+ if(copyEngineList.at(index).options!=NULL)
+ ui->stackedWidget->removeWidget(copyEngineList.at(index).options);
+ if(copyEngineList.at(index).item->isSelected())
+ {
+ copyEngineList.at(index).item->setSelected(false);
+ ui->treeWidget->topLevelItem(0)->setSelected(true);
+ }
+ delete copyEngineList.at(index).item;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"ui->stackedWidget->count(): "+QString::number(ui->stackedWidget->count()));
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"not found is the list: "+name);
+}
+
+void OptionDialog::on_pluginList_itemSelectionChanged()
+{
+ if(ui->pluginList->selectedItems().size()==0)
+ {
+ ui->pluginRemove->setEnabled(false);
+ ui->pluginInformation->setEnabled(false);
+ }
+ else
+ {
+ treeWidgetItem=ui->pluginList->selectedItems().first();
+ index=0;
+ loop_size=pluginLink.size();
+ while(index<loop_size)
+ {
+ if(pluginLink.at(index).item==treeWidgetItem)
+ {
+ ui->pluginRemove->setEnabled(pluginLink.at(index).isWritable);
+ ui->pluginInformation->setEnabled(true);
+ return;
+ }
+ index++;
+ }
+ }
+}
+
+void OptionDialog::on_pluginRemove_clicked()
+{
+ treeWidgetItem=ui->pluginList->selectedItems().first();
+ index=0;
+ loop_size=pluginLink.size();
+ while(index<loop_size)
+ {
+ if(pluginLink.at(index).item==treeWidgetItem)
+ {
+ plugins->removeThePluginSelected(pluginLink.at(index).path);
+ return;
+ }
+ index++;
+ }
+}
+
+void OptionDialog::on_pluginInformation_clicked()
+{
+ treeWidgetItem=ui->pluginList->selectedItems().first();
+ index=0;
+ loop_size=pluginLink.size();
+ while(index<loop_size)
+ {
+ if(pluginLink.at(index).item==treeWidgetItem)
+ {
+ plugins->showInformation(pluginLink.at(index).path);
+ return;
+ }
+ index++;
+ }
+}
+
+void OptionDialog::on_pluginAdd_clicked()
+{
+ plugins->addPlugin(defaultImportBackend);
+}
+
+void OptionDialog::on_checkBox_Log_clicked()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","enabled",ui->checkBox_Log->isChecked());
+ }
+ ui->lineEditLog_transfer_format->setEnabled(ui->checkBoxLog_transfer->isChecked() && ui->checkBox_Log->isChecked());
+ ui->lineEditLog_error_format->setEnabled(ui->checkBoxLog_error->isChecked() && ui->checkBox_Log->isChecked());
+ ui->lineEditLog_folder_format->setEnabled(ui->checkBoxLog_folder->isChecked() && ui->checkBox_Log->isChecked());
+}
+
+void OptionDialog::on_lineEditLog_File_editingFinished()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","file",ui->lineEditLog_File->text());
+ }
+}
+
+void OptionDialog::on_lineEditLog_transfer_format_editingFinished()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","transfer_format",ui->lineEditLog_transfer_format->text());
+ }
+}
+
+void OptionDialog::on_lineEditLog_error_format_editingFinished()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","error_format",ui->lineEditLog_error_format->text());
+ }
+}
+
+void OptionDialog::on_checkBoxLog_transfer_clicked()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","transfer",ui->checkBoxLog_transfer->isChecked());
+ }
+}
+
+void OptionDialog::on_checkBoxLog_error_clicked()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","error",ui->checkBoxLog_error->isChecked());
+ }
+}
+
+void OptionDialog::on_checkBoxLog_folder_clicked()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","folder",ui->checkBoxLog_folder->isChecked());
+ }
+}
+
+void OptionDialog::on_pushButton_clicked()
+{
+ QString file=QFileDialog::getSaveFileName(this,tr("Save logs as: "),resources->getWritablePath());
+ if(file!="")
+ {
+ ui->lineEditLog_File->setText(file);
+ on_lineEditLog_File_editingFinished();
+ }
+}
+
+void OptionDialog::on_checkBoxLog_sync_clicked()
+{
+ if(plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ options->setOptionValue("Write_log","sync",ui->checkBoxLog_sync->isChecked());
+ }
+}
+
+void OptionDialog::on_ActionOnManualOpen_currentIndexChanged(int index)
+{
+ if(index!=-1 && plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"data value: "+ui->ActionOnManualOpen->itemData(index).toString()+", string value: "+ui->ActionOnManualOpen->itemText(index)+", index: "+QString::number(index));
+ options->setOptionValue("Ultracopier","ActionOnManualOpen",index);
+ }
+}
+
+void OptionDialog::on_GroupWindowWhen_currentIndexChanged(int index)
+{
+ if(index!=-1 && plugins->allPluginHaveBeenLoaded())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"data value: "+ui->GroupWindowWhen->itemData(index).toString()+", string value: "+ui->GroupWindowWhen->itemText(index)+", index: "+QString::number(index));
+ options->setOptionValue("Ultracopier","GroupWindowWhen",index);
+ }
+}
diff --git a/OptionDialog.h b/OptionDialog.h
new file mode 100755
index 0000000..39a1baf
--- /dev/null
+++ b/OptionDialog.h
@@ -0,0 +1,101 @@
+/** \file OptionDialog.h
+\brief To have an interface to control the options
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef OPTIONDIALOG_H
+#define OPTIONDIALOG_H
+
+#include <QDialog>
+#include <QAbstractButton>
+
+#include "GlobalClass.h"
+
+namespace Ui {
+ class OptionDialog;
+}
+
+/** \brief Dialog for the options
+
+ It's need manage the ultracopier options, plugins selection, plugin prority.
+ It's need manage too the plugin options and plugins informations.
+ */
+class OptionDialog : public QDialog, public GlobalClass
+{
+ Q_OBJECT
+public:
+ explicit OptionDialog();
+ ~OptionDialog();
+ /** \brief add the option widget from copy engine */
+ void addCopyEngineWidget(QString name,QWidget * options);
+ /** \brief remove the option widget from copy engine */
+ void removeCopyEngineWidget(QString name);
+protected:
+ void changeEvent(QEvent *e);
+private slots:
+ void on_treeWidget_itemSelectionChanged();
+ void on_buttonBox_clicked(QAbstractButton *button);
+ //plugin management
+ void onePluginAdded(PluginsAvailable plugin);
+ void onePluginWillBeRemoved(PluginsAvailable plugin);
+ void loadOption();
+ void newOptionValue(QString group,QString name,QVariant value);
+ void on_Ultracopier_current_theme_currentIndexChanged(int index);
+ void on_Language_currentIndexChanged(int index);
+ void on_Language_autodetect_toggled(bool checked);
+ void on_CatchCopyAsDefault_toggled(bool checked);
+ void on_LoadAtSessionStarting_toggled(bool checked);
+ void on_CopyEngineList_itemSelectionChanged();
+ void on_toolButtonDown_clicked();
+ void on_toolButtonUp_clicked();
+ void on_pluginList_itemSelectionChanged();
+ void on_pluginRemove_clicked();
+ void on_pluginInformation_clicked();
+ void on_pluginAdd_clicked();
+ void on_checkBox_Log_clicked();
+ void on_lineEditLog_File_editingFinished();
+ void on_lineEditLog_transfer_format_editingFinished();
+ void on_lineEditLog_error_format_editingFinished();
+ void on_checkBoxLog_transfer_clicked();
+ void on_checkBoxLog_error_clicked();
+ void on_pushButton_clicked();
+ void on_checkBoxLog_folder_clicked();
+ void on_checkBoxLog_sync_clicked();
+ void on_ActionOnManualOpen_currentIndexChanged(int index);
+
+ void on_GroupWindowWhen_currentIndexChanged(int index);
+
+private:
+ Ui::OptionDialog *ui;
+ struct pluginStore
+ {
+ QTreeWidgetItem * item;
+ QString path;
+ bool isWritable;
+ };
+ QList<pluginStore> pluginLink;
+ struct pluginCopyEngine
+ {
+ QString name;
+ QTreeWidgetItem * item;
+ QWidget *options;
+ };
+ QList<pluginCopyEngine> copyEngineList;
+ void addLanguage(PluginsAvailable plugin);
+ void removeLanguage(PluginsAvailable plugin);
+ void addTheme(PluginsAvailable plugin);
+ void removeTheme(PluginsAvailable plugin);
+ void removeCopyEngine(PluginsAvailable plugin);
+ QStringList copyEngineStringList();
+ bool ignoreCopyEngineListEdition;
+ PluginsManager::ImportBackend defaultImportBackend;
+ int index,loop_size;
+ int loadedCopyEnginePlugin;
+ QTreeWidgetItem * treeWidgetItem;
+public slots:
+ void newThemeOptions(QWidget* theNewOptionsWidget,bool isLoaded,bool havePlugin);
+};
+
+#endif // OPTIONDIALOG_H
diff --git a/OptionDialog.ui b/OptionDialog.ui
new file mode 100644
index 0000000..873f75a
--- /dev/null
+++ b/OptionDialog.ui
@@ -0,0 +1,905 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OptionDialog</class>
+ <widget class="QDialog" name="OptionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>717</width>
+ <height>455</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string>Options</string>
+ </property>
+ </column>
+ <item>
+ <property name="text">
+ <string>General</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Plugins</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Copy engine</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Themes</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Log</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="stackedWidgetGeneral">
+ <layout class="QVBoxLayout" name="verticalLayout_10">
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelLanguage">
+ <property name="text">
+ <string>Language:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="Language"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelLanguageAutodetect">
+ <property name="text">
+ <string>Autodetect the system language:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="Language_autodetect">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelCatchCopyDefault">
+ <property name="text">
+ <string>Catch the copy/move as default:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="CatchCopyAsDefault">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="labelLoadAtSession">
+ <property name="text">
+ <string>Load at the session loading:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="LoadAtSessionStarting">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>When manual open:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QComboBox" name="ActionOnManualOpen">
+ <item>
+ <property name="text">
+ <string notr="true">Do nothing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">Ask source as folder</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">Ask sources as files</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QComboBox" name="GroupWindowWhen">
+ <item>
+ <property name="text">
+ <string notr="true">Never</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">When source is same</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">When destination is same</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">When source and destination are same</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">When source or destination are same</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string notr="true">Always</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Group window when:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>309</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="stackedWidgetPlugins">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTreeWidget" name="pluginList">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </column>
+ <item>
+ <property name="text">
+ <string>Copy engine</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Language</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Listener</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Plugin loader</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Session loader</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Themes</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Plugin</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="pluginAdd">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::MenuButtonPopup</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pluginRemove">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pluginInformation">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Information</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="stackedWidgetCopyEngine">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Copy engine by order of preference:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="formLayout">
+ <item>
+ <widget class="QListWidget" name="CopyEngineList">
+ <property name="uniformItemSizes">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="toolButtonUp">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources/resources.qrc">
+ <normaloff>:/moveUp.png</normaloff>:/moveUp.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="toolButtonDown">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources/resources.qrc">
+ <normaloff>:/moveDown.png</normaloff>:/moveDown.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelThemes">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>22</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Themes:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="Ultracopier_current_theme"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidgetThemes">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="page_2">
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>105</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="pixmap">
+ <pixmap resource="resources/resources.qrc">:/bug-128x128.png</pixmap>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="font">
+ <font>
+ <pointsize>15</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Unable to load the themes plugin</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>104</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_3">
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>109</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="pixmap">
+ <pixmap resource="resources/resources.qrc">:/none-128x128.png</pixmap>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>No option for this plugin</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>109</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_4">
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <item>
+ <spacer name="verticalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>109</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="pixmap">
+ <pixmap resource="resources/resources.qrc">:/none-128x128.png</pixmap>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>No plugin loaded</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>109</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_5">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QCheckBox" name="checkBox_Log">
+ <property name="text">
+ <string>Write the log file into:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLineEdit" name="lineEditLog_File">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Browse</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBoxLog_sync">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>This write directly the file when it receive the new entry, but it can produce 50% of lost of performance</string>
+ </property>
+ <property name="text">
+ <string>Synchronized log</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBoxLog_transfer">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Write the transfers:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditLog_transfer_format">
+ <property name="toolTip">
+ <string>The variables are %time%, %source%, %size%, %destination%</string>
+ </property>
+ <property name="placeholderText">
+ <string>Format</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBoxLog_error">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Write the errors:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditLog_error_format">
+ <property name="toolTip">
+ <string>The variables are %time%, %path%, %size%, %mtime%, %error%</string>
+ </property>
+ <property name="placeholderText">
+ <string>Format</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBoxLog_folder">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Write the folder operations:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditLog_folder_format">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="placeholderText">
+ <string>Format</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>255</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close|QDialogButtonBox::RestoreDefaults</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="resources/resources.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>Language_autodetect</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>Language</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>449</x>
+ <y>42</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>502</x>
+ <y>10</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lineEditLog_File</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>313</x>
+ <y>13</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>533</x>
+ <y>44</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>pushButton</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>583</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>584</x>
+ <y>40</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>checkBoxLog_transfer</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>345</x>
+ <y>21</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>582</x>
+ <y>105</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>checkBoxLog_error</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>348</x>
+ <y>25</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>557</x>
+ <y>156</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBoxLog_transfer</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lineEditLog_transfer_format</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>537</x>
+ <y>105</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>533</x>
+ <y>131</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBoxLog_error</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lineEditLog_error_format</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>501</x>
+ <y>156</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>501</x>
+ <y>182</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>checkBoxLog_folder</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>269</x>
+ <y>15</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>456</x>
+ <y>207</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>checkBox_Log</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>checkBoxLog_sync</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>334</x>
+ <y>12</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>304</x>
+ <y>69</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/OptionEngine.cpp b/OptionEngine.cpp
new file mode 100644
index 0000000..807e027
--- /dev/null
+++ b/OptionEngine.cpp
@@ -0,0 +1,271 @@
+/** \file OptionEngine.cpp
+\brief Define the class of the event dispatcher
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QFileInfo>
+#include <QDir>
+#include <QPluginLoader>
+#include <QLabel>
+#include <QComboBox>
+#include <QDialogButtonBox>
+#include <QMessageBox>
+
+#include "OptionEngine.h"
+
+/// \todo async the options write
+
+/// \brief Initiate the option, load from backend
+OptionEngine::OptionEngine()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //locate the settings
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ resources=ResourcesManager::getInstance();
+ QString settingsFilePath=resources->getWritablePath();
+ if(settingsFilePath!="")
+ settings = new QSettings(settingsFilePath+"Ultracopier.conf",QSettings::IniFormat);
+ else
+ settings = NULL;
+ #else // ULTRACOPIER_VERSION_PORTABLE
+ settings = new QSettings("Ultracopier","Ultracopier");
+ #endif // ULTRACOPIER_VERSION_PORTABLE
+ if(settings!=NULL)
+ {
+ //do some write test
+ if(settings->status()!=QSettings::NoError)
+ {
+ delete settings;
+ settings=NULL;
+ }
+ else if(!settings->isWritable())
+ {
+ delete settings;
+ settings=NULL;
+ }
+ else
+ {
+ settings->setValue("test","test");
+ if(settings->status()!=QSettings::NoError)
+ {
+ delete settings;
+ settings=NULL;
+ }
+ else
+ {
+ settings->remove("test");
+ if(settings->status()!=QSettings::NoError)
+ {
+ delete settings;
+ settings=NULL;
+ }
+ }
+ }
+ }
+ //set the backend
+ if(settings==NULL)
+ {
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ resources->disableWritablePath();
+ #endif // ULTRACOPIER_VERSION_PORTABLE
+ currentBackend=Memory;
+ }
+ else
+ currentBackend=File;
+}
+
+/// \brief Destroy the option
+OptionEngine::~OptionEngine()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ ResourcesManager::destroyInstanceAtTheLastCall();
+}
+
+/// \brief To add option group to options
+bool OptionEngine::addOptionGroup(const QString &groupName,const QList<QPair<QString, QVariant> > &KeysList)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start(\""+groupName+"\",[...])");
+ //search if previous with the same name exists
+ indexGroup=0;
+ loop_size=GroupKeysList.size();
+ while(indexGroup<loop_size)
+ {
+ if(GroupKeysList.at(indexGroup).groupName==groupName)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"group already used previously");
+ break;
+ }
+ indexGroup++;
+ }
+ //else create the entry
+ if(indexGroup==loop_size)
+ {
+ OptionEngineGroup tempEntry;
+ tempEntry.groupName=groupName;
+ GroupKeysList << tempEntry;
+ }
+ //here GroupKeysList.at(indexGroup) can be used
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"variable used: GroupKeysList.at("+QString::number(indexGroup)+")");
+ //if the backend is file, enter into the group
+ if(currentBackend==File)
+ settings->beginGroup(groupName);
+ //browse all key, and append it to the key
+ index=0;
+ QList<OptionEngineGroupKey> KeyListTemp;
+ loop_size=KeysList.size();
+ while(index<loop_size)
+ {
+ OptionEngineGroupKey theCurrentKey;
+ theCurrentKey.variableName=KeysList.at(index).first;
+ theCurrentKey.defaultValue=KeysList.at(index).second;
+ theCurrentKey.emptyList=false;
+ //if memory backend, load the default value into the current value
+ if(currentBackend==Memory)
+ theCurrentKey.currentValue=theCurrentKey.defaultValue;
+ else if(settings->contains(theCurrentKey.variableName))//if file backend, load the default value from the file
+ theCurrentKey.currentValue=settings->value(theCurrentKey.variableName);
+ else //or if not found load the default value and set into the file
+ {
+ theCurrentKey.currentValue=theCurrentKey.defaultValue;
+ //to switch default value if is unchanged
+ //settings->setValue(theCurrentKey.variableName,theCurrentKey.defaultValue);
+ }
+ if(settings->status()!=QSettings::NoError)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Have writing error, switch to memory only options");
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ resources->disableWritablePath();
+ #endif // ULTRACOPIER_VERSION_PORTABLE
+ currentBackend=Memory;
+ }
+ GroupKeysList[indexGroup].KeysList << theCurrentKey;
+ index++;
+ }
+ //if the backend is file, leave into the group
+ if(currentBackend==File)
+ settings->endGroup();
+ return true;
+}
+
+/// \brief To remove option group to options, remove the widget need be do into the calling object
+bool OptionEngine::removeOptionGroup(const QString &groupName)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start, groupName: "+groupName);
+ indexGroup=0;
+ loop_size=GroupKeysList.size();
+ while(indexGroup<loop_size)
+ {
+ if(GroupKeysList.at(indexGroup).groupName==groupName)
+ {
+ GroupKeysList.removeAt(indexGroup);
+ return true;
+ }
+ indexGroup++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"value not found, internal bug, groupName: "+groupName);
+ return false;
+}
+
+/// \brief To get option value
+QVariant OptionEngine::getOptionValue(const QString &groupName,const QString &variableName)
+{
+ indexGroup=0;
+ loop_size=GroupKeysList.size();
+ while(indexGroup<loop_size)
+ {
+ if(GroupKeysList.at(indexGroup).groupName==groupName)
+ {
+ //search if previous with the same name exists
+ indexGroupKey=0;
+ loop_sub_size=GroupKeysList.at(indexGroup).KeysList.size();
+ while(indexGroupKey<loop_sub_size)
+ {
+ if(GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).variableName==variableName)
+ return GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).currentValue;
+ indexGroupKey++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"value not found, internal bug, groupName: "+groupName+", variableName: "+variableName);
+ return QVariant();
+ }
+ indexGroup++;
+ }
+ QMessageBox::critical(NULL,"Internal error","Get the option value but not found");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"group \""+groupName+"\" not found, internal bug!");
+ //return default value
+ return QVariant();
+}
+
+/// \brief To set option value
+void OptionEngine::setOptionValue(const QString &groupName,const QString &variableName,const QVariant &value)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"groupName: \""+groupName+"\", variableName: \""+variableName+"\", value: \""+value.toString()+"\"");
+ indexGroup=0;
+ loop_size=GroupKeysList.size();
+ while(indexGroup<loop_size)
+ {
+ if(GroupKeysList.at(indexGroup).groupName==groupName)
+ {
+ //search if previous with the same name exists
+ indexGroupKey=0;
+ loop_sub_size=GroupKeysList.at(indexGroup).KeysList.size();
+ while(indexGroupKey<loop_sub_size)
+ {
+ if(GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).variableName==variableName)
+ {
+ if(GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).currentValue!=value) //protection to prevent same value writing
+ {
+ GroupKeysList[indexGroup].KeysList[indexGroupKey].currentValue=value;
+ if(currentBackend==File)
+ {
+ settings->beginGroup(groupName);
+ settings->setValue(variableName,value);
+ settings->endGroup();
+ if(settings->status()!=QSettings::NoError)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Have writing error, switch to memory only options");
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ resources->disableWritablePath();
+ #endif // ULTRACOPIER_VERSION_PORTABLE
+ currentBackend=Memory;
+ }
+ }
+ emit newOptionValue(groupName,variableName,value);
+ }
+ return;
+ }
+ indexGroupKey++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"value not found, internal bug, groupName: \""+groupName+"\", variableName: \""+variableName+"\", value: \""+value.toString()+"\"");
+ return;
+ }
+ indexGroup++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"group \""+groupName+"\" not found, internal bug, groupName: \""+groupName+"\", variableName: \""+variableName+"\", value: \""+value.toString()+"\"");
+}
+
+//the reset of right value of widget need be do into the calling object
+void OptionEngine::internal_resetToDefaultValue()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int indexGroup=0;
+ while(indexGroup<GroupKeysList.size())
+ {
+ //search if previous with the same name exists
+ int indexGroupKey=0;
+ while(indexGroupKey<GroupKeysList.at(indexGroup).KeysList.size())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"option check: "+GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).variableName);
+ if(GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).currentValue!=GroupKeysList.at(indexGroup).KeysList.at(indexGroupKey).defaultValue)
+ GroupKeysList[indexGroup].KeysList[indexGroupKey].currentValue=GroupKeysList[indexGroup].KeysList[indexGroupKey].defaultValue;
+ indexGroupKey++;
+ }
+ indexGroup++;
+ }
+}
+
+void OptionEngine::queryResetOptions()
+{
+ emit resetOptions();
+}
diff --git a/OptionEngine.h b/OptionEngine.h
new file mode 100644
index 0000000..9605535
--- /dev/null
+++ b/OptionEngine.h
@@ -0,0 +1,100 @@
+/** \file OptionEngine.h
+\brief Define the class of the option engine
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef OPTION_ENGINE_H
+#define OPTION_ENGINE_H
+
+#include <QDialog>
+#include <QList>
+#include <QSettings>
+#include <QFormLayout>
+#include <QLayout>
+#include <QStringList>
+#include <QFormLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QSpinBox>
+#include <QAbstractButton>
+#include <QTimer>
+#include <QWidget>
+
+#include "interface/OptionInterface.h"
+
+#include "Environment.h"
+#include "Singleton.h"
+#include "ResourcesManager.h"
+
+/** \brief To store the options
+
+ That's allow to have mutualised way to store the options. Then the plugins just keep Ultracopier manage it, the portable version will store on the disk near the application, and the normal version will keep at the normal location.
+ That's allow to have cache and buffer to not slow down Ultracopier when it's doing heavy copy/move.
+*/
+class OptionEngine : public QObject, public Singleton<OptionEngine>
+{
+ Q_OBJECT
+ //class OptionEngine : public OptionInterface, public QDialog, public Singleton<OptionEngine>
+ friend class Singleton<OptionEngine>;
+ public:
+ /// \brief To add option group to options
+ bool addOptionGroup(const QString &groupName,const QList<QPair<QString, QVariant> > &KeysList);
+ /// \brief To remove option group to options, remove the widget need be do into the calling object
+ bool removeOptionGroup(const QString &groupName);
+ /// \brief To get option value
+ QVariant getOptionValue(const QString &groupName,const QString &variableName);
+ /// \brief To set option value
+ void setOptionValue(const QString &groupName,const QString &variableName,const QVariant &value);
+ /// \brief To invalid option value
+ //void setInvalidOptionValue(const QString &groupName,const QString &variableName);
+ /// \brief get query reset options
+ void queryResetOptions();
+ private:
+ /// \brief Initiate the option, load from backend
+ OptionEngine();
+ /// \brief Destroy the option
+ ~OptionEngine();
+
+ /// \brief OptionEngineGroupKey then: Group -> Key
+ struct OptionEngineGroupKey
+ {
+ QString variableName;
+ QVariant defaultValue;
+ QVariant currentValue;
+ bool emptyList;
+ };
+ /// \brief OptionEngineGroup then: Group
+ struct OptionEngineGroup
+ {
+ QString groupName;
+ QList<OptionEngineGroupKey> KeysList;
+ };
+
+ /// \brief store the option group list
+ QList<OptionEngineGroup> GroupKeysList;
+ QStringList unmanagedTabName;
+ /// \brief Enumeration of backend
+ enum Backend
+ {
+ Memory, //Do intensive usage of memory, used only if the file backend is not available
+ File //Store all directly into file
+ };
+ /// \brief The current backend
+ Backend currentBackend;
+ /// \brief To store QSettings for the backend
+ QSettings *settings;
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ ResourcesManager *resources;
+ #endif // ULTRACOPIER_VERSION_PORTABLE
+ //the reset of right value of widget need be do into the calling object
+ void internal_resetToDefaultValue();
+ //temp variable
+ int loop_size,loop_sub_size,indexGroup,indexGroupKey,index;
+ signals:
+ void newOptionValue(const QString&,const QString&,const QVariant&);
+ void resetOptions();
+};
+
+#endif // OPTION_ENGINE_H
diff --git a/PlatformMacro.h b/PlatformMacro.h
new file mode 100644
index 0000000..5b79534
--- /dev/null
+++ b/PlatformMacro.h
@@ -0,0 +1,61 @@
+/** \file PlatformMacro.h
+\brief Define the macro for the platform
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QObject>
+
+#ifndef PLATFORM_MACRO_H
+#define PLATFORM_MACRO_H
+
+//windows
+#if defined(Q_OS_WIN32)
+ #if defined(_M_X64) //_WIN64
+ //windows 64Bits
+ #define ULTRACOPIER_PLATFORM_NAME tr("Windows 64Bits")
+ #define ULTRACOPIER_PLATFORM_CODE "windows-x86_64"
+ #else
+ //windows 32Bits
+ #define ULTRACOPIER_PLATFORM_NAME tr("Windows 32Bits")
+ #define ULTRACOPIER_PLATFORM_CODE "windows-x86"
+ #endif
+#elif defined(Q_OS_MAC)
+ //Mac OS X
+ #define ULTRACOPIER_PLATFORM_NAME tr("Mac OS X")
+ #define ULTRACOPIER_PLATFORM_CODE "mac-os-x"
+#elif defined(Q_OS_LINUX)
+ #if defined(__i386__)
+ //linux pc i386
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux pc i386")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-i386-pc"
+ #elif defined(__i486__)
+ //linux pc i486
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux pc i486")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-i486-pc"
+ #elif defined(__i586__)
+ //linux pc i586
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux pc i586")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-i586-pc"
+ #elif defined(__i686__)
+ //linux pc i686
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux pc i686")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-i686-pc"
+ #elif defined(__x86_64__)
+ //linux pc 64Bits
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux pc 64Bits")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-x86_64-pc"
+ #else
+ //linux unknow
+ #define ULTRACOPIER_PLATFORM_NAME tr("Linux unknow platform")
+ #define ULTRACOPIER_PLATFORM_CODE "linux-unknow-pc"
+ #endif
+#else
+ //unknow
+ #define ULTRACOPIER_PLATFORM_NAME tr("Unknow platform")
+ #define ULTRACOPIER_PLATFORM_CODE "unknow"
+#endif
+
+#endif // PLATFORM_MACRO_H
+
diff --git a/PluginInformation.cpp b/PluginInformation.cpp
new file mode 100644
index 0000000..11912fa
--- /dev/null
+++ b/PluginInformation.cpp
@@ -0,0 +1,126 @@
+/** \file PluginInformation.cpp
+\brief Define the plugin information
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "PluginInformation.h"
+#include "ui_PluginInformation.h"
+
+PluginInformation::PluginInformation() :
+ ui(new Ui::PluginInformation)
+{
+ ui->setupUi(this);
+ pluginIsLoaded=false;
+}
+
+PluginInformation::~PluginInformation()
+{
+ delete ui;
+}
+
+void PluginInformation::setPlugin(PluginsAvailable plugin)
+{
+ this->plugin=plugin;
+ pluginIsLoaded=true;
+ retranslateInformation();
+}
+
+void PluginInformation::setLanguage(QString language)
+{
+ this->language=language;
+}
+
+QString PluginInformation::categoryToTranslation(PluginType category)
+{
+ switch(category)
+ {
+ case PluginType_CopyEngine:
+ return tr("CopyEngine");
+ break;
+ case PluginType_Languages:
+ return tr("Languages");
+ break;
+ case PluginType_Listener:
+ return tr("Listener");
+ break;
+ case PluginType_PluginLoader:
+ return tr("PluginLoader");
+ break;
+ case PluginType_SessionLoader:
+ return tr("SessionLoader");
+ break;
+ case PluginType_Themes:
+ return tr("Themes");
+ break;
+ default:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"cat translation not found");
+ return "Unknow";
+ break;
+ }
+}
+
+void PluginInformation::retranslateInformation()
+{
+ if(!pluginIsLoaded)
+ return;
+ ui->retranslateUi(this);
+ this->setWindowTitle(tr("Information about %1").arg(plugin.name));
+ ui->name->setText(plugin.name);
+ ui->title->setText(getTranslatedText(plugin,"title",language));
+ ui->category->setText(categoryToTranslation(plugin.category));
+ ui->author->setText(getInformationText(plugin,"author"));
+ QString website=getTranslatedText(plugin,"website",language);
+ ui->website->setText("<a href=\""+website+"\" title=\""+website+"\">"+website+"</a>");
+ bool ok;
+ int timeStamps=getInformationText(plugin,"pubDate").toInt(&ok);
+ QDateTime date;
+ date.setTime_t(timeStamps);
+ ui->date->setDateTime(date);
+ if(!ok || timeStamps<=0)
+ ui->date->setEnabled(false);
+ ui->description->setPlainText(getTranslatedText(plugin,"description",language));
+ ui->version->setText(getInformationText(plugin,"version"));
+}
+
+/// \brief get informations text
+QString PluginInformation::getInformationText(PluginsAvailable plugin,QString informationName)
+{
+ int index=0;
+ while(index<plugin.informations.size())
+ {
+ if(plugin.informations.at(index).size()==2 && plugin.informations.at(index).first()==informationName)
+ return plugin.informations.at(index).last();
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"information not found: "+informationName+", for: "+plugin.name+", cat: "+categoryToTranslation(plugin.category));
+ return "";
+}
+
+/// \brief get translated text
+QString PluginInformation::getTranslatedText(PluginsAvailable plugin,QString informationName,QString mainShortName)
+{
+ int index=0;
+ QString TextFound;
+ while(index<plugin.informations.size())
+ {
+ if(plugin.informations.at(index).size()==3)
+ {
+ if(plugin.informations.at(index).first()==informationName)
+ {
+ if(plugin.informations.at(index).at(1)==mainShortName)
+ return plugin.informations.at(index).last();
+ else if(plugin.informations.at(index).at(1)=="en")
+ TextFound=plugin.informations.at(index).last();
+
+ }
+ }
+ index++;
+ }
+ #ifdef ULTRACOPIER_DEBUG
+ if(TextFound.isEmpty() || TextFound.isEmpty())
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"text is not found or empty for: "+informationName+", with the language: "+mainShortName+", for the plugin: "+plugin.path);
+ #endif // ULTRACOPIER_DEBUG
+ return TextFound;
+}
diff --git a/PluginInformation.h b/PluginInformation.h
new file mode 100644
index 0000000..bae5ea4
--- /dev/null
+++ b/PluginInformation.h
@@ -0,0 +1,44 @@
+/** \file PluginInformation.h
+\brief Define the plugin information
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef PLUGININFORMATION_H
+#define PLUGININFORMATION_H
+
+#include <QDialog>
+#include <QDateTime>
+
+#include "Environment.h"
+
+namespace Ui {
+ class PluginInformation;
+}
+
+/** \brief to show the plugin information */
+class PluginInformation : public QDialog
+{
+ Q_OBJECT
+ public:
+ explicit PluginInformation();
+ ~PluginInformation();
+ /** \brief get translated categorie */
+ QString categoryToTranslation(PluginType category);
+ /** \brief to get the new plugin informations */
+ void setPlugin(PluginsAvailable plugin);
+ /** \brief to set the language */
+ void setLanguage(QString language);
+ public slots:
+ void retranslateInformation();
+ private:
+ bool pluginIsLoaded;
+ PluginsAvailable plugin;
+ Ui::PluginInformation *ui;
+ QString language;
+ QString getInformationText(PluginsAvailable plugin,QString informationName);
+ QString getTranslatedText(PluginsAvailable plugin,QString informationName,QString mainShortName);
+};
+
+#endif // PLUGININFORMATION_H
diff --git a/PluginInformation.ui b/PluginInformation.ui
new file mode 100644
index 0000000..64a0bd1
--- /dev/null
+++ b/PluginInformation.ui
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PluginInformation</class>
+ <widget class="QDialog" name="PluginInformation">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>About this plugin</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="name">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Category:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="category">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="author">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Website:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="website">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Date:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QDateTimeEdit" name="date">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QTextEdit" name="description">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLineEdit" name="version">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Title:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="title">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/PluginLoader.cpp b/PluginLoader.cpp
new file mode 100755
index 0000000..2a59cb9
--- /dev/null
+++ b/PluginLoader.cpp
@@ -0,0 +1,230 @@
+/** \file PluginLoader.h
+\brief Define the plugin loader
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "PluginLoader.h"
+
+PluginLoader::PluginLoader(QObject *parent) :
+ QObject(parent)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the overall instance
+ plugins=PluginsManager::getInstance();
+ //load the plugin
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_PluginLoader);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ qRegisterMetaType<PluginsAvailable>("PluginsAvailable");
+ qRegisterMetaType<CatchState>("CatchState");
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this,SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this,SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins,SIGNAL(pluginListingIsfinish()), this,SLOT(allPluginIsloaded()));
+ plugins->unlockPluginListEdition();
+ needEnable=false;
+ last_state=Uncaught;
+ last_have_plugin=false;
+ last_inWaitOfReply=false;
+}
+
+PluginLoader::~PluginLoader()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_PluginLoader);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginWillBeRemoved(currentPlugin);
+ PluginsManager::destroyInstanceAtTheLastCall();
+}
+
+void PluginLoader::resendState()
+{
+ sendState(true);
+}
+
+void PluginLoader::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_PluginLoader)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QString pluginPath=plugin.path+PluginsManager::getResolvedPluginName("pluginLoader");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"try load: "+pluginPath);
+ QPluginLoader *pluginLoader= new QPluginLoader(pluginPath);
+ QObject *pluginInstance = pluginLoader->instance();
+ if(pluginInstance)
+ {
+ PluginInterface_PluginLoader *PluginLoader = qobject_cast<PluginInterface_PluginLoader *>(pluginInstance);
+ //check if found
+ index=0;
+ loop_size=pluginList.size();
+ while(index<loop_size)
+ {
+ if(pluginList.at(index).PluginLoaderInterface==PluginLoader)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Plugin already found"));
+ pluginLoader->unload();
+ return;
+ }
+ index++;
+ }
+ if(PluginLoader)
+ {
+ #ifdef ULTRACOPIER_DEBUG
+ connect(PluginLoader,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SLOT(debugInformation(DebugLevel,QString,QString,QString,int)));
+ #endif // ULTRACOPIER_DEBUG
+ LocalPlugin newEntry;
+ newEntry.options=new LocalPluginOptions("PluginLoader-"+plugin.name);
+ newEntry.pluginLoader = pluginLoader;
+ newEntry.PluginLoaderInterface = PluginLoader;
+ newEntry.path = plugin.path;
+ newEntry.state = Uncaught;
+ newEntry.inWaitOfReply = false;
+ pluginList << newEntry;
+ PluginLoader->setResources(newEntry.options,plugin.writablePath,plugin.path,ULTRACOPIER_VERSION_PORTABLE_BOOL);
+ connect(pluginList.last().PluginLoaderInterface,SIGNAL(newState(CatchState)),this,SLOT(newState(CatchState)));
+ if(needEnable)
+ {
+ pluginList.last().inWaitOfReply=true;
+ newEntry.PluginLoaderInterface->setEnabled(needEnable);
+ }
+
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to cast the plugin: "+pluginLoader->errorString());
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to load the plugin: "+pluginLoader->errorString());
+}
+
+void PluginLoader::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_PluginLoader)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ index=0;
+ loop_size=pluginList.size();
+ while(index<loop_size)
+ {
+ if(plugin.path==pluginList.at(index).path)
+ {
+ pluginList.at(index).PluginLoaderInterface->setEnabled(false);
+ if(!pluginList.at(index).pluginLoader->isLoaded() || pluginList.at(index).pluginLoader->unload())
+ {
+ delete pluginList.at(index).options;
+ pluginList.removeAt(index);
+ }
+ sendState();
+ return;
+ }
+ index++;
+ }
+}
+
+void PluginLoader::load()
+{
+ needEnable=true;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginList.size())
+ {
+ pluginList[index].inWaitOfReply=true;
+ pluginList.at(index).PluginLoaderInterface->setEnabled(true);
+ index++;
+ }
+}
+
+void PluginLoader::unload()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ needEnable=false;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ pluginList[index].inWaitOfReply=true;
+ pluginList.at(index).PluginLoaderInterface->setEnabled(false);
+ index++;
+ }
+}
+
+#ifdef ULTRACOPIER_DEBUG
+void PluginLoader::debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne)
+{
+ DebugEngine::addDebugInformationStatic(level,fonction,text,file,ligne,"Plugin loader plugin");
+}
+#endif // ULTRACOPIER_DEBUG
+
+void PluginLoader::allPluginIsloaded()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"with value: "+QString::number(pluginList.size()>0));
+ sendState(true);
+}
+
+void PluginLoader::sendState(bool force)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, pluginList.size(): %1, force: %2").arg(pluginList.size()).arg(force));
+ CatchState current_state=Uncaught;
+ bool found_not_listen=false,found_listen=false,found_inWaitOfReply=false;
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(current_state==Uncaught)
+ {
+ if(pluginList.at(index).state==Semiuncaught)
+ current_state=Semiuncaught;
+ else if(pluginList.at(index).state==Uncaught)
+ found_not_listen=true;
+ else if(pluginList.at(index).state==Caught)
+ found_listen=true;
+ }
+ if(pluginList.at(index).inWaitOfReply)
+ found_inWaitOfReply=true;
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("current_state: %1").arg(current_state));
+ if(current_state==Uncaught)
+ {
+ if(found_not_listen && !found_listen)
+ current_state=Uncaught;
+ else if(!found_not_listen && found_listen)
+ current_state=Caught;
+ else
+ current_state=Semiuncaught;
+ }
+ bool have_plugin=pluginList.size()>0;
+ if(force || current_state!=last_state || have_plugin!=last_have_plugin || found_inWaitOfReply!=last_inWaitOfReply)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("send pluginLoaderReady(%1,%2,%3)").arg(current_state).arg(have_plugin).arg(found_inWaitOfReply));
+ emit pluginLoaderReady(current_state,have_plugin,found_inWaitOfReply);
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Skip the signal sending"));
+ last_state=Uncaught;
+ last_have_plugin=have_plugin;
+ last_inWaitOfReply=found_inWaitOfReply;
+}
+
+void PluginLoader::newState(const CatchState &state)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, state: %1").arg(state));
+ PluginInterface_PluginLoader *temp=qobject_cast<PluginInterface_PluginLoader *>(QObject::sender());
+ if(temp==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("listener not located!"));
+ return;
+ }
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(temp==pluginList.at(index).PluginLoaderInterface)
+ {
+ pluginList[index].state=state;
+ pluginList[index].inWaitOfReply=false;
+ sendState(true);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,QString("listener not found!"));
+}
diff --git a/PluginLoader.h b/PluginLoader.h
new file mode 100755
index 0000000..0632709
--- /dev/null
+++ b/PluginLoader.h
@@ -0,0 +1,79 @@
+/** \file PluginLoader.h
+\brief Define the class to load the plugin and lunch it
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING
+
+This class load ALL plugin compatible to listen and catch the copy/move
+*/
+
+#ifndef PluginLoader_H
+#define PluginLoader_H
+
+#include <QObject>
+#include <QList>
+#include <QPluginLoader>
+#include <QString>
+#include <QStringList>
+
+#include "interface/PluginInterface_PluginLoader.h"
+#include "PluginsManager.h"
+#include "GlobalClass.h"
+
+namespace Ui {
+ class PluginLoaderOptions;
+}
+
+/// \todo PluginLoader -> put plugin by plugin loading to add plugin no reload all
+/// \todo async the plugin call
+
+/** \brief Load the plugin
+
+ It use ResourcesManager(), but it provide more higher abstraction. It parse the plugins information, check it, check the dependancies.
+
+ \see ResourcesManager::ResourcesManager()
+ */
+class PluginLoader : public QObject, GlobalClass
+{
+ Q_OBJECT
+public:
+ explicit PluginLoader(QObject *parent = 0);
+ ~PluginLoader();
+ /** \brief to rended the state */
+ void resendState();
+ /** \brief should load plugin into file manager if needed */
+ void load();
+ /** \brief should unload plugin into file manager */
+ void unload();
+private slots:
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ #ifdef ULTRACOPIER_DEBUG
+ void debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne);
+ #endif // ULTRACOPIER_DEBUG
+ void allPluginIsloaded();
+ void newState(const CatchState &state);
+private:
+ //variable
+ struct LocalPlugin
+ {
+ PluginInterface_PluginLoader * PluginLoaderInterface;
+ QPluginLoader * pluginLoader;
+ CatchState state;
+ QString path;
+ bool inWaitOfReply;
+ LocalPluginOptions *options;
+ };
+ QList<LocalPlugin> pluginList;
+ bool needEnable;
+ //temp variable
+ int index,loop_size;
+ CatchState last_state;
+ bool last_have_plugin,last_inWaitOfReply;
+ void sendState(bool force=false);
+signals:
+ void pluginLoaderReady(CatchState state,bool havePlugin,bool someAreInWaitOfReply);
+};
+
+#endif // PluginLoader_H
diff --git a/PluginsManager.cpp b/PluginsManager.cpp
new file mode 100644
index 0000000..4dc9157
--- /dev/null
+++ b/PluginsManager.cpp
@@ -0,0 +1,889 @@
+/** \file PluginsManager.cpp
+\brief Define the class to manage and load the plugins
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDir>
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QFile>
+#include <QFileInfo>
+
+#include "PluginsManager.h"
+
+/// \brief Create the manager and load the defaults variables
+PluginsManager::PluginsManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the overall instance
+ pluginLoaded=false;
+ resources=ResourcesManager::getInstance();
+ options=OptionEngine::getInstance();
+
+ language="en";
+ stopIt=false;
+ editionSemList.release();
+ checkPluginThread=new AuthPlugin();
+ englishPluginType << "CopyEngine" << "Languages" << "Listener" << "PluginLoader" << "SessionLoader" << "Themes";
+ //catPlugin << tr("CopyEngine") << tr("Languages") << tr("Listener") << tr("PluginLoader") << tr("SessionLoader") << tr("Themes");
+ importingPlugin=false;
+ connect(&decodeThread, SIGNAL(decodedIsFinish()), this, SLOT(decodingFinished()));
+ connect(checkPluginThread, SIGNAL(authentifiedPath(QString)), this, SLOT(newAuthPath(QString)));
+ connect(this, SIGNAL(finished()), this, SLOT(post_operation()));
+ connect(this, SIGNAL(newLanguageLoaded()), &pluginInformationWindows, SLOT(retranslateInformation()));
+// connect(this, SIGNAL(pluginListingIsfinish()), options,SLOT(setInterfaceValue()));
+ //load the plugins list
+ /// \bug bug when I put here: moveToThread(this);, due to the direction connection to remove the plugin
+ start();
+}
+
+/// \brief Destroy the manager
+PluginsManager::~PluginsManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ int loop_size=pluginsList.size();
+ while(index<loop_size)
+ {
+ emit onePluginWillBeUnloaded(pluginsList.at(index));
+ index++;
+ }
+ stopIt=true;
+ if(this->isRunning())
+ this->wait(0);
+ delete checkPluginThread;
+ OptionEngine::destroyInstanceAtTheLastCall();
+ ResourcesManager::destroyInstanceAtTheLastCall();
+}
+
+/// \brief set current language
+void PluginsManager::setLanguage(const QString &language)
+{
+ this->language=language;
+}
+
+void PluginsManager::post_operation()
+{
+ pluginLoaded=true;
+ emit pluginListingIsfinish();
+}
+
+bool PluginsManager::allPluginHaveBeenLoaded()
+{
+ return pluginLoaded;
+}
+
+void PluginsManager::lockPluginListEdition()
+{
+ editionSemList.acquire();
+}
+
+void PluginsManager::unlockPluginListEdition()
+{
+ editionSemList.release();
+}
+
+void PluginsManager::run()
+{
+ //load the path and plugins into the path
+ QStringList readPath;
+ readPath << resources->getReadPath();
+ pluginsList.clear();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"pluginsList.size(): "+QString::number(pluginsList.size()));
+ foreach(QString basePath,readPath)
+ {
+ foreach(QString dirSub,englishPluginType)
+ {
+ QString pluginComposed=basePath+dirSub+QDir::separator();
+ QDir dir(pluginComposed);
+ if(stopIt)
+ return;
+ if(dir.exists())
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"search plugin into: "+pluginComposed);
+ foreach(QString dirName, dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
+ {
+ if(stopIt)
+ return;
+ loadPluginInformation(pluginComposed+dirName+QDir::separator());
+ }
+ }
+ }
+ }
+ #ifdef ULTRACOPIER_DEBUG
+ int index=0;
+ int loop_size=pluginsList.size();
+ while(index<loop_size)
+ {
+ QString category=categoryToString(pluginsList.at(index).category);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Plugin "+QString::number(index)+" loaded ("+category+"): "+pluginsList.at(index).path);
+ index++;
+ }
+ #endif
+ checkPluginThread->loadSearchPath(readPath,englishPluginType);
+ checkPluginThread->stop();
+ checkPluginThread->start();
+ checkDependencies();
+}
+
+QString PluginsManager::categoryToString(const PluginType &category)
+{
+ switch(category)
+ {
+ case PluginType_CopyEngine:
+ return "CopyEngine";
+ break;
+ case PluginType_Languages:
+ return "Languages";
+ break;
+ case PluginType_Listener:
+ return "Listener";
+ break;
+ case PluginType_PluginLoader:
+ return "PluginLoader";
+ break;
+ case PluginType_SessionLoader:
+ return "SessionLoader";
+ break;
+ case PluginType_Themes:
+ return "Themes";
+ break;
+ default:
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"cat text not found");
+ return "Unknow";
+ break;
+ }
+}
+
+QString PluginsManager::categoryToTranslation(const PluginType &category)
+{
+ return pluginInformationWindows.categoryToTranslation(category);
+}
+
+bool PluginsManager::isSamePlugin(const PluginsAvailable &pluginA,const PluginsAvailable &pluginB)
+{
+ if(pluginA.category!=pluginB.category)
+ return false;
+ if(pluginA.path!=pluginB.path)
+ return false;
+ if(pluginA.name!=pluginB.name)
+ return false;
+ if(pluginA.writablePath!=pluginB.writablePath)
+ return false;
+ if(pluginA.categorySpecific!=pluginB.categorySpecific)
+ return false;
+ if(pluginA.version!=pluginB.version)
+ return false;
+ if(pluginA.informations!=pluginB.informations)
+ return false;
+ return true;
+}
+
+bool PluginsManager::loadPluginInformation(const QString &path)
+{
+ PluginsAvailable tempPlugin;
+ tempPlugin.isAuth = false;
+ tempPlugin.path = path;
+ tempPlugin.category = PluginType_Unknow;
+ QDir pluginPath(path);
+ if(pluginPath.cdUp() && pluginPath.cdUp() &&
+ resources->getWritablePath()!="" &&
+ pluginPath==QDir(resources->getWritablePath()))
+ tempPlugin.isWritable=true;
+ else
+ tempPlugin.isWritable=false;
+ QFile xmlMetaData(path+"informations.xml");
+ if(xmlMetaData.exists())
+ {
+ if(xmlMetaData.open(QIODevice::ReadOnly))
+ {
+ loadPluginXml(&tempPlugin,xmlMetaData.readAll());
+ xmlMetaData.close();
+ }
+ else
+ {
+ tempPlugin.errorString=tr("informations.xml is not accessible");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"informations.xml is not accessible into the plugin: "+path);
+ }
+ }
+ else
+ {
+ tempPlugin.errorString=tr("informations.xml not found into the plugin");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"informations.xml not found into the plugin: "+path);
+ }
+ editionSemList.acquire();
+ pluginsList << tempPlugin;
+ editionSemList.release();
+ if(tempPlugin.errorString=="")
+ {
+ emit onePluginAdded(tempPlugin);
+ return true;
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Error detected, the not loaded: "+tempPlugin.errorString+", for path: "+tempPlugin.path);
+ return false;
+ }
+}
+
+void PluginsManager::loadPluginXml(PluginsAvailable * thePlugin,const QByteArray &xml)
+{
+ QString errorStr;
+ int errorLine;
+ int errorColumn;
+ QDomDocument domDocument;
+ if (!domDocument.setContent(xml, false, &errorStr,&errorLine,&errorColumn))
+ {
+ thePlugin->errorString=tr("%1, parse error at line %2, column %3: %4").arg("informations.xml").arg(errorLine).arg(errorColumn).arg(errorStr);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("%1, Parse error at line %2, column %3: %4").arg("informations.xml").arg(errorLine).arg(errorColumn).arg(errorStr));
+ }
+ else
+ {
+ QDomElement root = domDocument.documentElement();
+ if (root.tagName() != "package")
+ {
+ thePlugin->errorString=tr("\"package\" root tag not found for the xml file");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"\"package\" root balise not found for the xml file");
+ }
+ //load the variable
+ if(thePlugin->errorString=="")
+ loadBalise(root,"title",&(thePlugin->informations),&(thePlugin->errorString),true,true,true);
+ if(thePlugin->errorString=="")
+ loadBalise(root,"website",&(thePlugin->informations),&(thePlugin->errorString),false,true);
+ if(thePlugin->errorString=="")
+ loadBalise(root,"description",&(thePlugin->informations),&(thePlugin->errorString),true,true,true);
+ if(thePlugin->errorString=="")
+ loadBalise(root,"author",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ loadBalise(root,"pubDate",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ {
+ loadBalise(root,"version",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ thePlugin->version=thePlugin->informations.last().last();
+ }
+ if(thePlugin->errorString=="")
+ {
+ loadBalise(root,"category",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ {
+ QString tempCat=thePlugin->informations.last().last();
+ if(tempCat=="Languages")
+ thePlugin->category=PluginType_Languages;
+ else if(tempCat=="CopyEngine")
+ thePlugin->category=PluginType_CopyEngine;
+ else if(tempCat=="Listener")
+ thePlugin->category=PluginType_Listener;
+ else if(tempCat=="PluginLoader")
+ thePlugin->category=PluginType_PluginLoader;
+ else if(tempCat=="SessionLoader")
+ thePlugin->category=PluginType_SessionLoader;
+ else if(tempCat=="Themes")
+ thePlugin->category=PluginType_Themes;
+ else
+ thePlugin->errorString="Unknow category: "+(int)thePlugin->category;
+ if(thePlugin->errorString.isEmpty())
+ {
+ if(thePlugin->category!=PluginType_Languages)
+ {
+ loadBalise(root,"architecture",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ {
+ #ifndef ULTRACOPIER_VERSION_PORTABLE
+ if(thePlugin->informations.last().last()!=ULTRACOPIER_PLATFORM_CODE)
+ thePlugin->errorString="Wrong platform code: "+thePlugin->informations.last().last();
+ #endif
+ }
+ }
+ }
+ }
+ }
+ if(thePlugin->errorString=="")
+ {
+ loadBalise(root,"name",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ {
+ thePlugin->name=thePlugin->informations.last().last();
+ int index=0;
+ int loop_size=pluginsList.size();
+ int sub_index,loop_sub_size;
+ while(index<loop_size)
+ {
+ sub_index=0;
+ loop_sub_size=pluginsList.at(index).informations.size();
+ while(sub_index<loop_sub_size)
+ {
+ if(pluginsList.at(index).informations.at(sub_index).first()=="name" &&
+ pluginsList.at(index).name==thePlugin->name &&
+ pluginsList.at(index).category==thePlugin->category)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Plugin duplicate found ("+QString::number((int)thePlugin->category)+"/"+pluginsList.at(index).informations.at(sub_index).last()+"), already loaded, actual version skipped: "+thePlugin->version);
+ thePlugin->errorString=tr("Duplicated plugin found, already loaded!");
+ break;
+ break;
+ }
+ sub_index++;
+ }
+ index++;
+ }
+ }
+ }
+ if(thePlugin->errorString=="")
+ loadBalise(root,"dependencies",&(thePlugin->informations),&(thePlugin->errorString),true,false);
+ if(thePlugin->errorString=="")
+ {
+ QDomElement child = root.firstChildElement("categorySpecific");
+ if(!child.isNull() && child.isElement())
+ thePlugin->categorySpecific=child;
+ }
+ }
+}
+
+/// \brief to load the multi-language balise
+void PluginsManager::loadBalise(const QDomElement &root,const QString &name,QList<QStringList> *informations,QString *errorString,bool needHaveOneEntryMinimum,bool multiLanguage,bool englishNeedBeFound)
+{
+ int foundElement=0;
+ bool englishTextIsFoundForThisChild=false;
+ QDomElement child = root.firstChildElement(name);
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ {
+ QStringList newInformations;
+ if(multiLanguage)
+ {
+ if(child.hasAttribute("xml:lang"))
+ {
+ if(child.attribute("xml:lang")=="en")
+ englishTextIsFoundForThisChild=true;
+ foundElement++;
+ newInformations << child.tagName() << child.attribute("xml:lang") << child.text();
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Have not the attribute xml:lang: child.tagName(): %1, child.text(): %2").arg(child.tagName()).arg(child.text()));
+ }
+ else
+ {
+ foundElement++;
+ newInformations << child.tagName() << child.text();
+ }
+ *informations << newInformations;
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Is not Element: child.tagName(): %1").arg(child.tagName()));
+ child = child.nextSiblingElement(name);
+ }
+ if(multiLanguage && englishTextIsFoundForThisChild==false && englishNeedBeFound)
+ {
+ informations->clear();
+ *errorString=tr("English text missing into the informations.xml for the tag: %1").arg(name);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("English text missing into the informations.xml for the tag: %1").arg(name));
+ return;
+ }
+ if(needHaveOneEntryMinimum && foundElement==0)
+ {
+ informations->clear();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Tag not found: %1").arg(name));
+ *errorString=tr("Tag not found: %1").arg(name);
+ }
+}
+
+/// \brief to load the get dom specific
+QString PluginsManager::getDomSpecific(const QDomElement &root,const QString &name,const QList<QPair<QString,QString> > &listChildAttribute)
+{
+ QDomElement child = root.firstChildElement(name);
+ int index,loop_size;
+ bool allIsFound;
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ {
+ allIsFound=true;
+ index=0;
+ loop_size=listChildAttribute.size();
+ while(index<loop_size)
+ {
+ if(child.attribute(listChildAttribute.at(index).first)!=listChildAttribute.at(index).second)
+ {
+ allIsFound=false;
+ break;
+ }
+ index++;
+ }
+ if(allIsFound)
+ return child.text();
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Is not Element: child.tagName(): %1").arg(child.tagName()));
+ child = child.nextSiblingElement(name);
+ }
+ return QString();
+}
+
+/// \brief to load the get dom specific
+QString PluginsManager::getDomSpecific(const QDomElement &root,const QString &name)
+{
+ QDomElement child = root.firstChildElement(name);
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ return child.text();
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Is not Element: child.tagName(): %1").arg(child.tagName()));
+ child = child.nextSiblingElement(name);
+ }
+ return QString();
+}
+
+/// \brief check the dependencies
+void PluginsManager::checkDependencies()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ int loop_size=pluginsList.size();
+ int sub_index,loop_sub_size,resolv_size,indexOfDependencies;
+ bool depCheck;
+ while(index<loop_size)
+ {
+ sub_index=0;
+ loop_sub_size=pluginsList.at(index).informations.size();
+ while(sub_index<loop_sub_size)
+ {
+ if(pluginsList.at(index).informations.at(sub_index).size()==2 && pluginsList.at(index).informations.at(sub_index).at(0)=="dependencies")
+ {
+ QString dependencies=pluginsList.at(index).informations.at(sub_index).at(1);
+ dependencies=dependencies.replace(QRegExp("[\n\r]+"),"&&");
+ dependencies=dependencies.replace(QRegExp("[ \t]+"),"");
+ dependencies=dependencies.replace(QRegExp("(&&)+"),"&&");
+ dependencies=dependencies.replace(QRegExp("^&&"),"");
+ dependencies=dependencies.replace(QRegExp("&&$"),"");
+ QStringList dependenciesToResolv=dependencies.split(QRegExp("(&&|\\|\\||\\(|\\))"),QString::SkipEmptyParts);
+ indexOfDependencies=0;
+ resolv_size=dependenciesToResolv.size();
+ while(indexOfDependencies<resolv_size)
+ {
+ QString dependenciesToParse=dependenciesToResolv.at(indexOfDependencies);
+ if(!dependenciesToParse.contains(QRegExp("^(<=|<|=|>|>=)[a-zA-Z0-9\\-]+-([0-9]+\\.)*[0-9]+$")))
+ {
+ pluginsList[index].informations.clear();
+ pluginsList[index].errorString=tr("Dependencies part is wrong");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Dependencies part is wrong: %1").arg(dependenciesToParse));
+ break;
+ }
+ QString partName=dependenciesToParse;
+ partName=partName.remove(QRegExp("(<=|<|=|>|>=)"));
+ partName=partName.remove(QRegExp("-([0-9]+\\.)*[0-9]+"));
+ QString partVersion=dependenciesToParse;
+ partVersion=partVersion.remove(QRegExp("(<=|<|=|>|>=)"));
+ partVersion=partVersion.remove(QRegExp("[a-zA-Z0-9\\-]+-"));
+ QString partComp=dependenciesToParse;
+ partComp=partComp.remove(QRegExp("[a-zA-Z0-9\\-]+-([0-9]+\\.)*[0-9]+"));
+ //current version soft
+ QString pluginVersion=getPluginVersion(partName);
+ depCheck=compareVersion(pluginVersion,partComp,partVersion);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"dependencies to resolv, partName: "+partName+", partVersion: "+partVersion+", partComp: "+partComp+", pluginVersion: "+pluginVersion+", depCheck: "+QString::number(depCheck));
+ if(!depCheck)
+ {
+ pluginsList[index].informations.clear();
+ pluginsList[index].errorString=tr("Dependencies %1 are not satisfied, for plugin: %2").arg(dependenciesToParse).arg(pluginsList[index].path);
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Dependencies %1 are not satisfied, for plugin: %2").arg(dependenciesToParse).arg(pluginsList[index].path));
+ break;
+ }
+ indexOfDependencies++;
+ }
+ }
+ sub_index++;
+ }
+ index++;
+ }
+}
+
+/// \brief get the version
+QString PluginsManager::getPluginVersion(const QString &pluginName)
+{
+ if(pluginName=="ultracopier")
+ return ULTRACOPIER_VERSION;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginsList.size())
+ {
+ QString version,internalName;
+ int sub_index=0;
+ while(sub_index<pluginsList.at(index).informations.size())
+ {
+ if(pluginsList.at(index).informations.at(sub_index).size()==2 && pluginsList.at(index).informations.at(sub_index).at(0)=="version")
+ version=pluginsList.at(index).informations.at(sub_index).at(1);
+ if(pluginsList.at(index).informations.at(sub_index).size()==2 && pluginsList.at(index).informations.at(sub_index).at(0)=="internalName")
+ internalName=pluginsList.at(index).informations.at(sub_index).at(1);
+ sub_index++;
+ }
+ if(internalName==pluginName)
+ return version;
+ index++;
+ }
+ return "";
+}
+
+/// \brief To compare version
+bool PluginsManager::compareVersion(const QString &versionA,const QString &sign,const QString &versionB)
+{
+ QStringList versionANumber=versionA.split(".");
+ QStringList versionBNumber=versionB.split(".");
+ int index=0;
+ int defaultReturnValue=true;
+ if(sign=="<")
+ defaultReturnValue=false;
+ if(sign==">")
+ defaultReturnValue=false;
+ while(index<versionANumber.size() && index<versionBNumber.size())
+ {
+ unsigned int reaNumberA=versionANumber.at(index).toUInt();
+ unsigned int reaNumberB=versionBNumber.at(index).toUInt();
+ if(sign=="=" && reaNumberA!=reaNumberB)
+ return false;
+ if(sign=="<")
+ {
+ if(reaNumberA>reaNumberB)
+ return false;
+ if(reaNumberA<reaNumberB)
+ return true;
+ }
+ if(sign==">")
+ {
+ if(reaNumberA<reaNumberB)
+ return false;
+ if(reaNumberA>reaNumberB)
+ return true;
+ }
+ if(sign=="<=")
+ {
+ if(reaNumberA>reaNumberB)
+ return false;
+ if(reaNumberA<reaNumberB)
+ return true;
+ }
+ if(sign==">=")
+ {
+ if(reaNumberA<reaNumberB)
+ return false;
+ if(reaNumberA>reaNumberB)
+ return true;
+ }
+ index++;
+ }
+ return defaultReturnValue;
+}
+
+QList<PluginsAvailable> PluginsManager::getPluginsByCategory(const PluginType &category)
+{
+ QList<PluginsAvailable> list;
+ int index=0,loop_size=pluginsList.size();
+ while(index<loop_size)
+ {
+ if(pluginsList.at(index).category==category && pluginsList.at(index).errorString=="")
+ list<<pluginsList.at(index);
+ index++;
+ }
+ return list;
+}
+
+QList<PluginsAvailable> PluginsManager::getPlugins()
+{
+ QList<PluginsAvailable> list;
+ int index=0;
+ while(index<pluginsList.size())
+ {
+ if(pluginsList.at(index).errorString=="")
+ list<<pluginsList.at(index);
+ index++;
+ }
+ return list;
+}
+
+/// \brief show the information
+/// \todo pass plugin info
+void PluginsManager::showInformation(const QString &path)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginsList.size())
+ {
+ if(pluginsList.at(index).path==path)
+ {
+ pluginInformationWindows.setLanguage(mainShortName);
+ pluginInformationWindows.setPlugin(pluginsList.at(index));
+ pluginInformationWindows.show();
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"item not selected");
+}
+
+void PluginsManager::showInformationDoubleClick()
+{
+// showInformation(false);
+}
+
+void PluginsManager::removeThePluginSelected(const QString &path)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginsList.size())
+ {
+ if(pluginsList.at(index).path==path)
+ {
+ QMessageBox::StandardButton reply;
+ /// \todo check if previous version as internal, if yes ask if switch to it, else remove and do marked to disable the internal version too
+ // if(pluginsList.at(index).internalVersionAlternative.isEmpty())
+ reply = QMessageBox::question(NULL,tr("Remove %1").arg(pluginsList.at(index).name),tr("Are you sure about removing \"%1\" in version %2?").arg(pluginsList.at(index).name).arg(pluginsList.at(index).version),QMessageBox::Yes|QMessageBox::No,QMessageBox::No);
+ // else
+ // reply = QMessageBox::question(NULL,tr("Remove %1").arg(getTranslatedText(pluginsList.at(index),"name",mainShortName)),tr("Are you sure to wish remove \"%1\" in version %2 for the internal version %3?").arg(getTranslatedText(pluginsList.at(index),"name",mainShortName)).arg(pluginsList.at(index).version).arg(pluginsList.at(index).internalVersionAlternative),QMessageBox::Yes|QMessageBox::No,QMessageBox::No);
+ if(reply==QMessageBox::Yes)
+ {
+ emit onePluginWillBeUnloaded(pluginsList.at(index));
+ emit onePluginWillBeRemoved(pluginsList.at(index));
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"remove plugin at this path: "+pluginsList.at(index).path);
+ if(!ResourcesManager::removeFolder(pluginsList.at(index).path))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to remove the plugin");
+ QMessageBox::critical(NULL,tr("Error"),tr("Error while the removing plugin, please check right of remove on the folder: \n%1").arg(pluginsList.at(index).path));
+ }
+ pluginsList.removeAt(index);
+ checkDependencies();
+ }
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"item not selected");
+}
+
+void PluginsManager::addPlugin(const ImportBackend &backend)
+{
+ if(backend==ImportBackend_File)
+ excuteTheFileBackendLoader();
+}
+
+void PluginsManager::excuteTheFileBackendLoader()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ if(importingPlugin)
+ {
+ QMessageBox::information(NULL,tr("Information"),tr("Previous import is in progress..."));
+ return;
+ }
+ QString fileName = QFileDialog::getOpenFileName(NULL,tr("Open Ultracopier plugin"),QString(),tr("Ultracopier plugin (*.urc)"));
+ if(fileName!="")
+ {
+ QFile temp(fileName);
+ if(temp.open(QIODevice::ReadOnly))
+ {
+ importingPlugin=true;
+ lunchDecodeThread(temp.readAll());
+ temp.close();
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"unable to open the file: "+temp.errorString());
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to open the plugin: %1").arg(temp.errorString()));
+ }
+ }
+}
+
+void PluginsManager::lunchDecodeThread(const QByteArray &data)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ decodeThread.setData(data);
+ decodeThread.start(QThread::LowestPriority);
+}
+
+void PluginsManager::decodingFinished()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ if(!decodeThread.errorFound())
+ {
+ QByteArray data=decodeThread.decodedData();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"data.size(): "+QString::number(data.size()));
+ QTarDecode tarFile;
+ if(!tarFile.decodeData(data))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"tarFile.errorString(): "+tarFile.errorString());
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it: %1").arg(tarFile.errorString()));
+ }
+ else
+ {
+ QStringList fileList = tarFile.getFileList();
+ QList<QByteArray> dataList = tarFile.getDataList();
+ if(fileList.size()>1)
+ {
+ QString basePluginArchive="";
+ /* block use less for tar?
+ if(fileList.at(0).contains(QRegExp("[\\/]")))
+ {
+ bool folderFoundEveryWhere=true;
+ basePluginArchive=fileList.at(0);
+ basePluginArchive.remove(QRegExp("[\\/].*$"));
+ for (int i = 0; i < list.size(); ++i)
+ {
+ if(!fileList.at(i).startsWith(basePluginArchive))
+ {
+ folderFoundEveryWhere=false;
+ break;
+ }
+ }
+ if(folderFoundEveryWhere)
+ {
+ for (int i = 0; i < fileList.size(); ++i)
+ fileList[i].remove(0,basePluginArchive.size());
+ }
+ else
+ basePluginArchive="";
+ }*/
+ PluginsAvailable tempPlugin;
+ QString categoryFinal="";
+ for (int i = 0; i < fileList.size(); ++i)
+ if(fileList.at(i)=="informations.xml")
+ {
+ loadPluginXml(&tempPlugin,dataList.at(i));
+ break;
+ }
+ if(tempPlugin.errorString=="")
+ {
+ categoryFinal=categoryToString(tempPlugin.category);
+ if(categoryFinal!="")
+ {
+ QString writablePath=resources->getWritablePath();
+ if(writablePath!="")
+ {
+ QDir dir;
+ QString finalPluginPath=writablePath+categoryFinal+QDir::separator()+tempPlugin.name+QDir::separator();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"writablePath: \""+writablePath+"\"");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"basePluginArchive: \""+basePluginArchive+"\"");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"categoryFinal: \""+categoryFinal+"\"");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"finalPluginPath: \""+finalPluginPath+"\"");
+ if(!dir.exists(finalPluginPath))
+ {
+ bool errorFound=false;
+ for (int i = 0; i < fileList.size(); ++i)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"file "+QString::number(i)+": "+finalPluginPath+fileList.at(i));
+ fileList[i].remove(QRegExp("^(..?[\\/])+"));
+ QFile currentFile(finalPluginPath+fileList.at(i));
+ QFileInfo info(currentFile);
+ if(!dir.exists(info.absolutePath()))
+ if(!dir.mkpath(info.absolutePath()))
+ {
+ resources->disableWritablePath();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Unable to make the path: "+info.absolutePath());
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to create a folder to install the plugin:\n%1").arg(info.absolutePath()));
+ errorFound=true;
+ break;
+ }
+ if(currentFile.open(QIODevice::ReadWrite))
+ {
+ currentFile.write(dataList.at(i));
+ currentFile.close();
+ }
+ else
+ {
+ resources->disableWritablePath();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Unable to make the file: "+info.absolutePath()+", error:"+currentFile.errorString());
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to create a file to install the plugin:\n%1\nsince:%2").arg(info.absolutePath()).arg(currentFile.errorString()));
+ errorFound=true;
+ break;
+ }
+ }
+ if(!errorFound)
+ {
+ if(loadPluginInformation(finalPluginPath))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"push the new plugin into the real list");
+ checkDependencies();
+ emit needLangToRefreshPluginList();
+ }
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Folder with same name is present, skip the plugin installation: "+finalPluginPath);
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Folder with same name is present, skip the plugin installation:\n%1").arg(finalPluginPath));
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"Have not writable path, then how add you plugin?");
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it"));
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"category into informations.xml not found!");
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it"));
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"Error in the xml: "+tempPlugin.errorString);
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it: %1").arg(tempPlugin.errorString));
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"No file found into the plugin");
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it"));
+ }
+ }
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"decodeThread.errorFound(), error: "+decodeThread.errorString());
+ QMessageBox::critical(NULL,tr("Plugin loader"),tr("Unable to load the plugin content, please check it: %1").arg(decodeThread.errorString()));
+ }
+ importingPlugin=false;
+}
+
+void PluginsManager::newAuthPath(const QString &path)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginsList.size())
+ {
+ if(pluginsList.at(index).path==path)
+ {
+ pluginsList[index].isAuth=true;
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"plugin not located");
+}
+
+/// \brief transfor short plugin name into file name
+QString PluginsManager::getResolvedPluginName(const QString &name)
+{
+ #if defined(Q_OS_LINUX)
+ return "lib"+name+".so";
+ #elif defined(Q_OS_MAC)
+ #if defined(QT_DEBUG)
+ return "lib"+name+"_debug.dylib";
+ #else
+ return "lib"+name+".dylib";
+ #endif
+ #elif defined(Q_OS_WIN32)
+ #if defined(QT_DEBUG)
+ return name+"d.dll";
+ #else
+ return name+".dll";
+ #endif
+ #else
+ #error "Platform not supported"
+ #endif
+}
+
+bool operator==(PluginsAvailable pluginA,PluginsAvailable pluginB)
+{
+ return PluginsManager::isSamePlugin(pluginA,pluginB);
+}
diff --git a/PluginsManager.h b/PluginsManager.h
new file mode 100644
index 0000000..0283279
--- /dev/null
+++ b/PluginsManager.h
@@ -0,0 +1,147 @@
+/** \file PluginsManager.h
+\brief Define the class to manage and load the plugins
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef PLUGINS_MANAGER_H
+#define PLUGINS_MANAGER_H
+
+#include <QObject>
+#include <QList>
+#include <QStringList>
+#include <QDomElement>
+#include <QDomDocument>
+#include <QDomNode>
+#include <QTreeWidgetItem>
+#include <QDateTime>
+#include <QAction>
+#include <QMenu>
+#include <QCryptographicHash>
+#include <QString>
+#include <QSemaphore>
+
+#include "Environment.h"
+#include "Singleton.h"
+#include "OptionEngine.h"
+#include "ResourcesManager.h"
+#include "PluginInformation.h"
+#include "QXzDecodeThread.h"
+#include "QTarDecode.h"
+#include "AuthPlugin.h"
+
+namespace Ui {
+ class PluginOptions;
+}
+
+/** \brief Define the class to manage and load the resources linked with the themes
+
+This class provide a core load and manage the resources */
+class PluginsManager : public QThread, public Singleton<PluginsManager>
+{
+ Q_OBJECT
+ friend class Singleton<PluginsManager>;
+ public:
+ /// \brief to get plugins of type specific
+ QList<PluginsAvailable> getPluginsByCategory(const PluginType &type);
+ /** \brief to get plugins
+ \todo check where is used to convert to PluginsAvailable
+ */
+ QList<PluginsAvailable> getPlugins();
+ /// \brief get translated text
+ //QString getTranslatedText(PluginsAvailable plugin,QString informationName,QString mainShortName);
+ //QString getTranslatedText(PluginsAvailable plugin,QString informationName);
+ /// \brief transform short plugin name into file name
+ static QString getResolvedPluginName(const QString &name);
+ static bool isSamePlugin(const PluginsAvailable &pluginA,const PluginsAvailable &pluginB);
+ void lockPluginListEdition();
+ void unlockPluginListEdition();
+ bool allPluginHaveBeenLoaded();
+ /// \brief to load the get dom specific
+ QString getDomSpecific(const QDomElement &root,const QString &name,const QList<QPair<QString,QString> > &listChildAttribute);
+ QString getDomSpecific(const QDomElement &root,const QString &name);
+ /// \brief set current language
+ void setLanguage(const QString &language);
+ /// \brief Enumeration of plugin add backend
+ enum ImportBackend
+ {
+ ImportBackend_File, //import plugin from local file
+ ImportBackend_Internet //import plugin form internet
+ };
+ private:
+ /// \brief Create the manager and load the defaults variables
+ PluginsManager();
+ /// \brief Destroy the language manager
+ ~PluginsManager();
+ /// \brief get informations text
+ //QString getInformationText(PluginsAvailable plugin,QString informationName);
+ //for the options
+ OptionEngine *options;
+ /// \brief Store the object of resources manager
+ ResourcesManager *resources;
+ /// \brief List of plugins
+ QList<PluginsAvailable> pluginsList;
+ /// \brief to load the multi-language balise
+ void loadBalise(const QDomElement &root,const QString &name,QList<QStringList> *informations,QString *errorString,bool needHaveOneEntryMinimum=true,bool multiLanguage=false,bool englishNeedBeFound=false);
+ /// \brief check the dependencies
+ void checkDependencies();
+ /// \brief get the version
+ QString getPluginVersion(const QString &pluginName);
+ /// \brief To compare version
+ bool compareVersion(const QString &versionA,const QString &sign,const QString &versionB);
+ /// \brief plugin information windows
+ PluginInformation pluginInformationWindows;
+ /// \brief list of cat plugin type
+ //QStringList catPlugin;
+ QStringList englishPluginType;
+ QList<QTreeWidgetItem *> catItemList;
+ /// \brief store the current mainShortName
+ QString mainShortName;
+ /// \brief load the plugin list
+ void loadPluginList();
+ QAction *backendMenuFile; ///< Pointer on the file backend menu
+ bool importingPlugin;
+ void lunchDecodeThread(const QByteArray &data);
+ QXzDecodeThread decodeThread;
+ void loadPluginXml(PluginsAvailable * thePlugin,const QByteArray &xml);
+ AuthPlugin *checkPluginThread;
+ QStringList readPluginPath;
+ bool loadPluginInformation(const QString &path);
+ QSemaphore editionSemList;
+ bool stopIt;
+ bool pluginLoaded;
+ QString language;
+ void excuteTheFileBackendLoader();
+ QString categoryToString(const PluginType &category);
+ QString categoryToTranslation(const PluginType &category);
+ //temp variable
+ int index,loop_size,sub_index,loop_sub_size;
+ private slots:
+ /// \brief show the information
+ void showInformationDoubleClick();
+ void decodingFinished();
+ void newAuthPath(const QString &path);
+ void post_operation();
+/* public slots:
+ /// \brief to refresh the plugin list
+ void refreshPluginList(QString mainShortName="en");*/
+ signals:
+ void pluginListingIsfinish();
+ void onePluginAdded(const PluginsAvailable&);
+ void onePluginWillBeRemoved(const PluginsAvailable&); // when will be really removed
+ void onePluginWillBeUnloaded(const PluginsAvailable&);//just unload to quit the application
+ void needLangToRefreshPluginList();
+ void newLanguageLoaded();
+ protected:
+ void run();
+ public slots: //do gui action
+ void showInformation(const QString &path);
+ void removeThePluginSelected(const QString &path);
+ void addPlugin(const ImportBackend &backend);
+};
+
+/// \brief to do structure comparaison
+bool operator==(PluginsAvailable pluginA,PluginsAvailable pluginB);
+
+#endif // PLUGINS_MANAGER_H
diff --git a/README b/README
new file mode 100644
index 0000000..95a8b19
--- /dev/null
+++ b/README
@@ -0,0 +1,56 @@
+=======================================================
+Description ===========================================
+=======================================================
+
+Ultracopier (http://ultracopier.first-world.info/) is free and open
+source software licensed under GPL3 that acts as a replacement for
+files copy dialogs.
+
+Main features include:
+ - pause/resume transfers
+ - dynamic speed limitation
+ - on-error resume,
+ - error/collision management
+
+=======================================================
+License ===============================================
+=======================================================
+Ultracopier is licensed under the GNU General Public License version 3.
+The text of the GNU General Public License can be viewed at http://www.gnu.org/licenses/gpl.html
+See COPYING file.
+
+=======================================================
+Core Developers =======================================
+=======================================================
+BRULE Herman or alpha_one_x86 <ultracopier@first-world.info>
+- Original author, API, kio_slaves, source
+See the Development team section of http://ultracopier.first-world.info/contact.html for an updated list of Ultracopier team!
+
+=======================================================
+Building and documentation ============================
+=======================================================
+See the wiki for the general documentation and how to for building: http://ultracopier-wiki.first-world.info/
+For the code documentation: http://doc-ultracopier.first-world.info/ (generated by doxygen)
+The source proposed on the site is reconstritued source from: https://github.com/alphaonex86/Ultracopier to facilitate contribute effort.
+
+=======================================================
+Licence for the source ================================
+=======================================================
+All images into resources/ is extracted from the oxygen pack of KDE 4.8. Some are directly remaked from the png version.
+*.ts and *.qm into resources/ or plugins/Languages/ is under GPL3.
+All images into plugins/Languages/ are extracted from piwik.
+All informations.xml into plugins/Languages/ are under GPL3.
+All the file *.dox *.h *.cpp *.pro *.ui at the root, interface/ folder of the source are under GPL3.
+The files: QTarDecode.cpp, QTarDecode.h, QXzDecode.cpp,
+QXzDecode.h, QXzDecodeThread.cpp, QXzDecodeThread.h into: lib/qt-tar-xz/ are under GPL3.
+The other file into lib/qt-tar-xz/ is XZ Embedded.
+All *.qrc into resources/ are under GPL3.
+
+======================================================
+Licensing of XZ Embedded =============================
+======================================================
+
+All the files in this package have been written by Lasse Collin
+and/or Igor Pavlov. All these files have been put into the
+public domain. You can do whatever you want with these files.
+As usual, this software is provided "as is", without any warranty.
diff --git a/ResourcesManager.cpp b/ResourcesManager.cpp
new file mode 100644
index 0000000..008bf50
--- /dev/null
+++ b/ResourcesManager.cpp
@@ -0,0 +1,210 @@
+/** \file ResourcesManager.cpp
+\brief Define the class to manage and load the resources linked with the themes
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QDir>
+#include <QFile>
+#include <QApplication>
+#include <QFSFileEngine>
+#include <QFileInfo>
+
+
+#include "ResourcesManager.h"
+
+/// \brief Create the manager and load the defaults variables
+ResourcesManager::ResourcesManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the internal path
+ searchPath<<QString(":/");
+ //load the user path but only if exists and writable
+ //load the ultracopier path
+ #ifdef ULTRACOPIER_VERSION_PORTABLE
+ #ifdef ULTRACOPIER_VERSION_PORTABLEAPPS
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Ultracopier is compiled with the flag: ULTRACOPIER_VERSION_PORTABLEAPPS");
+ //load the data folder path
+ QDir dir(QApplication::applicationDirPath());
+ dir.cdUp();
+ dir.cdUp();
+ dir.cd("Data");
+ searchPath<<ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ writablePath=ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ #else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Ultracopier is compiled with the flag: ULTRACOPIER_VERSION_PORTABLE");
+ //load the ultracopier path
+ QDir dir(QApplication::applicationDirPath());
+ dir.cd("Data");
+ searchPath<<ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ writablePath=ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ #endif
+ #else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"Ultracopier is compiled as user privacy mode");
+ #ifdef Q_OS_WIN32
+ #define EXTRA_HOME_PATH "\\ultracopier\\"
+ #else
+ #define EXTRA_HOME_PATH "/.config/Ultracopier/"
+ #endif
+ #ifdef Q_OS_LINUX
+ QDir linuxDir("/usr/share/ultracopier/");
+ if(linuxDir.exists())
+ searchPath<<"/usr/share/ultracopier/";
+ #endif
+ //load the user path but only if exists and writable
+ QDir dir(QFSFileEngine::homePath()+EXTRA_HOME_PATH);
+ if(dir.exists())
+ {
+ writablePath=ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ searchPath<<ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ } //if not exists try to create it
+ else if(dir.mkpath(dir.absolutePath()))
+ {
+ //if created, then have write permissions
+ writablePath=ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ searchPath<<ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ }
+ //load the ultracopier path
+ searchPath<<ResourcesManager::AddSlashIfNeeded(QApplication::applicationDirPath());
+ #endif
+ searchPath.removeDuplicates();
+ #ifdef ULTRACOPIER_DEBUG
+ index=0;
+ loop_size=searchPath.size();
+ while(index<loop_size) //look at each val
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"searchPath.at("+QString::number(index)+"): "+searchPath.at(index));
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Information,"writablePath: "+writablePath);
+ #endif // ULTRACOPIER_DEBUG
+}
+
+/// \brief Destroy the resource manager
+ResourcesManager::~ResourcesManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+}
+
+/// \brief Get folder presence and the path
+QString ResourcesManager::getFolderReadPath(const QString &path)
+{
+ index=0;
+ loop_size=searchPath.size();
+ while(index<loop_size) //look at each val
+ {
+ QDir dir(searchPath.at(index)+path);
+ if(dir.exists()) // if the path have been found, then return the full path
+ return ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ index++;
+ }
+ return "";
+}
+
+/// \brief Get folder presence, the path and check in the folder and sub-folder the file presence
+QString ResourcesManager::getFolderReadPathMultiple(const QString &path,const QStringList &fileToCheck)
+{
+ index=0;
+ loop_size=searchPath.size();
+ while(index<loop_size) //look at each val
+ {
+ QDir dir(searchPath.at(index)+path);
+ if(checkFolderContent(dir.absolutePath(),fileToCheck))
+ return dir.absolutePath()+QDir::separator();
+ index++;
+ }
+ return "";
+}
+
+bool ResourcesManager::checkFolderContent(const QString &path,const QStringList &fileToCheck)
+{
+ QDir dir(path);
+ if(dir.exists()) // if the path have been found, then return the full path
+ {
+ bool allFileToCheckIsFound=true;
+ index=0;
+ loop_size=fileToCheck.size();
+ QString partialPath=ResourcesManager::AddSlashIfNeeded(dir.absolutePath());
+ while(index<loop_size) //look at each val
+ {
+ if(!QFile::exists(partialPath+fileToCheck.at(index))) //if a file have been not found, consider the folder as not suitable
+ {
+ allFileToCheckIsFound=false;
+ break;
+ }
+ index++;
+ }
+ if(allFileToCheckIsFound==true) // if all file into have been found then return this path
+ return true;
+ }
+ return false;
+}
+
+/// \brief add / or \ in function of the platform at the end of path if both / and \ are not found
+QString ResourcesManager::AddSlashIfNeeded(const QString &path)
+{
+ if(path.contains(QRegExp("[/\\\\]$")))
+ return path;
+ else
+ return path+QDir::separator();
+}
+
+/// \brief get the writable path
+QString ResourcesManager::getWritablePath()
+{
+ return writablePath;
+}
+
+/// \brief disable the writable path, if ultracopier is unable to write into
+bool ResourcesManager::disableWritablePath()
+{
+ bool returnVal=true;
+ if(writablePath=="")
+ returnVal=false;
+ else
+ writablePath="";
+ return returnVal;
+}
+
+/// \brief get the read path
+QStringList ResourcesManager::getReadPath()
+{
+ return searchPath;
+}
+
+/// \brief remove folder
+bool ResourcesManager::removeFolder(const QString &dir)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"folder to remove: "+dir);
+ bool errorFound=false;
+ QDir currentDir(dir);
+ QFileInfoList files = currentDir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+ int index=0;
+ int loop_size=files.size();
+ while(index<loop_size)
+ {
+ if(files.at(index).isFile())
+ {
+ QFile file(files.at(index).absoluteFilePath());
+ if(!file.remove())
+ {
+ errorFound=true;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"remove file failed: "+file.errorString());
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"file removed: "+file.fileName());
+ }
+ else if(files.at(index).isDir())
+ removeFolder(files.at(index).absoluteFilePath());
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unknow file type for: "+files.at(index).absoluteFilePath());
+ index++;
+ }
+ if(!currentDir.rmpath(dir))
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Critical,"remove path failed, check right and if is empty: "+dir);
+ errorFound=true;
+ }
+ return !errorFound;
+}
diff --git a/ResourcesManager.h b/ResourcesManager.h
new file mode 100644
index 0000000..01444f9
--- /dev/null
+++ b/ResourcesManager.h
@@ -0,0 +1,57 @@
+/** \file ResourcesManager.h
+\brief Define the class to manage and load the resources linked with the themes
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef RESOURCES_MANAGER_H
+#define RESOURCES_MANAGER_H
+
+#include <QStringList>
+#include <QString>
+#include <QObject>
+
+#include "Environment.h"
+#include "Singleton.h"
+
+/** \brief Define the class to manage and load the resources linked with the themes
+
+This class provide a core load and manage the resources */
+class ResourcesManager : public QObject, public Singleton<ResourcesManager>
+{
+ Q_OBJECT
+ friend class Singleton<ResourcesManager>;
+ private:
+ /// \brief Create the manager and load the default variable
+ ResourcesManager();
+ /// \brief Destroy the resource manager
+ ~ResourcesManager();
+ public:
+ /** \brief Get folder presence and the path
+ \return Empty QString if not found */
+ QString getFolderReadPath(const QString &path);
+ /** \brief Get folder presence, the path and check in the folder and sub-folder the file presence
+ \return Empty QString if not found */
+ QString getFolderReadPathMultiple(const QString &path,const QStringList &fileToCheck);
+ bool checkFolderContent(const QString &path,const QStringList &fileToCheck);
+ /// \brief add / or \ in function of the platform at the end of path if both / and \ are not found
+ static QString AddSlashIfNeeded(const QString &path);
+ /// \brief get the writable path
+ QString getWritablePath();
+ /// \brief disable the writable path, if ultracopier is unable to write into
+ bool disableWritablePath();
+ /// \brief get the read path
+ QStringList getReadPath();
+ /// \brief remove folder
+ static bool removeFolder(const QString &dir);
+ private:
+ /// \brief List of the path to read only access
+ QStringList searchPath;
+ /// \brief The writable path, empty if not found
+ QString writablePath;
+ //temp variable
+ int index,loop_size;
+};
+
+#endif // RESOURCES_MANAGER_H
diff --git a/SessionLoader.cpp b/SessionLoader.cpp
new file mode 100644
index 0000000..c459acf
--- /dev/null
+++ b/SessionLoader.cpp
@@ -0,0 +1,123 @@
+/** \file SessionLoader.h
+\brief Define the session loader
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "SessionLoader.h"
+
+SessionLoader::SessionLoader(QObject *parent) :
+ QObject(parent)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //load the options
+ QList<QPair<QString, QVariant> > KeysList;
+ KeysList.append(qMakePair(QString("LoadAtSessionStarting"),QVariant(true)));
+ options->addOptionGroup("SessionLoader",KeysList);
+ connect(options,SIGNAL(newOptionValue(QString,QString,QVariant)), this, SLOT(newOptionValue(QString,QString,QVariant)));
+ //load the plugin
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_SessionLoader);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ qRegisterMetaType<PluginsAvailable>("PluginsAvailable");
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this,SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this,SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ plugins->unlockPluginListEdition();
+}
+
+SessionLoader::~SessionLoader()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_SessionLoader);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginWillBeRemoved(currentPlugin);
+}
+
+void SessionLoader::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_SessionLoader)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QString pluginPath=plugin.path+PluginsManager::getResolvedPluginName("sessionLoader");
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"try load: "+pluginPath);
+ LocalPlugin newEntry;
+ QPluginLoader *pluginLoader= new QPluginLoader(pluginPath);
+ newEntry.pluginLoader=pluginLoader;
+ QObject *pluginInstance = pluginLoader->instance();
+ if(pluginInstance)
+ {
+ PluginInterface_SessionLoader *sessionLoader = qobject_cast<PluginInterface_SessionLoader *>(pluginInstance);
+ //check if found
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).sessionLoaderInterface==sessionLoader)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Plugin already found"));
+ pluginLoader->unload();
+ return;
+ }
+ index++;
+ }
+ if(sessionLoader)
+ {
+ #ifdef ULTRACOPIER_DEBUG
+ connect(sessionLoader,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SLOT(debugInformation(DebugLevel,QString,QString,QString,int)));
+ #endif // ULTRACOPIER_DEBUG
+ newEntry.options=new LocalPluginOptions("SessionLoader-"+plugin.name);
+ newEntry.sessionLoaderInterface=sessionLoader;
+ newEntry.path=plugin.path;
+ newEntry.sessionLoaderInterface->setResources(newEntry.options,plugin.writablePath,plugin.path,ULTRACOPIER_VERSION_PORTABLE_BOOL);
+ pluginList << newEntry;
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to cast the plugin: "+pluginLoader->errorString());
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"unable to load the plugin: "+pluginLoader->errorString());
+}
+
+void SessionLoader::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_SessionLoader)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(plugin.path==pluginList.at(index).path)
+ {
+ if(!pluginList.at(index).pluginLoader->isLoaded() || pluginList.at(index).pluginLoader->unload())
+ {
+ delete pluginList.at(index).options;
+ pluginList.removeAt(index);
+ }
+ break;
+ }
+ index++;
+ }
+}
+
+void SessionLoader::newOptionValue(const QString &groupName,const QString &variableName,const QVariant &value)
+{
+ if(groupName=="SessionLoader" && variableName=="Enabled")
+ {
+ bool shouldEnabled=value.toBool();
+ int index=0;
+ while(index<pluginList.size())
+ {
+ pluginList.at(index).sessionLoaderInterface->setEnabled(shouldEnabled);
+ index++;
+ }
+ }
+}
+
+#ifdef ULTRACOPIER_DEBUG
+void SessionLoader::debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne)
+{
+ DebugEngine::addDebugInformationStatic(level,fonction,text,file,ligne,"Session loader plugin");
+}
+#endif // ULTRACOPIER_DEBUG
+
diff --git a/SessionLoader.h b/SessionLoader.h
new file mode 100644
index 0000000..5676cec
--- /dev/null
+++ b/SessionLoader.h
@@ -0,0 +1,53 @@
+/** \file SessionLoader.h
+\brief Define the class to load the plugin and lunch it
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING
+
+This class load ALL plugin compatible to listen and catch the copy/move
+*/
+
+#ifndef SESSIONLOADER_H
+#define SESSIONLOADER_H
+
+#include <QObject>
+#include <QList>
+#include <QPluginLoader>
+#include <QString>
+#include <QStringList>
+
+#include "interface/PluginInterface_SessionLoader.h"
+#include "PluginsManager.h"
+#include "GlobalClass.h"
+
+/// \todo SessionLoader -> put plugin by plugin loading to add plugin no reload all
+/// \todo async the plugin call
+
+/** \brief manage all SessionLoader plugin */
+class SessionLoader : public QObject, GlobalClass
+{
+ Q_OBJECT
+ public:
+ explicit SessionLoader(QObject *parent = 0);
+ ~SessionLoader();
+ private slots:
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ void newOptionValue(const QString &groupName,const QString &variableName,const QVariant &value);
+ #ifdef ULTRACOPIER_DEBUG
+ void debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne);
+ #endif // ULTRACOPIER_DEBUG
+ private:
+ //variable
+ struct LocalPlugin
+ {
+ PluginInterface_SessionLoader * sessionLoaderInterface;
+ QPluginLoader * pluginLoader;
+ QString path;
+ LocalPluginOptions *options;
+ };
+ QList<LocalPlugin> pluginList;
+};
+
+#endif // SESSIONLOADER_H
diff --git a/Singleton.h b/Singleton.h
new file mode 100644
index 0000000..d88a029
--- /dev/null
+++ b/Singleton.h
@@ -0,0 +1,52 @@
+/** \file Singleton.h
+\brief Define the singleton for class which should have unique object
+\author alpha_one_x86
+\note Big thanks to all people in the channel #qt-fr of freenode of irc
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QMutex>
+#include <QMutexLocker>
+
+#ifndef SINGLETON_H
+#define SINGLETON_H
+
+/** \class Singleton
+\brief Define the singleton for class which should have unique object
+\note Big thanks to all people in the channel #qt-fr of freenode of irc */
+template <typename T>
+class Singleton
+{
+ public:
+ /// \brief Public interface
+ static T *getInstance()
+ {
+ number_load++;
+ if(_singleton==NULL)
+ _singleton = new T;
+ return (static_cast<T*> (_singleton));
+ }
+ /// \brief For destroy only when the call to this function call count is the same as the getInstance() count call
+ static void destroyInstanceAtTheLastCall()
+ {
+ number_load--;
+ if(number_load==0)
+ {
+ delete _singleton;
+ _singleton=NULL;
+ }
+ }
+ private:
+ /// \brief Unique instance
+ static T *_singleton;
+ /// \brief To count the getInstance() call count
+ static int number_load;
+};
+
+template <typename T>
+T *Singleton<T>::_singleton = NULL;
+template <typename T>
+int Singleton<T>::number_load = 0;
+
+#endif // SINGLETON_H
diff --git a/StructEnumDefinition.h b/StructEnumDefinition.h
new file mode 100644
index 0000000..79bdb7e
--- /dev/null
+++ b/StructEnumDefinition.h
@@ -0,0 +1,146 @@
+/** \file StructEnumDefinition.h
+\brief Define the structure and enumeration used in ultracopier or into the plugin
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING
+\todo Add transfer state normal and custom */
+
+#include <QVariant>
+#include <QString>
+#include <QList>
+
+#ifndef STRUCTDEF_H
+#define STRUCTDEF_H
+
+/// \brief Define the mode of the copy window/request, if need be copy or move
+enum CopyMode
+{
+ Copy=0x00000000,
+ Move=0x00000001
+};
+
+/// \brief Define the catching state, if the copy is totally catch of the explorer, partially or nothing
+enum CatchState
+{
+ Uncaught=0x00000000,
+ Semiuncaught=0x00000001,
+ Caught=0x00000002
+};
+
+/// \brief Define the listening state
+enum ListeningState
+{
+ NotListening=0x00000000,///< 0 listener is listening
+ SemiListening=0x00000001,///< only part of listeners are listening
+ FullListening=0x00000002///< all the listeners are listening
+};
+
+/// \brief Define the copy type, if folder, file or both
+enum CopyType
+{
+ File = 0x00000001,
+ FileAndFolder = 0x00000002
+};
+
+/// \brief transfer list operation, can define nothing, the import/export or both
+enum TransferListOperation
+{
+ TransferListOperation_None = 0x00000000,
+ TransferListOperation_Import = 0x00000001,
+ TransferListOperation_Export = 0x00000002,
+ TransferListOperation_ImportExport = TransferListOperation_Import | TransferListOperation_Export
+};
+
+enum EngineActionInProgress
+{
+ Idle = 0x00000000,
+ Listing = 0x00000001,
+ Copying = 0x00000002,
+ CopyingAndListing = Listing | Copying
+};
+
+enum DebugLevel
+{
+ DebugLevel_Information=0x00000001,
+ DebugLevel_Critical=0x00000002,
+ DebugLevel_Warning=0x00000003,
+ DebugLevel_Notice=0x00000004
+};
+
+enum SizeUnit
+{
+ SizeUnit_byte=0x00000000,
+ SizeUnit_KiloByte=0x00000001,
+ SizeUnit_MegaByte=0x00000002,
+ SizeUnit_GigaByte=0x00000003,
+ SizeUnit_TeraByte=0x00000004,
+ SizeUnit_PetaByte=0x00000005,
+ SizeUnit_ExaByte=0x00000006,
+ SizeUnit_ZettaByte=0x00000007,
+ SizeUnit_YottaByte=0x00000008
+};
+
+/// \brief structure for decompossed time
+struct TimeDecomposition
+{
+ quint16 second;
+ quint16 minute;
+ quint16 hour;
+};
+
+//////////////////////////// Return list //////////////////////////////
+enum ActionTypeCopyList
+{
+ //playlist action
+ MoveItem=0x00000000,
+ RemoveItem=0x00000001,
+ AddingItem=0x00000002,
+ //Item action
+ PreOperation=0x00000003,
+ Transfer=0x00000004,
+ PostOperation=0x00000005,
+ CustomOperation=0x00000006 /// \note this need be used after preoperation and before postoperation
+};
+
+/// \brief structure for progression item
+struct ProgressionItem
+{
+ quint64 id;
+ quint64 current;
+ quint64 total;
+};
+
+/// \brief item to insert item in the interface
+struct ItemOfCopyList
+{
+ quint64 id;
+ // if type == CustomOperation, then is the translated name of the operation
+ QString sourceFullPath;///< full path with file name: /foo/foo.txt
+ QString sourceFileName;///< full path with file name: foo.txt
+ QString destinationFullPath;///< full path with file name: /foo/foo.txt
+ QString destinationFileName;///< full path with file name: foo.txt
+ // if type == CustomOperation, then 0 = without progression, 1 = with progression
+ quint64 size;
+ CopyMode mode;
+};
+
+/// \brief The definition of no removing action on transfer list
+struct ActionOnCopyList
+{
+ int position;
+ ///< if type == MoveItem
+ int moveAt;
+};
+
+/// \brief action normal or due to interface query on copy list
+struct returnActionOnCopyList
+{
+ ActionTypeCopyList type;
+ ///< used if type == AddingItem || type == PreOperation (for interface without transfer list) || type == CustomOperation
+ ItemOfCopyList addAction;
+ ///< used if type != AddingItem
+ ActionOnCopyList userAction;
+};
+
+#endif // STRUCTDEF_H
diff --git a/StructEnumDefinition_UltracopierSpecific.h b/StructEnumDefinition_UltracopierSpecific.h
new file mode 100644
index 0000000..c9ed2d0
--- /dev/null
+++ b/StructEnumDefinition_UltracopierSpecific.h
@@ -0,0 +1,57 @@
+/** \file StructEnumDefinition_UltracopierSpecific.h
+\brief Define the structure and enumeration used in ultracopier only
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QString>
+#include <QList>
+#include <QDomElement>
+
+#ifndef STRUCTDEF_ULTRACOPIERSPECIFIC_H
+#define STRUCTDEF_ULTRACOPIERSPECIFIC_H
+
+enum PluginType
+{
+ PluginType_Unknow,
+ PluginType_CopyEngine,
+ PluginType_Languages,
+ PluginType_Listener,
+ PluginType_PluginLoader,
+ PluginType_SessionLoader,
+ PluginType_Themes
+};
+
+/// \brief structure to store the general plugin related information
+struct PluginsAvailable
+{
+ PluginType category;
+ QString path;
+ QString name;
+ QString writablePath;
+ QDomElement categorySpecific;
+ QString version;
+ QList<QStringList> informations;
+ QString errorString;
+ bool isWritable;
+ bool isAuth;
+};
+
+enum DebugLevel_custom
+{
+ DebugLevel_custom_Information,
+ DebugLevel_custom_Critical,
+ DebugLevel_custom_Warning,
+ DebugLevel_custom_Notice,
+ DebugLevel_custom_UserNote
+};
+
+enum ActionOnManualOpen
+{
+ ActionOnManualOpen_Nothing=0x00,
+ ActionOnManualOpen_Folder=0x01,
+ ActionOnManualOpen_Files=0x02
+};
+
+#endif // STRUCTDEF_ULTRACOPIERSPECIFIC_H
diff --git a/SystrayIcon.cpp b/SystrayIcon.cpp
new file mode 100644
index 0000000..b4fef7d
--- /dev/null
+++ b/SystrayIcon.cpp
@@ -0,0 +1,388 @@
+/** \file SystrayIcon.cpp
+\brief Define the class of the systray icon
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QMessageBox>
+
+#include "SystrayIcon.h"
+
+/// \brief Initiate and show the icon in the systray
+SystrayIcon::SystrayIcon()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ //setup the systray icon
+ haveListenerInfo = false;
+ havePluginLoaderInfo = false;
+ sysTrayIcon = new QSystemTrayIcon();
+ systrayMenu = new QMenu();
+ actionMenuAbout = new QAction(this);
+ actionMenuQuit = new QAction(this);
+ actionOptions = new QAction(this);
+ //actionTransfer = new QAction(this);
+ copyMenu = new QMenu();
+ sysTrayIcon->setContextMenu(systrayMenu);
+ sysTrayIcon->setToolTip("Ultracopier");
+ #ifdef Q_OS_WIN32
+ sysTrayIcon->setIcon(QIcon(":/systray_Uncaught_Windows.png"));
+ #else
+ sysTrayIcon->setIcon(QIcon(":/systray_Uncaught_Unix.png"));
+ #endif
+ sysTrayIcon->show();
+ //connect the action
+ connect(actionMenuQuit, SIGNAL(triggered()), this, SIGNAL(quit()));
+ connect(actionMenuAbout, SIGNAL(triggered()), this, SIGNAL(showHelp()));
+ connect(actionOptions, SIGNAL(triggered()), this, SIGNAL(showOptions()));
+ connect(sysTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(CatchAction(QSystemTrayIcon::ActivationReason)));
+ connect(plugins, SIGNAL(pluginListingIsfinish()), this, SLOT(reloadEngineList()));
+ //display the icon
+ updateCurrentTheme();
+ //if theme/language change, update graphic part
+ connect(themes, SIGNAL(theThemeIsReloaded()), this, SLOT(updateCurrentTheme()));
+ connect(languages, SIGNAL(newLanguageLoaded(QString)), this, SLOT(retranslateTheUI()));
+ systrayMenu->addMenu(copyMenu);
+ systrayMenu->addAction(actionOptions);
+ systrayMenu->addAction(actionMenuAbout);
+ systrayMenu->addAction(actionMenuQuit);
+ systrayMenu->insertSeparator(actionOptions);
+ retranslateTheUI();
+ updateSystrayIcon();
+}
+
+/// \brief Hide and destroy the icon in the systray
+SystrayIcon::~SystrayIcon()
+{
+ delete actionMenuQuit;
+ delete actionMenuAbout;
+ delete actionOptions;
+ delete systrayMenu;
+ delete copyMenu;
+ delete sysTrayIcon;
+}
+
+void SystrayIcon::listenerReady(const ListeningState &state,const bool &havePlugin,const bool &someAreInWaitOfReply)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("state: %1, havePlugin: %2, someAreInWaitOfReply: %3").arg(state).arg(havePlugin).arg(someAreInWaitOfReply));
+ Q_UNUSED(someAreInWaitOfReply);
+ stateListener=state;
+ haveListenerInfo=true;
+ haveListener=havePlugin;
+ updateSystrayIcon();
+ if(!havePlugin)
+ showTryCatchMessageWithNoListener();
+}
+
+void SystrayIcon::pluginLoaderReady(const CatchState &state,const bool &havePlugin,const bool &someAreInWaitOfReply)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("state: %1, havePlugin: %2, someAreInWaitOfReply: %3").arg(state).arg(havePlugin).arg(someAreInWaitOfReply));
+ Q_UNUSED(someAreInWaitOfReply);
+ statePluginLoader=state;
+ havePluginLoaderInfo=true;
+ havePluginLoader=havePlugin;
+ updateSystrayIcon();
+}
+
+void SystrayIcon::showTryCatchMessageWithNoListener()
+{
+ showSystrayMessage(tr("No copy listener found. Do the copy manually by right click one the system tray icon."));
+}
+
+/// \brief To show a message linked to the systray icon
+void SystrayIcon::showSystrayMessage(const QString& text)
+{
+ sysTrayIcon->showMessage(tr("Information"),text,QSystemTrayIcon::Information,0);
+}
+
+/// \brief To update the systray icon
+void SystrayIcon::updateSystrayIcon()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("start, haveListenerInfo %1, havePluginLoaderInfo: %2").arg(haveListenerInfo).arg(havePluginLoaderInfo));
+ QString toolTip;
+ QString icon;
+ if(!haveListenerInfo || !havePluginLoaderInfo)
+ {
+ toolTip=tr("Searching informations...");
+ icon="Uncaught";
+ }
+ else
+ {
+ ListeningState stateListener=this->stateListener;
+ CatchState statePluginLoader=this->statePluginLoader;
+ if(!haveListener)
+ stateListener=NotListening;
+ if(!havePluginLoader)
+ statePluginLoader=Caught;
+ if((stateListener==NotListening && statePluginLoader==Uncaught) || (stateListener==SemiListening && statePluginLoader==Semiuncaught) || (stateListener==FullListening && statePluginLoader==Caught))
+ {
+ if(stateListener==NotListening)
+ {
+ toolTip=tr("Not catching the explorer copy/move");
+ icon="Uncaught";
+ }
+ else if(stateListener==SemiListening)
+ {
+ toolTip=tr("Semi catching the explorer copy/move");
+ icon="Semiuncaught";
+ }
+ else
+ {
+ toolTip=tr("Catching the explorer copy/move");
+ icon="Caught";
+ }
+ }
+ else
+ {
+ icon="Semiuncaught";
+ QString first_part;
+ QString second_part;
+ if(stateListener==NotListening)
+ first_part="No listening";
+ else if(stateListener==SemiListening)
+ first_part="Semi listening";
+ else if(stateListener==FullListening)
+ first_part="Full listening";
+ else
+ first_part="Unknow listening";
+ if(statePluginLoader==Uncaught)
+ second_part="No catching";
+ else if(statePluginLoader==Semiuncaught)
+ second_part="Semi catching";
+ else if(statePluginLoader==Caught)
+ second_part="Full catching";
+ else
+ second_part="Unknow catching";
+ toolTip=first_part+"/"+second_part;
+ }
+ }
+ QIcon theNewSystrayIcon;
+ #ifdef Q_OS_WIN32
+ theNewSystrayIcon=themes->loadIcon("SystemTrayIcon/systray_"+icon+"_Windows.png");
+ #else
+ theNewSystrayIcon=themes->loadIcon("SystemTrayIcon/systray_"+icon+"_Unix.png");
+ #endif
+ if(theNewSystrayIcon.isNull())
+ {
+ #ifdef Q_OS_WIN32
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"use the default systray icon: :/systray_"+icon+"_Windows.png");
+ theNewSystrayIcon=QIcon(":/systray_"+icon+"_Windows.png");
+ #else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"use the default systray icon: :/systray_"+icon+"_Unix.png");
+ theNewSystrayIcon=QIcon(":/systray_"+icon+"_Unix.png");
+ #endif
+ }
+ else
+ {
+ #ifdef Q_OS_WIN32
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"icon: systray_"+icon+"_Windows.png");
+ #else
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"icon: systray_"+icon+"_Unix.png");
+ #endif
+ }
+ sysTrayIcon->setIcon(theNewSystrayIcon);
+ sysTrayIcon->setToolTip("Ultracopier - "+toolTip);
+}
+
+/// \brief To update the current themes
+void SystrayIcon::updateCurrentTheme()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"icon: start");
+ //load the systray menu item
+ QIcon tempIcon;
+
+ tempIcon=themes->loadIcon("SystemTrayIcon/exit.png");
+ if(!tempIcon.isNull())
+ IconQuit=QIcon(tempIcon);
+ else
+ IconQuit=QIcon("");
+ actionMenuQuit->setIcon(IconQuit);
+
+ tempIcon=themes->loadIcon("SystemTrayIcon/informations.png");
+ if(!tempIcon.isNull())
+ IconInfo=QIcon(tempIcon);
+ else
+ IconInfo=QIcon("");
+ actionMenuAbout->setIcon(IconInfo);
+
+ tempIcon=themes->loadIcon("SystemTrayIcon/options.png");
+ if(!tempIcon.isNull())
+ IconOptions=QIcon(tempIcon);
+ else
+ IconOptions=QIcon("");
+ actionOptions->setIcon(IconOptions);
+
+ tempIcon=themes->loadIcon("SystemTrayIcon/add.png");
+ if(!tempIcon.isNull())
+ IconAdd=QIcon(tempIcon);
+ else
+ IconAdd=QIcon("");
+ copyMenu->setIcon(IconAdd);
+
+ //update the systray icon
+ updateSystrayIcon();
+ reloadEngineList();
+}
+
+/* \brief For catch an action on the systray icon
+\param reason Why it activated */
+void SystrayIcon::CatchAction(QSystemTrayIcon::ActivationReason reason)
+{
+ if(reason==QSystemTrayIcon::DoubleClick || reason==QSystemTrayIcon::Trigger)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Double click on system tray icon");
+ if(stateListener!=NotListening || statePluginLoader!=Uncaught)
+ emit tryUncatchCopy();
+ else
+ {
+ if(!haveListener)
+ showTryCatchMessageWithNoListener();
+ emit tryCatchCopy();
+ }
+ }
+ else if(reason==QSystemTrayIcon::Context)//do nothing on right click to show as auto the menu
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("Action on the systray icon is unknown: %1").arg(reason));
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Action on the systray icon is unknown: %1").arg(reason));
+ QMessageBox::warning(NULL,tr("Warning"),tr("Action on the systray icon is unknown!"));
+ }
+}
+
+/// \brief To catch copy menu action
+void SystrayIcon::CatchCopyQuery()
+{
+ QAction * currentAction=qobject_cast<QAction *>(QObject::sender());
+ if(currentAction==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"action not found");
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+currentAction->data().toString());
+ emit addWindowCopyMove(Copy,currentAction->data().toString());
+}
+
+/// \brief To catch move menu action
+void SystrayIcon::CatchMoveQuery()
+{
+ QAction * currentAction=qobject_cast<QAction *>(QObject::sender());
+ if(currentAction==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"action not found");
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+currentAction->data().toString());
+ emit addWindowCopyMove(Move,currentAction->data().toString());
+}
+
+/// \brief To catch transfer menu action
+void SystrayIcon::CatchTransferQuery()
+{
+ QAction * currentAction=qobject_cast<QAction *>(QObject::sender());
+ if(currentAction==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"action not found");
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+currentAction->data().toString());
+ emit addWindowTransfer(currentAction->data().toString());
+}
+
+/// \brief to retranslate the ui
+void SystrayIcon::retranslateTheUI()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"retranslateTheUI");
+ #ifdef ULTRACOPIER_DEBUG
+ actionMenuAbout ->setText(tr("&About/Debug report"));
+ #else // ULTRACOPIER_DEBUG
+ actionMenuAbout ->setText(tr("&About"));
+ #endif // ULTRACOPIER_DEBUG
+ actionMenuQuit ->setText(tr("&Quit"));
+ actionOptions ->setText(tr("&Options"));
+ copyMenu ->setTitle(tr("A&dd copy/moving"));
+ reloadEngineList();
+ updateSystrayIcon();
+}
+
+void SystrayIcon::addCopyEngine(const QString &name,const bool &canDoOnlyCopy)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ EngineEntry entry;
+ entry.name=name;
+ entry.canDoOnlyCopy=canDoOnlyCopy;
+ engineEntryList << entry;
+ if(plugins->allPluginHaveBeenLoaded())
+ reloadEngineList();
+}
+
+void SystrayIcon::removeCopyEngine(const QString &name)
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ int index=0;
+ while(index<engineEntryList.size())
+ {
+ if(engineEntryList.at(index).name==name)
+ {
+ engineEntryList.removeAt(index);
+ break;
+ }
+ index++;
+ }
+ void reloadEngineList();
+}
+
+void SystrayIcon::reloadEngineList()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ copyMenu->clear();
+ if(engineEntryList.size()==0)
+ {
+ copyMenu->setEnabled(false);
+ return;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"engineEntryList.size(): "+QString::number(engineEntryList.size()));
+ copyMenu->setEnabled(true);
+ if(engineEntryList.size()==1)
+ {
+ QAction *copy=new QAction(IconAdd,tr("Add &copy"),copyMenu);
+ connect(copy,SIGNAL(triggered()),this,SLOT(CatchCopyQuery()));
+ copy->setData(engineEntryList.first().name);
+ copyMenu->addAction(copy);
+ if(!engineEntryList.first().canDoOnlyCopy)
+ {
+ QAction *transfer=new QAction(IconAdd,tr("Add &transfer"),copyMenu);
+ connect(transfer,SIGNAL(triggered()),this,SLOT(CatchTransferQuery()));
+ transfer->setData(engineEntryList.first().name);
+ copyMenu->addAction(transfer);
+ QAction *move=new QAction(IconAdd,tr("Add &move"),copyMenu);
+ connect(move,SIGNAL(triggered()),this,SLOT(CatchMoveQuery()));
+ move->setData(engineEntryList.first().name);
+ copyMenu->addAction(move);
+ }
+ }
+ else
+ {
+ int index=0;
+ while(index<engineEntryList.size())
+ {
+ QMenu * menu=new QMenu(engineEntryList.at(index).name);
+ QAction *copy=new QAction(IconAdd,tr("Add &copy"),menu);
+ connect(copy,SIGNAL(triggered()),this,SLOT(CatchCopyQuery()));
+ copy->setData(engineEntryList.at(index).name);
+ menu->addAction(copy);
+ if(!engineEntryList.at(index).canDoOnlyCopy)
+ {
+ QAction *transfer=new QAction(IconAdd,tr("Add &transfer"),menu);
+ connect(transfer,SIGNAL(triggered()),this,SLOT(CatchTransferQuery()));
+ transfer->setData(engineEntryList.at(index).name);
+ menu->addAction(transfer);
+ QAction *move=new QAction(IconAdd,tr("Add &move"),menu);
+ connect(move,SIGNAL(triggered()),this,SLOT(CatchMoveQuery()));
+ move->setData(engineEntryList.at(index).name);
+ menu->addAction(move);
+ }
+ copyMenu->addMenu(menu);
+ index++;
+ }
+ }
+}
diff --git a/SystrayIcon.h b/SystrayIcon.h
new file mode 100644
index 0000000..86d0668
--- /dev/null
+++ b/SystrayIcon.h
@@ -0,0 +1,101 @@
+/** \file SystrayIcon.h
+\brief Define the class of the systray icon
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef SYSTRAY_ICON_H
+#define SYSTRAY_ICON_H
+
+#include <QSystemTrayIcon>
+#include <QObject>
+#include <QAction>
+#include <QMenu>
+
+#include "Environment.h"
+#include "GlobalClass.h"
+
+/** \brief The systray icon
+
+This class provide a systray icon and its functions */
+class SystrayIcon : public QObject, public GlobalClass
+{
+ Q_OBJECT
+ public:
+ /// \brief Initiate and show the icon in the systray
+ SystrayIcon();
+ /// \brief Hide and destroy the icon in the systray
+ ~SystrayIcon();
+ public slots:
+ /// \brief For show a message linked to the systray icon
+ void showSystrayMessage(const QString& text);
+ /** \brief Send that's caught state have changed for CatchedState::Uncatched or CatchedState::Semicatched or CatchedState::Catched
+ \see CatchState
+ \see tryCatchCopy()
+ \see tryUncatchCopy()
+ \param state is the new state */
+ void listenerReady(const ListeningState &state,const bool &havePlugin,const bool &someAreInWaitOfReply);
+ void pluginLoaderReady(const CatchState &state,const bool &havePlugin,const bool &someAreInWaitOfReply);
+ void addCopyEngine(const QString &name,const bool &canDoOnlyCopy);
+ void removeCopyEngine(const QString &name);
+ private:
+ QSystemTrayIcon* sysTrayIcon; ///< Pointer on the systray icon
+ QMenu* systrayMenu; ///< Pointer on the menu
+ QMenu* copyMenu; ///< Pointer on the copy menu (move or copy)
+ QAction* actionMenuQuit; ///< Pointer on the Quit action
+ QAction* actionMenuAbout; ///< Pointer on the About action
+ QAction* actionOptions; ///< Pointer on the Options action
+ QIcon IconQuit; ///< Pointer on the icon for quit
+ QIcon IconInfo; ///< Pointer on the icon for info
+ QIcon IconAdd; ///< Pointer on the icon for add
+ QIcon IconOptions; ///< Pointer on the options
+ /// \brief To update the systray icon
+ void updateSystrayIcon();
+ void showTryCatchMessageWithNoListener();
+ struct EngineEntry
+ {
+ bool canDoOnlyCopy;
+ QString name;
+ };
+ QList<EngineEntry> engineEntryList;
+ // To store the current catch state
+ ListeningState stateListener;
+ CatchState statePluginLoader;
+ bool haveListenerInfo,havePluginLoaderInfo;
+ bool haveListener,havePluginLoader;
+ private slots:
+ /// \brief To update the current themes
+ void updateCurrentTheme();
+ /** \brief To catch an action on the systray icon
+ \param reason Why it activated */
+ void CatchAction(QSystemTrayIcon::ActivationReason reason);
+ /// \brief To catch copy menu action
+ void CatchCopyQuery();
+ /// \brief To catch move menu action
+ void CatchMoveQuery();
+ /// \brief To catch transfer menu action
+ void CatchTransferQuery();
+ /// \brief to retranslate the ui
+ void retranslateTheUI();
+ void reloadEngineList();
+ signals:
+ /// \brief Quit ultracopier
+ void quit();
+ /// \brief Try catch the copy/move with plugin compatible
+ void tryCatchCopy();
+ /// \brief Try uncatch the copy/move with plugin compatible
+ void tryUncatchCopy();
+ /// \brief Show the help dialog
+ void showHelp();
+ /// \brief Show the help option
+ void showOptions();
+ /** \brief Add window copy or window move
+ \param mode Can be CopyMode::Copy or CopyMode::Move
+ \return The core object of the new window created */
+ void addWindowCopyMove(CopyMode mode,QString name);
+ void addWindowTransfer(QString name);
+};
+
+#endif // SYSTRAY_ICON_H
+
diff --git a/ThemesManager.cpp b/ThemesManager.cpp
new file mode 100644
index 0000000..fe62380
--- /dev/null
+++ b/ThemesManager.cpp
@@ -0,0 +1,245 @@
+/** \file ThemesManager.cpp
+\brief Define the class for manage and load the themes
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include <QString>
+#include <QFile>
+#include <QMessageBox>
+
+#include "ThemesManager.h"
+
+#define ULTRACOPIER_DEFAULT_STYLE "Oxygen"
+
+/// \todo load each plugin to have their options
+/// \todo get the current themes instance
+
+/// \brief Create the manager and load the defaults variables
+ThemesManager::ThemesManager()
+{
+ //load the debug engine as external part because ThemesManager is base class
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ currentPluginIndex=-1;
+
+ //load the overall instance
+ resources=ResourcesManager::getInstance();
+ plugins=PluginsManager::getInstance();
+ options=OptionEngine::getInstance();
+ languages=LanguagesManager::getInstance();
+
+ //connect the plugin management
+ plugins->lockPluginListEdition();
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_Themes);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginAdded(currentPlugin);
+ connect(plugins,SIGNAL(onePluginAdded(PluginsAvailable)), this,SLOT(onePluginAdded(PluginsAvailable)));
+ connect(plugins,SIGNAL(onePluginWillBeRemoved(PluginsAvailable)), this,SLOT(onePluginWillBeRemoved(PluginsAvailable)),Qt::DirectConnection);
+ connect(plugins,SIGNAL(pluginListingIsfinish()), this,SLOT(allPluginIsLoaded()));
+ plugins->unlockPluginListEdition();
+
+ //do the options
+ QList<QPair<QString, QVariant> > KeysList;
+ KeysList.append(qMakePair(QString("Ultracopier_current_theme"),QVariant(ULTRACOPIER_DEFAULT_STYLE)));
+ options->addOptionGroup("Themes",KeysList);
+
+ //load the default and current themes path
+ defaultStylePath=":/Themes/"+QString(ULTRACOPIER_DEFAULT_STYLE)+"/";
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Default style: "+defaultStylePath);
+ currentStylePath=defaultStylePath;
+ connect(options, SIGNAL(newOptionValue(QString,QString,QVariant)), this, SLOT(newOptionValue(QString,QString,QVariant)));
+ connect(languages, SIGNAL(newLanguageLoaded(QString)), &facilityEngine,SLOT(retranslate()));
+}
+
+/// \brief Destroy the themes manager
+ThemesManager::~ThemesManager()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ QList<PluginsAvailable> list=plugins->getPluginsByCategory(PluginType_Themes);
+ foreach(PluginsAvailable currentPlugin,list)
+ onePluginWillBeRemoved(currentPlugin);
+ LanguagesManager::destroyInstanceAtTheLastCall();
+ OptionEngine::destroyInstanceAtTheLastCall();
+ PluginsManager::destroyInstanceAtTheLastCall();
+ ResourcesManager::destroyInstanceAtTheLastCall();
+}
+
+void ThemesManager::onePluginAdded(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_Themes)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+plugin.name);
+ PluginsAvailableThemes newThemes;
+ newThemes.plugin=plugin;
+ newThemes.factory=NULL;
+ newThemes.pluginLoader=NULL;
+ pluginList << newThemes;
+ //setFileName
+ /**/
+}
+
+void ThemesManager::onePluginWillBeRemoved(const PluginsAvailable &plugin)
+{
+ if(plugin.category!=PluginType_Themes)
+ return;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start: "+plugin.name);
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).plugin==plugin)
+ {
+ if(pluginList.at(index).factory!=NULL)
+ delete pluginList.at(index).factory;
+ if(pluginList.at(index).pluginLoader!=NULL)
+ {
+ pluginList.at(index).pluginLoader->unload();
+ delete pluginList.at(index).pluginLoader;
+ }
+ if(currentPluginIndex==index)
+ currentPluginIndex=-1;
+ if(index<currentPluginIndex)
+ currentPluginIndex--;
+ pluginList.removeAt(index);
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"plugin not found");
+}
+
+/** \brief To get image into the current themes, or default if not found
+\param filePath The file path to search, like toto.png resolved with the root of the current themes
+\see currentStylePath */
+QIcon ThemesManager::loadIcon(const QString &fileName)
+{
+ if(currentPluginIndex==-1)
+ return QIcon();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Send interface pixmap: "+fileName);
+ return pluginList.at(currentPluginIndex).factory->getIcon(fileName);
+}
+
+void ThemesManager::allPluginIsLoaded()
+{
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"start");
+ currentPluginIndex=-1;
+ if(pluginList.size()==0)
+ {
+ emit newThemeOptions(NULL,false,false);
+ emit theThemeIsReloaded();
+ return;
+ }
+ QString name=options->getOptionValue("Themes","Ultracopier_current_theme").toString();
+ int index=0;
+ while(index<pluginList.size())
+ {
+ if(pluginList.at(index).plugin.name==name)
+ {
+ QPluginLoader *pluginLoader=new QPluginLoader(pluginList.at(index).plugin.path+QDir::separator()+plugins->getResolvedPluginName("interface"));
+ QObject *pluginInstance = pluginLoader->instance();
+ if(pluginInstance==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to load the plugin %1: %2").arg(pluginList.at(index).plugin.path+QDir::separator()+plugins->getResolvedPluginName("interface")).arg(pluginLoader->errorString()));
+ pluginLoader->unload();
+ }
+ else
+ {
+ PluginInterface_ThemesFactory *factory = qobject_cast<PluginInterface_ThemesFactory *>(pluginInstance);
+ //check if found
+ int indexTemp=0;
+ while(indexTemp<pluginList.size())
+ {
+ if(pluginList.at(indexTemp).factory==factory)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("Plugin already found, current: %1, conflit plugin: %2, name: %3")
+ .arg(pluginList.at(index).plugin.path+QDir::separator()+plugins->getResolvedPluginName("interface"))
+ .arg(pluginList.at(indexTemp).plugin.path+QDir::separator()+plugins->getResolvedPluginName("interface"))
+ .arg(name)
+ );
+ pluginLoader->unload();
+ emit newThemeOptions(NULL,false,true);
+ emit theThemeIsReloaded();
+ return;
+ }
+ indexTemp++;
+ }
+ if(factory==NULL)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,QString("unable to cast the plugin: %1").arg(pluginLoader->errorString()));
+ pluginLoader->unload();
+ }
+ else
+ {
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"preload: "+name+", at the index: "+QString::number(index)+", name at this index: "+pluginList[index].plugin.name);
+ #ifdef ULTRACOPIER_DEBUG
+ qRegisterMetaType<DebugLevel>("DebugLevel");
+ connect(factory,SIGNAL(debugInformation(DebugLevel,QString,QString,QString,int)),this,SLOT(debugInformation(DebugLevel,QString,QString,QString,int)),Qt::QueuedConnection);
+ #endif // ULTRACOPIER_DEBUG
+ connect(languages,SIGNAL(newLanguageLoaded(QString)),factory,SLOT(newLanguageLoaded()));
+ pluginList[index].factory=factory;
+ pluginList[index].pluginLoader=pluginLoader;
+ pluginList[index].options=new LocalPluginOptions("Themes-"+name);
+ pluginList.at(index).factory->setResources(pluginList[index].options,pluginList.at(index).plugin.writablePath,pluginList.at(index).plugin.path,&facilityEngine,ULTRACOPIER_VERSION_PORTABLE_BOOL);
+ currentPluginIndex=index;
+ currentStylePath=pluginList[index].plugin.path;
+ emit newThemeOptions(pluginList.at(index).factory->options(),true,true);
+ emit theThemeIsReloaded();
+ return;
+ }
+ }
+ emit newThemeOptions(NULL,false,true);
+ emit theThemeIsReloaded();
+ return;
+ }
+ index++;
+ }
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Warning,"theme not found!");
+ emit newThemeOptions(NULL,false,true);
+ emit theThemeIsReloaded();
+}
+
+PluginInterface_Themes * ThemesManager::getThemesInstance()
+{
+ if(currentPluginIndex==-1)
+ return NULL;
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,"Send interface: "+pluginList.at(currentPluginIndex).plugin.name);
+ return pluginList.at(currentPluginIndex).factory->getInstance();
+}
+
+#ifdef ULTRACOPIER_DEBUG
+void ThemesManager::debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne)
+{
+ DebugEngine::addDebugInformationStatic(level,fonction,text,file,ligne,"Theme plugin");
+}
+#endif // ULTRACOPIER_DEBUG
+
+void ThemesManager::newOptionValue(const QString &group,const QString &name,const QVariant &value)
+{
+ if(group=="Themes" && name=="Ultracopier_current_theme")
+ {
+ if(currentPluginIndex!=-1 && value.toString()!=pluginList.at(currentPluginIndex).plugin.name)
+ {
+ int tempCurrentPluginIndex=currentPluginIndex;
+ emit theThemeNeedBeUnloaded();
+ ULTRACOPIER_DEBUGCONSOLE(DebugLevel_Notice,QString("unload the themes: %1 (%2)").arg(pluginList.at(tempCurrentPluginIndex).plugin.name).arg(tempCurrentPluginIndex));
+ if(pluginList.at(tempCurrentPluginIndex).options!=NULL)
+ {
+ delete pluginList.at(tempCurrentPluginIndex).options;
+ pluginList[tempCurrentPluginIndex].options=NULL;
+ }
+ if(pluginList.at(tempCurrentPluginIndex).factory!=NULL)
+ {
+ delete pluginList.at(tempCurrentPluginIndex).factory;
+ pluginList[tempCurrentPluginIndex].factory=NULL;
+ }
+ if(pluginList.at(tempCurrentPluginIndex).pluginLoader!=NULL)
+ {
+ pluginList.at(tempCurrentPluginIndex).pluginLoader->unload();
+ delete pluginList.at(tempCurrentPluginIndex).pluginLoader;
+ pluginList[tempCurrentPluginIndex].pluginLoader=NULL;
+ }
+ }
+ allPluginIsLoaded();
+ //emit theThemeIsReloaded(); -> do into allPluginIsLoaded(); now
+ }
+}
diff --git a/ThemesManager.h b/ThemesManager.h
new file mode 100644
index 0000000..9bfb36c
--- /dev/null
+++ b/ThemesManager.h
@@ -0,0 +1,90 @@
+/** \file ThemesManager.h
+\brief Define the class to manage and load the themes
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef THEMES_MANAGER_H
+#define THEMES_MANAGER_H
+
+#include <QString>
+#include <QObject>
+#include <QIcon>
+#include <QList>
+#include <QPluginLoader>
+
+#include "Environment.h"
+#include "ResourcesManager.h"
+#include "Singleton.h"
+#include "OptionEngine.h"
+#include "PluginsManager.h"
+#include "LanguagesManager.h"
+#include "LocalPluginOptions.h"
+#include "FacilityEngine.h"
+
+#include "interface/PluginInterface_Themes.h"
+
+/** \brief Define the class to manage and load the themes
+
+This class provide a core load and manage the themes */
+class ThemesManager : public QObject, public Singleton<ThemesManager>
+{
+ Q_OBJECT
+ friend class Singleton<ThemesManager>;
+ //public slots:
+ /*/// \brief To change the current themes selected
+ bool changeCurrentTheme(QString theNewThemeToLoad);*/
+ public:
+ /** \brief To get image into the current themes, or default if not found
+ \param filePath The file path to search, like toto.png resolved with the root of the current themes
+ \see currentStylePath */
+ QIcon loadIcon(const QString &fileName);
+ /** \brief To get if one themes instance
+ \see Core() */
+ PluginInterface_Themes * getThemesInstance();
+ private:
+ /// \brief Create the manager and load the defaults variables
+ ThemesManager();
+ /// \brief Destroy the themes manager
+ ~ThemesManager();
+ /// \brief The default themes path where it has theme's files
+ QString defaultStylePath;
+ /// \brief The current themes path loaded by ultracopier
+ QString currentStylePath;
+ /// \brief Store the object of resources manager
+ ResourcesManager *resources;
+ //for the options
+ OptionEngine *options;
+ /// \brief Store the object of languages manager
+ LanguagesManager *languages;
+ /// \brief Store the object of plugin manager
+ PluginsManager *plugins;
+ /// \brief OptionEngineGroupKey then: Group -> Key
+ struct PluginsAvailableThemes
+ {
+ PluginsAvailable plugin;
+ PluginInterface_ThemesFactory *factory;
+ QPluginLoader *pluginLoader;
+ LocalPluginOptions *options;
+ };
+ QList<PluginsAvailableThemes> pluginList;
+ int currentPluginIndex;
+ FacilityEngine facilityEngine;
+ signals:
+ /// \brief send this signal when the themes have changed
+ void theThemeNeedBeUnloaded();
+ void theThemeIsReloaded();
+ void newThemeOptions(QWidget *,bool isLoaded,bool havePlugin);
+ private slots:
+ /// \brief reload the themes
+ void onePluginAdded(const PluginsAvailable &plugin);
+ void onePluginWillBeRemoved(const PluginsAvailable &plugin);
+ void allPluginIsLoaded();
+ void newOptionValue(const QString &group,const QString &name,const QVariant &value);
+ #ifdef ULTRACOPIER_DEBUG
+ void debugInformation(DebugLevel level,const QString& fonction,const QString& text,const QString& file,const int& ligne);
+ #endif // ULTRACOPIER_DEBUG
+};
+
+#endif // THEMES_MANAGER_H
diff --git a/Variable.h b/Variable.h
new file mode 100644
index 0000000..87e0c48
--- /dev/null
+++ b/Variable.h
@@ -0,0 +1,39 @@
+/** \file Variable.h
+\brief Define the environment variable
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+/// \brief Un-comment this next line to put ultracopier in debug mode
+#define ULTRACOPIER_DEBUG
+/// \brief Max number of ligne show on the GUI
+#define ULTRACOPIER_DEBUG_MAX_GUI_LINE 5000
+/// \brief the version
+#define ULTRACOPIER_VERSION "0.3.0.5"
+/// \brief the windows version
+#define ULTRACOPIER_WINDOWS_VERSION 0,3,0,5
+// define if the version is portable or not
+//#define ULTRACOPIER_VERSION_PORTABLE
+//#define ULTRACOPIER_VERSION_PORTABLEAPPS
+/// \brief define time to update the speed detection update ont the interface (in ms)
+#define ULTRACOPIER_TIME_INTERFACE_UPDATE 500
+
+/** \brief How many value store to calculate the average value
+ * 5*ULTRACOPIER_TIME_INTERFACE_UPDATE = 5*500 to get 2.5s
+ * */
+#define ULTRACOPIER_MAXVALUESPEEDSTORED 5
+
+/// \brief the socket name, to have unique instance of ultracopier, and pass arguments between the instance
+#define ULTRACOPIER_SOCKETNAME "ultracopier-0.3"
+
+/// \brief to have internet support, to communicate with the web site for update and plugins
+#define ULTRACOPIER_INTERNET_SUPPORT
+
+/// \brief to disable plugin support to do all in one version with static Qt for the protable version
+#define ULTRACOPIER_PLUGIN_SUPPORT
+
+#endif // VARIABLE_H
diff --git a/interface/FacilityInterface.h b/interface/FacilityInterface.h
new file mode 100644
index 0000000..d919498
--- /dev/null
+++ b/interface/FacilityInterface.h
@@ -0,0 +1,38 @@
+/** \file FacilityInterface.h
+\brief Define the class of the facility engine
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef FACILITY_INTERFACE_H
+#define FACILITY_INTERFACE_H
+
+#include <QVariant>
+#include <QString>
+#include <QStringList>
+
+#include "../StructEnumDefinition.h"
+
+/// \brief To define the interface, to pass the facility object from Ultracopier to the plugins without compatibility problem
+class FacilityInterface : public QObject
+{
+ public:
+ /// \brief To force the text re-translation
+ virtual void retranslate() = 0;
+ /// \brief convert size in Byte to String
+ virtual QString sizeToString(const double &size) = 0;
+ /// \brief convert size unit to String
+ virtual QString sizeUnitToString(const SizeUnit &sizeUnit) = 0;
+ /// \brief translate the text
+ virtual QString translateText(const QString &text) = 0;
+ /// \brief speed to string in byte per seconds
+ virtual QString speedToString(const double &speed) = 0;
+ /// \brief Decompose the time in second
+ virtual TimeDecomposition secondsToTimeDecomposition(const quint32 &seconds) = 0;
+ /// \brief have the fonctionnality
+ virtual bool haveFunctionality(const QString &fonctionnality) = 0;
+ /// \brief call the fonctionnality
+ virtual QVariant callFunctionality(const QString &fonctionnality,const QStringList &args=QStringList()) = 0;
+};
+
+#endif // FACILITY_INTERFACE_H
diff --git a/interface/OptionInterface.h b/interface/OptionInterface.h
new file mode 100644
index 0000000..2be66cb
--- /dev/null
+++ b/interface/OptionInterface.h
@@ -0,0 +1,37 @@
+/** \file OptionInterface.h
+\brief Define the class of the option engine
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef OPTION_INTERFACE_H
+#define OPTION_INTERFACE_H
+
+#include <QString>
+#include <QList>
+#include <QVariant>
+#include <QPair>
+
+#include "../StructEnumDefinition.h"
+
+/** \brief to pass the options to the plugin, the instance is created into Ultracopier from the class LocalPluginOptions()
+ * \see LocalPluginOptions()
+ * **/
+class OptionInterface : public QObject
+{
+ Q_OBJECT
+ public:
+ /// \brief To add option group to options
+ virtual bool addOptionGroup(const QList<QPair<QString, QVariant> > &KeysList) = 0;
+ /*/// \brief To remove option group to options, removed to the load plugin
+ virtual bool removeOptionGroup() = 0;*/
+ /// \brief To get option value
+ virtual QVariant getOptionValue(const QString &variableName) = 0;
+ /// \brief To set option value
+ virtual void setOptionValue(const QString &variableName,const QVariant &value) = 0;
+ signals:
+ //void newOptionValue(QString,QVariant);-> disabled because the value will not externally changed, then useless notification
+ void resetOptions();
+};
+
+#endif // OPTION_INTERFACE_H
diff --git a/interface/PluginInterface_CopyEngine.h b/interface/PluginInterface_CopyEngine.h
new file mode 100644
index 0000000..b7198f2
--- /dev/null
+++ b/interface/PluginInterface_CopyEngine.h
@@ -0,0 +1,214 @@
+/** \file PluginInterface_CopyEngine.h
+\brief Define the interface of the plugin of type: copy engine
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef PLUGININTERFACE_COPYENGINE_H
+#define PLUGININTERFACE_COPYENGINE_H
+
+#include <QStringList>
+#include <QString>
+#include <QObject>
+#include <QList>
+#include <QPair>
+#include <QWidget>
+#include <QDateTime>
+
+#include "OptionInterface.h"
+#include "FacilityInterface.h"
+#include "../StructEnumDefinition.h"
+
+/** \brief To define the interface between Ultracopier and the copy engine
+ * This interface support:
+ * - Multiple transfer and multiple transfer progression
+ * - Only the copy mode (source as read only)
+ * - Only manipulation of folder, file, file + folder
+ * - Change on live file size
+ * - Speed is calculated by ultracopier in using the size \see getGeneralProgression()
+ * - Support speed limitation if the engine provide it, else inform Ultracopier
+ * - File/Folder can be added interactively or not
+ * - The collision and error is managed by the plug-in to have useful information (like preview, size, date, ...)
+ * **/
+class PluginInterface_CopyEngine : public QObject
+{
+ Q_OBJECT
+ public:
+ /** \brief to send the options panel
+ * \return return false if have not the options
+ * \param tempWidget the widget to generate on it the options */
+ virtual bool getOptionsEngine(QWidget * tempWidget) = 0;
+ /** \brief to have interface widget to do modal dialog
+ * \param interface to have the widget of the interface, useful for modal dialog */
+ virtual void setInterfacePointer(QWidget * interface) = 0;
+ /** \brief compare the current sources of the copy, with the passed arguments
+ * \param sources the sources list to compares with the current sources list
+ * \return true if have same sources, else false (or empty) */
+ virtual bool haveSameSource(const QStringList &sources) = 0;
+ /** \brief compare the current destination of the copy, with the passed arguments
+ * \param destination the destination to compares with the current destination
+ * \return true if have same destination, else false (or empty) */
+ virtual bool haveSameDestination(const QString &destination) = 0;
+
+
+ //external soft like file browser have send copy/move list to do
+ /** \brief send copy without destination, ask the destination
+ * \param sources the sources list to copy
+ * \return true if the copy have been accepted */
+ virtual bool newCopy(const QStringList &sources) = 0;
+ /** \brief send copy with destination
+ * \param sources the sources list to copy
+ * \param destination the destination to copy
+ * \return true if the copy have been accepted */
+ virtual bool newCopy(const QStringList &sources,const QString &destination) = 0;
+ /** \brief send move without destination, ask the destination
+ * \param sources the sources list to move
+ * \return true if the move have been accepted */
+ virtual bool newMove(const QStringList &sources) = 0;
+ /** \brief send move without destination, ask the destination
+ * \param sources the sources list to move
+ * \param destination the destination to move
+ * \return true if the move have been accepted */
+ virtual bool newMove(const QStringList &sources,const QString &destination) = 0;
+
+
+ /** \brief to get byte read, use by Ultracopier for the speed calculation
+ * real size transfered to right speed calculation */
+ virtual quint64 realByteTransfered() = 0;
+
+
+ /** \brief get the speed limitation
+ * < -1 if not able, 0 if disabled */
+ virtual qint64 getSpeedLimitation() = 0;
+
+
+ //get user action
+ /** \brief get the collision action list */
+ virtual QList<QPair<QString,QString> > getCollisionAction() = 0;
+ /** \brief get the collision error list */
+ virtual QList<QPair<QString,QString> > getErrorAction() = 0;
+
+
+ //transfer list
+ /** \brief to sync the transfer list
+ * Used when the interface is changed, useful to minimize the memory size */
+ virtual void syncTransferList() = 0;
+ public slots:
+ //user ask ask to add folder (add it with interface ask source/destination)
+ /** \brief add folder called on the interface
+ * Used by manual adding */
+ virtual bool userAddFolder(const CopyMode &mode) = 0;
+ /** \brief add file called on the interface
+ * Used by manual adding */
+ virtual bool userAddFile(const CopyMode &mode) = 0;
+
+
+ //action on the transfer
+ /// \brief put the transfer in pause
+ virtual void pause() = 0;
+ /// \brief resume the transfer
+ virtual void resume() = 0;
+ /** \brief skip one transfer entry
+ * \param id id of the file to remove */
+ virtual void skip(const quint64 &id) = 0;
+ /// \brief cancel all the transfer
+ virtual void cancel() = 0;
+
+
+ //edit the transfer list
+ /** \brief remove the selected item
+ * \param ids ids is the id list of the selected items */
+ virtual void removeItems(const QList<int> &ids) = 0;
+ /** \brief move on top of the list the selected item
+ * \param ids ids is the id list of the selected items */
+ virtual void moveItemsOnTop(const QList<int> &ids) = 0;
+ /** \brief move up the list the selected item
+ * \param ids ids is the id list of the selected items */
+ virtual void moveItemsUp(const QList<int> &ids) = 0;
+ /** \brief move down the list the selected item
+ * \param ids ids is the id list of the selected items */
+ virtual void moveItemsDown(const QList<int> &ids) = 0;
+ /** \brief move on bottom of the list the selected item
+ * \param ids ids is the id list of the selected items */
+ virtual void moveItemsOnBottom(const QList<int> &ids) = 0;
+ /// \brief export the transfer list into a file
+ virtual void exportTransferList() = 0;
+ /// \brief import the transfer list into a file
+ virtual void importTransferList() = 0;
+
+
+ /** \brief to set the speed limitation
+ * -1 if not able, 0 if disabled */
+ virtual bool setSpeedLimitation(const qint64 &speedLimitation) = 0;
+
+
+ //action
+ /// \brief to set the collision action
+ virtual void setCollisionAction(const QString &action) = 0;
+ /// \brief to set the error action
+ virtual void setErrorAction(const QString &action) = 0;
+ /* signal to implement
+ signals:
+ //send information about the copy
+ void actionInProgess(EngineActionInProgress engineActionInProgress); //should update interface information on this event
+
+ void newFolderListing(QString path);
+ void newCollisionAction(QString action);
+ void newErrorAction(QString action);
+ void isInPause(bool isInPause);
+
+ void newActionOnList(const QList<returnActionOnCopyList>&);///very important, need be temporized to group the modification to do and not flood the interface
+ void syncReady();
+
+ / ** \brief to get the progression for a specific file
+ * \param id the id of the transfer, id send during population the transfer list
+ * first = current transfered byte, second = byte to transfer * /
+ void pushFileProgression(const QList<ProgressionItem> &progressionList);
+ //get information about the copy
+ / ** \brief to get the general progression
+ * first = current transfered byte, second = byte to transfer * /
+ void pushGeneralProgression(const quint64 &,const quint64 &);
+
+
+ void cancelAll();
+
+ //send error occurred
+ void error(QString path,quint64 size,QDateTime mtime,QString error);
+ //for the extra logging
+ void rmPath(QString path);
+ void mkPath(QString path);*/
+};
+
+/// \brief To define the interface for the factory to do copy engine instance
+class PluginInterface_CopyEngineFactory : public QObject
+{
+ Q_OBJECT
+ public:
+ /// \brief to get one instance
+ virtual PluginInterface_CopyEngine * getInstance() = 0;
+ /// \brief to set resources, writePath can be empty if read only mode
+ virtual void setResources(OptionInterface * options,const QString &writePath,const QString &pluginPath,FacilityInterface * facilityInterface,const bool &portableVersion) = 0;
+ //get mode allowed
+ /// \brief define if can copy file, folder or both
+ virtual CopyType getCopyType() = 0;
+ /// \brief define if can import/export or nothing
+ virtual TransferListOperation getTransferListOperation() = 0;
+ /// \brief define if can only copy, or copy and move
+ virtual bool canDoOnlyCopy() = 0;
+ /// \brief to get the supported protocols for the source
+ virtual QStringList supportedProtocolsForTheSource() = 0;
+ /// \brief to get the supported protocols for the destination
+ virtual QStringList supportedProtocolsForTheDestination() = 0;
+ /// \brief to get the options of the copy engine
+ virtual QWidget * options() = 0;
+ public slots:
+ /// \brief to reset the options
+ virtual void resetOptions() = 0;
+ /// \brief to reload the translation, because the new language have been loaded
+ virtual void newLanguageLoaded() = 0;
+
+};
+
+Q_DECLARE_INTERFACE(PluginInterface_CopyEngineFactory,"first-world.info.ultracopier.PluginInterface.CopyEngineFactory/0.3.0.5");
+
+#endif // PLUGININTERFACE_COPYENGINE_H
diff --git a/interface/PluginInterface_Listener.h b/interface/PluginInterface_Listener.h
new file mode 100644
index 0000000..7d6508b
--- /dev/null
+++ b/interface/PluginInterface_Listener.h
@@ -0,0 +1,48 @@
+/** \file PluginInterface_Listener.h
+\brief Define the interface of the plugin of type: listener
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef PLUGININTERFACE_LISTENER_H
+#define PLUGININTERFACE_LISTENER_H
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+
+#include "OptionInterface.h"
+
+#include "../StructEnumDefinition.h"
+
+/** \brief To define the interface between Ultracopier and the listener
+ * */
+class PluginInterface_Listener : public QObject
+{
+ Q_OBJECT
+ public:
+ /// \brief put this plugin in listen mode
+ virtual void listen() = 0;
+ /// \brief put close the listen
+ virtual void close() = 0;
+ /// \brief to get the error string
+ virtual const QString errorString() = 0;
+ /// \brief set the resources for the plugin
+ virtual void setResources(OptionInterface * options,QString writePath,QString pluginPath,bool portableVersion) = 0;
+ public slots:
+ /// \brief send when copy is finished
+ virtual void transferFinished(quint32 orderId,bool withError) = 0;
+ /// \brief send when copy is canceled
+ virtual void transferCanceled(quint32 orderId) = 0;
+ /* signal to implement
+ signals:
+ void newState(ListeningState state);
+ void newCopy(quint32 orderId,QStringList sources);
+ void newCopy(quint32 orderId,QStringList sources,QString destination);
+ void newMove(quint32 orderId,QStringList sources);
+ void newMove(quint32 orderId,QStringList sources,QString destination);*/
+};
+
+Q_DECLARE_INTERFACE(PluginInterface_Listener,"first-world.info.ultracopier.PluginInterface.Listener/0.3.0.5");
+
+#endif // PLUGININTERFACE_LISTENER_H
diff --git a/interface/PluginInterface_PluginLoader.h b/interface/PluginInterface_PluginLoader.h
new file mode 100644
index 0000000..e04bcd9
--- /dev/null
+++ b/interface/PluginInterface_PluginLoader.h
@@ -0,0 +1,33 @@
+/** \file PluginInterface_PluginLoader.h
+\brief Define the interface of the plugin of type: plugin loader
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef PLUGININTERFACE_PLUGINLOADER_H
+#define PLUGININTERFACE_PLUGINLOADER_H
+
+#include <QString>
+
+#include "OptionInterface.h"
+
+#include "../StructEnumDefinition.h"
+
+/** \brief To define the interface between Ultracopier and the plugin loader
+ * */
+class PluginInterface_PluginLoader : public QObject
+{
+ Q_OBJECT
+ public:
+ /// \brief try enable/disable the catching
+ virtual void setEnabled(bool) = 0;
+ /// \brief to set resources, writePath can be empty if read only mode
+ virtual void setResources(OptionInterface * options,QString writePath,QString pluginPath,bool portableVersion) = 0;
+ /* signal to implement
+ signals:
+ void newState(CatchState);*/
+};
+
+Q_DECLARE_INTERFACE(PluginInterface_PluginLoader,"first-world.info.ultracopier.PluginInterface.PluginLoader/0.3.0.1");
+
+#endif // PLUGININTERFACE_PLUGINLOADER_H
diff --git a/interface/PluginInterface_SessionLoader.h b/interface/PluginInterface_SessionLoader.h
new file mode 100644
index 0000000..2e49fa3
--- /dev/null
+++ b/interface/PluginInterface_SessionLoader.h
@@ -0,0 +1,31 @@
+/** \file PluginInterface_SessionLoader.h
+\brief Define the interface of the plugin of type: session loader
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef PLUGININTERFACE_SESSIONLOADER_H
+#define PLUGININTERFACE_SESSIONLOADER_H
+
+#include <QString>
+
+#include "OptionInterface.h"
+
+#include "../StructEnumDefinition.h"
+
+/** \brief To define the interface between Ultracopier and the session loader
+ * */
+class PluginInterface_SessionLoader : public QObject
+{
+ public:
+ /// \brief set enabled/disabled
+ virtual void setEnabled(bool) = 0;
+ /// \brief get if is enabled
+ virtual bool getEnabled() = 0;
+ /// \brief set the resources
+ virtual void setResources(OptionInterface * options,QString writePath,QString pluginPath,bool portableVersion) = 0;
+};
+
+Q_DECLARE_INTERFACE(PluginInterface_SessionLoader,"first-world.info.ultracopier.PluginInterface.SessionLoader/0.3.0.4");
+
+#endif // PLUGININTERFACE_SESSIONLOADER_H
diff --git a/interface/PluginInterface_Themes.h b/interface/PluginInterface_Themes.h
new file mode 100644
index 0000000..8b9d40b
--- /dev/null
+++ b/interface/PluginInterface_Themes.h
@@ -0,0 +1,123 @@
+/** \file PluginInterface_Themes.h
+\brief Define the interface of the plugin of type: copy engine
+\author alpha_one_x86
+\version 0.3
+\date 2010 */
+
+#ifndef PLUGININTERFACE_THEMES_H
+#define PLUGININTERFACE_THEMES_H
+
+#include <QStringList>
+#include <QString>
+#include <QObject>
+#include <QWidget>
+#include <QList>
+#include <QPair>
+#include <QUrl>
+#include <QIcon>
+
+#include "OptionInterface.h"
+#include "FacilityInterface.h"
+#include "../StructEnumDefinition.h"
+
+/** \brief To define the interface between Ultracopier and the interface
+ * */
+class PluginInterface_Themes : public QWidget
+{
+ Q_OBJECT
+ public slots:
+ //send information about the copy
+ /// \brief to set the action in progress
+ virtual void actionInProgess(EngineActionInProgress) = 0;
+
+ /// \brief the new folder is listing
+ virtual void newFolderListing(const QString &path) = 0;
+ /** \brief show the detected speed
+ * in byte per seconds */
+ virtual void detectedSpeed(const quint64 &speed) = 0;
+ /** \brief show the remaining time
+ * time in seconds */
+ virtual void remainingTime(const int &remainingSeconds) = 0;
+ /// \brief set the current collision action
+ virtual void newCollisionAction(const QString &action) = 0;
+ /// \brief set the current error action
+ virtual void newErrorAction(const QString &action) = 0;
+ /// \brief set one error is detected
+ virtual void errorDetected() = 0;
+ /** \brief the max speed used
+ * in byte per seconds, -1 if not able, 0 if disabled */
+ virtual bool setSpeedLimitation(const qint64 &speedLimitation) = 0;
+ /// \brief get action on the transfer list (add/move/remove)
+ virtual void getActionOnList(const QList<returnActionOnCopyList> &returnActions) = 0;
+ /// \brief show the general progression
+ virtual void setGeneralProgression(const quint64 &current,const quint64 &total) = 0;
+ /// \brief show the file progression
+ virtual void setFileProgression(const QList<ProgressionItem> &progressionList) = 0;
+ public:
+ /// \brief get the widget for the copy engine
+ virtual QWidget * getOptionsEngineWidget() = 0;
+ /// \brief to set if the copy engine is found
+ virtual void getOptionsEngineEnabled(bool isEnabled) = 0;
+ /// \brief set collision action
+ virtual void setCollisionAction(const QList<QPair<QString,QString> > &collisionActionList) = 0;
+ /// \brief set error action
+ virtual void setErrorAction(const QList<QPair<QString,QString> > &errorActionList) = 0;
+ /// \brief set the copyType -> file or folder
+ virtual void setCopyType(CopyType) = 0;
+ /// \brief set the copyMove -> copy or move, to force in copy or move, else support both
+ virtual void forceCopyMode(CopyMode) = 0;
+ /// \brief set if transfer list is exportable/importable
+ virtual void setTransferListOperation(TransferListOperation transferListOperation) = 0;
+ /** \brief set if the order is external (like file manager copy)
+ * to notify the interface, which can hide add folder/filer button */
+ virtual void haveExternalOrder() = 0;
+ /// \brief set if is in pause
+ virtual void isInPause(bool) = 0;
+ /* signal to implement
+ signals:
+ //set the transfer list
+ void removeItems(QList<int> ids);
+ void moveItemsOnTop(QList<int> ids);
+ void moveItemsUp(QList<int> ids);
+ void moveItemsDown(QList<int> ids);
+ void moveItemsOnBottom(QList<int> ids);
+ void exportTransferList();
+ void importTransferList();
+ //user ask ask to add folder (add it with interface ask source/destination)
+ void userAddFolder(CopyMode);
+ void userAddFile(CopyMode);
+ void urlDropped(QList<QUrl> urls);
+ //action on the copy
+ void pause();
+ void resume();
+ void skip(quint64 id);
+ void cancel();
+ //edit the action
+ void sendCollisionAction(QString action);
+ void sendErrorAction(QString action);
+ void newSpeedLimitation(qint64);///< -1 if not able, 0 if disabled*/
+};
+
+/// \brief To define the interface for the factory to do themes instance
+class PluginInterface_ThemesFactory : public QObject
+{
+ Q_OBJECT
+ public:
+ /// \brief to get one instance
+ virtual PluginInterface_Themes * getInstance() = 0;
+ /// \brief to set resources, writePath can be empty if read only mode
+ virtual void setResources(OptionInterface * options,const QString &writePath,const QString &pluginPath,FacilityInterface * facilityInterface,bool portableVersion) = 0;
+ /// \brief to get the default options widget
+ virtual QWidget * options() = 0;
+ /// \brief to get a resource icon
+ virtual QIcon getIcon(const QString &fileName) = 0;
+ public slots:
+ /// \brief to reset as default the local options
+ virtual void resetOptions() = 0;
+ /// \brief retranslate the language because the language have changed
+ virtual void newLanguageLoaded() = 0;
+};
+
+Q_DECLARE_INTERFACE(PluginInterface_ThemesFactory,"first-world.info.ultracopier.PluginInterface.ThemesFactory/0.3.0.5");
+
+#endif // PLUGININTERFACE_THEMES_H
diff --git a/lib/qt-tar-xz/QTarDecode.cpp b/lib/qt-tar-xz/QTarDecode.cpp
new file mode 100644
index 0000000..fe15359
--- /dev/null
+++ b/lib/qt-tar-xz/QTarDecode.cpp
@@ -0,0 +1,113 @@
+/** \file QTarDecode.cpp
+\brief To read a tar data block
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "QTarDecode.h"
+#include <QDebug>
+
+QTarDecode::QTarDecode()
+{
+ error="Unknow error";
+}
+
+QString QTarDecode::errorString()
+{
+ return error;
+}
+
+void QTarDecode::setErrorString(QString error)
+{
+ this->error=error;
+ fileList.clear();
+ dataList.clear();
+}
+
+bool QTarDecode::decodeData(QByteArray data)
+{
+ setErrorString("Unknow error");
+ if(data.size()<1024)
+ return false;
+ int offset=0;
+ while(offset<data.size())
+ {
+ //load the file name from ascii, from 0+offset with size of 100
+ QString fileName=data.mid(0+offset,100);
+ //load the file type
+ QString fileType=data.mid(156+offset,1);
+ //load the ustar string
+ QString ustar=data.mid(257+offset,5);
+ //load the ustar version
+ QString ustarVersion=data.mid(263+offset,2);
+ bool ok;
+ //load the file size from ascii, from 124+offset with size of 12
+ int finalSize=QString(data.mid(124+offset,12)).toUInt(&ok,8);
+ //if the size conversion to qulonglong have failed, then qui with error
+ if(ok==false)
+ {
+ //if((offset+1024)==data.size())
+ //it's the end of the archive, no more verification
+ break;
+ /*else
+ {
+ setErrorString("Unable to convert ascii size at "+QString::number(124+offset)+" to usigned long long: \""+QString(data.mid(124+offset,12))+"\"");
+ return false;
+ }*/
+ }
+ //if check if the ustar not found
+ if(ustar!="ustar")
+ {
+ setErrorString("\"ustar\" string not found at "+QString::number(257+offset)+", content: \""+ustar+"\"");
+ return false;
+ }
+ if(ustarVersion!="00")
+ {
+ setErrorString("ustar version string is wrong, content:\""+ustarVersion+"\"");
+ return false;
+ }
+ //check if the file have the good size for load the data
+ if((offset+512+finalSize)>data.size())
+ {
+ setErrorString("The tar file seem be too short");
+ return false;
+ }
+ if(fileType=="0") //this code manage only the file, then only the file is returned
+ {
+ QByteArray fileData=data.mid(512+offset,finalSize);
+ fileList << fileName;
+ dataList << fileData;
+ }
+ //calculate the offset for the next header
+ bool retenu=((finalSize%512)!=0);
+ //go to the next header
+ offset+=512+(finalSize/512+retenu)*512;
+ }
+ if(fileList.size()>0)
+ {
+ QString baseDirToTest=fileList.at(0);
+ baseDirToTest.remove(QRegExp("/.*$"));
+ baseDirToTest+='/';
+ bool isFoundForAllEntries=true;
+ for (int i = 0; i < fileList.size(); ++i)
+ if(!fileList.at(i).startsWith(baseDirToTest))
+ isFoundForAllEntries=false;
+ if(isFoundForAllEntries)
+ for (int i = 0; i < fileList.size(); ++i)
+ fileList[i].remove(0,baseDirToTest.size());
+ }
+ return true;
+}
+
+QStringList QTarDecode::getFileList()
+{
+ return fileList;
+}
+
+QList<QByteArray> QTarDecode::getDataList()
+{
+ return dataList;
+}
+
+
diff --git a/lib/qt-tar-xz/QTarDecode.h b/lib/qt-tar-xz/QTarDecode.h
new file mode 100644
index 0000000..6e8e5e5
--- /dev/null
+++ b/lib/qt-tar-xz/QTarDecode.h
@@ -0,0 +1,37 @@
+/** \file QTarDecode.h
+\brief To read a tar data block
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef QTARDECODE_H
+#define QTARDECODE_H
+
+#include <QObject>
+#include <QList>
+#include <QByteArray>
+#include <QString>
+#include <QStringList>
+
+/// \brief read the raw tar data, and organize it into data structure
+class QTarDecode : public QObject
+{
+ public:
+ QTarDecode();
+ /// \brief to get the file list
+ QStringList getFileList();
+ /// \brief to get the data of the file
+ QList<QByteArray> getDataList();
+ /// \brief to pass the raw tar data
+ bool decodeData(QByteArray data);
+ /// \brief to return error string
+ QString errorString();
+ private:
+ QStringList fileList;
+ QList<QByteArray> dataList;
+ QString error;
+ void setErrorString(QString error);
+};
+
+#endif // QTARDECODE_H
diff --git a/lib/qt-tar-xz/QXzDecode.cpp b/lib/qt-tar-xz/QXzDecode.cpp
new file mode 100644
index 0000000..6aa13bb
--- /dev/null
+++ b/lib/qt-tar-xz/QXzDecode.cpp
@@ -0,0 +1,148 @@
+/** \file QXzDecode.cpp
+\brief To decompress a xz stream
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "QXzDecode.h"
+#include <QDebug>
+extern "C" {
+#include "xz.h"
+}
+
+static uint8_t in[BUFSIZ];
+static uint8_t out[BUFSIZ];
+
+QXzDecode::QXzDecode(QByteArray data,quint64 maxSize)
+{
+ error="Unknow error";
+ this->data=data;
+ this->maxSize=maxSize;
+ isDecoded=false;
+}
+
+bool QXzDecode::decodeStream(QDataStream *stream_xz_decode_in,QDataStream *stream_xz_decode_out)
+{
+ isDecoded=false;
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+
+ xz_crc32_init();
+
+ /*
+ * Support up to 64 MiB dictionary. The actually needed memory
+ * is allocated once the headers have been parsed.
+ */
+ s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
+ if (s == NULL) {
+ error=tr("Memory allocation failed");
+ xz_dec_end(s);
+ return isDecoded;
+ }
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = 0;
+ b.out = out;
+ b.out_pos = 0;
+ b.out_size = BUFSIZ;
+
+ while (true) {
+ //input of data
+ if (b.in_pos == b.in_size) {
+ b.in_size = stream_xz_decode_in->readRawData((char *)in,sizeof(in));
+ b.in_pos = 0;
+ }
+
+ ret = xz_dec_run(s, &b);
+
+ //output of data
+ if (b.out_pos == sizeof(out))
+ {
+ if (stream_xz_decode_out->writeRawData((char *)out,b.out_pos) != (int)b.out_pos)
+ {
+ error=tr("Write error");
+ xz_dec_end(s);
+ return isDecoded;
+ }
+ b.out_pos = 0;
+ }
+
+ if (ret == XZ_OK)
+ continue;
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (ret == XZ_UNSUPPORTED_CHECK) {
+ continue;
+ }
+#endif
+
+ if (stream_xz_decode_out->writeRawData((char *)out,b.out_pos) != (int)b.out_pos)
+ {
+ error=tr("Write error");
+ xz_dec_end(s);
+ return isDecoded;
+ }
+
+ switch (ret) {
+ case XZ_STREAM_END:
+ xz_dec_end(s);
+ isDecoded=true;
+ return isDecoded;
+ case XZ_MEM_ERROR:
+ error=tr("Memory allocation failed");
+ xz_dec_end(s);
+ return isDecoded;
+ case XZ_MEMLIMIT_ERROR:
+ error=tr("Memory usage limit reached");
+ xz_dec_end(s);
+ return isDecoded;
+ case XZ_FORMAT_ERROR:
+ error=tr("Not a .xz file");
+ xz_dec_end(s);
+ return isDecoded;
+ case XZ_OPTIONS_ERROR:
+ error=tr("Unsupported options in the .xz headers");
+ xz_dec_end(s);
+ return isDecoded;
+ case XZ_DATA_ERROR:
+ case XZ_BUF_ERROR:
+ error=tr("The file is corrupted");
+ xz_dec_end(s);
+ return isDecoded;
+ default:
+ error=tr("Bug!");
+ xz_dec_end(s);
+ return isDecoded;
+ }
+ }
+}
+
+bool QXzDecode::decode()
+{
+ if(data.size() < 32) // check the minimal size
+ error=tr("The input data is too short");
+ QByteArray outputData;
+ QDataStream stream_xz_decode_in(&data,QIODevice::ReadOnly);
+ QDataStream stream_xz_decode_out(&outputData,QIODevice::WriteOnly);
+ int returnVal=decodeStream(&stream_xz_decode_in,&stream_xz_decode_out);
+ data=outputData;
+ return returnVal;
+}
+
+QByteArray QXzDecode::decodedData()
+{
+ if(isDecoded)
+ return data;
+ else
+ return QByteArray();
+}
+
+QString QXzDecode::errorString()
+{
+ return error;
+}
+
+
diff --git a/lib/qt-tar-xz/QXzDecode.h b/lib/qt-tar-xz/QXzDecode.h
new file mode 100644
index 0000000..9a654f0
--- /dev/null
+++ b/lib/qt-tar-xz/QXzDecode.h
@@ -0,0 +1,42 @@
+/** \file QXzDecode.h
+\brief To decompress a xz stream
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef QXZDECODE_H
+#define QXZDECODE_H
+
+#include <QObject>
+#include <QByteArray>
+#include <QDataStream>
+
+//comment this to check integrity of compressed file, compressed via: xz --check=crc32 YourFile
+//#define XZ_DEC_ANY_CHECK
+
+/// \brief The decode class for the xz stream
+class QXzDecode : public QObject
+{
+ public:
+ /** \brief create the object to decode it
+ * \param data the compressed data
+ * \param maxSize the max size
+ * **/
+ QXzDecode(QByteArray data,quint64 maxSize=0);
+ /// \brief lunch the decode
+ bool decode();
+ /// \brief the error string
+ QString errorString();
+ /// \brief the un-compressed data
+ QByteArray decodedData();
+ /// \brief un-compress the data by stream
+ bool decodeStream(QDataStream *stream_xz_decode_in,QDataStream *stream_xz_decode_out);
+ private:
+ QByteArray data;
+ QString error;
+ bool isDecoded;
+ quint64 maxSize;
+};
+
+#endif // QXZDECODE_H
diff --git a/lib/qt-tar-xz/QXzDecodeThread.cpp b/lib/qt-tar-xz/QXzDecodeThread.cpp
new file mode 100644
index 0000000..9872cef
--- /dev/null
+++ b/lib/qt-tar-xz/QXzDecodeThread.cpp
@@ -0,0 +1,50 @@
+/** \file QXzDecodeThread.cpp
+\brief To have thread to decode the data
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#include "QXzDecodeThread.h"
+
+QXzDecodeThread::QXzDecodeThread()
+{
+ moveToThread(this);
+ DataToDecode=NULL;
+ error=false;
+}
+
+QXzDecodeThread::~QXzDecodeThread()
+{
+ if(DataToDecode!=NULL)
+ delete DataToDecode;
+}
+
+void QXzDecodeThread::setData(QByteArray data,quint64 maxSize)
+{
+ if(DataToDecode!=NULL)
+ delete DataToDecode;
+ DataToDecode=new QXzDecode(data,maxSize);
+}
+
+bool QXzDecodeThread::errorFound()
+{
+ return error;
+}
+
+QString QXzDecodeThread::errorString()
+{
+ return DataToDecode->errorString();
+}
+
+QByteArray QXzDecodeThread::decodedData()
+{
+ return DataToDecode->decodedData();
+}
+
+void QXzDecodeThread::run()
+{
+ error=!DataToDecode->decode();
+ emit decodedIsFinish();
+}
+
diff --git a/lib/qt-tar-xz/QXzDecodeThread.h b/lib/qt-tar-xz/QXzDecodeThread.h
new file mode 100644
index 0000000..6fedc22
--- /dev/null
+++ b/lib/qt-tar-xz/QXzDecodeThread.h
@@ -0,0 +1,39 @@
+/** \file QXzDecodeThread.h
+\brief To have thread to decode the data
+\author alpha_one_x86
+\version 0.3
+\date 2010
+\licence GPL3, see the file COPYING */
+
+#ifndef QXZDECODETHREAD_H
+#define QXZDECODETHREAD_H
+
+#include <QThread>
+#include "QXzDecode.h"
+
+/// \brief to decode the xz via a thread
+class QXzDecodeThread : public QThread
+{
+ Q_OBJECT
+ public:
+ QXzDecodeThread();
+ ~QXzDecodeThread();
+ /// \brief to return if the error have been found
+ bool errorFound();
+ /// \brief to return the error string
+ QString errorString();
+ /// \brief to get the decoded data
+ QByteArray decodedData();
+ /// \brief to send the data
+ void setData(QByteArray data,quint64 maxSize=0);
+ protected:
+ void run();
+ private:
+ /// \brief to have temporary storage
+ QXzDecode *DataToDecode;
+ bool error;
+ signals:
+ void decodedIsFinish();
+};
+
+#endif // QXZDECODETHREAD_H
diff --git a/lib/qt-tar-xz/xz.h b/lib/qt-tar-xz/xz.h
new file mode 100644
index 0000000..470f6df
--- /dev/null
+++ b/lib/qt-tar-xz/xz.h
@@ -0,0 +1,273 @@
+/*
+ * XZ decompressor
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#define XZ_DEC_ANY_CHECK
+
+#ifndef XZ_H
+#define XZ_H
+
+#ifdef __KERNEL__
+# include <linux/stddef.h>
+# include <linux/types.h>
+#else
+# include <stddef.h>
+# include <stdint.h>
+#endif
+
+/* In Linux, this is used to make extern functions static when needed. */
+#ifndef XZ_EXTERN
+# define XZ_EXTERN extern
+#endif
+
+/* In Linux, this is used to mark the functions with __init when needed. */
+#ifndef XZ_FUNC
+# define XZ_FUNC
+#endif
+
+/**
+ * enum xz_mode - Operation mode
+ *
+ * @XZ_SINGLE: Single-call mode. This uses less RAM than
+ * than multi-call modes, because the LZMA2
+ * dictionary doesn't need to be allocated as
+ * part of the decoder state. All required data
+ * structures are allocated at initialization,
+ * so xz_dec_run() cannot return XZ_MEM_ERROR.
+ * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
+ * dictionary buffer. All data structures are
+ * allocated at initialization, so xz_dec_run()
+ * cannot return XZ_MEM_ERROR.
+ * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
+ * allocated once the required size has been
+ * parsed from the stream headers. If the
+ * allocation fails, xz_dec_run() will return
+ * XZ_MEM_ERROR.
+ *
+ * It is possible to enable support only for a subset of the above
+ * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
+ * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
+ * with support for all operation modes, but the preboot code may
+ * be built with fewer features to minimize code size.
+ */
+enum xz_mode {
+ XZ_SINGLE,
+ XZ_PREALLOC,
+ XZ_DYNALLOC
+};
+
+/**
+ * enum xz_ret - Return codes
+ * @XZ_OK: Everything is OK so far. More input or more
+ * output space is required to continue. This
+ * return code is possible only in multi-call mode
+ * (XZ_PREALLOC or XZ_DYNALLOC).
+ * @XZ_STREAM_END: Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
+ * is still possible in multi-call mode by simply
+ * calling xz_dec_run() again.
+ * NOTE: This return value is used only if
+ * XZ_DEC_ANY_CHECK was defined at build time,
+ * which is not used in the kernel. Unsupported
+ * check types return XZ_OPTIONS_ERROR if
+ * XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEM_ERROR: Allocating memory failed. This return code is
+ * possible only if the decoder was initialized
+ * with XZ_DYNALLOC. The amount of memory that was
+ * tried to be allocated was no more than the
+ * dict_max argument given to xz_dec_init().
+ * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
+ * allowed by the dict_max argument given to
+ * xz_dec_init(). This return value is possible
+ * only in multi-call mode (XZ_PREALLOC or
+ * XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
+ * ignores the dict_max argument.
+ * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
+ * bytes).
+ * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
+ * compression options. In the decoder this means
+ * that the header CRC32 matches, but the header
+ * itself specifies something that we don't support.
+ * @XZ_DATA_ERROR: Compressed data is corrupt.
+ * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
+ * different between multi-call and single-call
+ * mode; more information below.
+ *
+ * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
+ * to XZ code cannot consume any input and cannot produce any new output.
+ * This happens when there is no new input available, or the output buffer
+ * is full while at least one output byte is still pending. Assuming your
+ * code is not buggy, you can get this error only when decoding a compressed
+ * stream that is truncated or otherwise corrupt.
+ *
+ * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
+ * is too small, or the compressed input is corrupt in a way that makes the
+ * decoder produce more output than the caller expected. When it is
+ * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
+ * is used instead of XZ_BUF_ERROR.
+ */
+enum xz_ret {
+ XZ_OK,
+ XZ_STREAM_END,
+ XZ_UNSUPPORTED_CHECK,
+ XZ_MEM_ERROR,
+ XZ_MEMLIMIT_ERROR,
+ XZ_FORMAT_ERROR,
+ XZ_OPTIONS_ERROR,
+ XZ_DATA_ERROR,
+ XZ_BUF_ERROR
+};
+
+/**
+ * struct xz_buf - Passing input and output buffers to XZ code
+ * @in: Beginning of the input buffer. This may be NULL if and only
+ * if in_pos is equal to in_size.
+ * @in_pos: Current position in the input buffer. This must not exceed
+ * in_size.
+ * @in_size: Size of the input buffer
+ * @out: Beginning of the output buffer. This may be NULL if and only
+ * if out_pos is equal to out_size.
+ * @out_pos: Current position in the output buffer. This must not exceed
+ * out_size.
+ * @out_size: Size of the output buffer
+ *
+ * Only the contents of the output buffer from out[out_pos] onward, and
+ * the variables in_pos and out_pos are modified by the XZ code.
+ */
+struct xz_buf {
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_size;
+
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+};
+
+/**
+ * struct xz_dec - Opaque type to hold the XZ decoder state
+ */
+struct xz_dec;
+
+/**
+ * xz_dec_init() - Allocate and initialize a XZ decoder state
+ * @mode: Operation mode
+ * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
+ * multi-call decoding. This is ignored in single-call mode
+ * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
+ * or 2^n + 2^(n-1) bytes (the latter sizes are less common
+ * in practice), so other values for dict_max don't make sense.
+ * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
+ * 512 KiB, and 1 MiB are probably the only reasonable values,
+ * except for kernel and initramfs images where a bigger
+ * dictionary can be fine and useful.
+ *
+ * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
+ * once. The caller must provide enough output space or the decoding will
+ * fail. The output space is used as the dictionary buffer, which is why
+ * there is no need to allocate the dictionary as part of the decoder's
+ * internal state.
+ *
+ * Because the output buffer is used as the workspace, streams encoded using
+ * a big dictionary are not a problem in single-call mode. It is enough that
+ * the output buffer is big enough to hold the actual uncompressed data; it
+ * can be smaller than the dictionary size stored in the stream headers.
+ *
+ * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
+ * of memory is preallocated for the LZMA2 dictionary. This way there is no
+ * risk that xz_dec_run() could run out of memory, since xz_dec_run() will
+ * never allocate any memory. Instead, if the preallocated dictionary is too
+ * small for decoding the given input stream, xz_dec_run() will return
+ * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
+ * decoded to avoid allocating excessive amount of memory for the dictionary.
+ *
+ * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
+ * dict_max specifies the maximum allowed dictionary size that xz_dec_run()
+ * may allocate once it has parsed the dictionary size from the stream
+ * headers. This way excessive allocations can be avoided while still
+ * limiting the maximum memory usage to a sane value to prevent running the
+ * system out of memory when decompressing streams from untrusted sources.
+ *
+ * On success, xz_dec_init() returns a pointer to struct xz_dec, which is
+ * ready to be used with xz_dec_run(). If memory allocation fails,
+ * xz_dec_init() returns NULL.
+ */
+XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
+ enum xz_mode mode, uint32_t dict_max);
+
+/**
+ * xz_dec_run() - Run the XZ decoder
+ * @s: Decoder state allocated using xz_dec_init()
+ * @b: Input and output buffers
+ *
+ * The possible return values depend on build options and operation mode.
+ * See enum xz_ret for details.
+ *
+ * NOTE: If an error occurs in single-call mode (return value is not
+ * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the
+ * contents of the output buffer from b->out[b->out_pos] onward are
+ * undefined. This is true even after XZ_BUF_ERROR, because with some filter
+ * chains, there may be a second pass over the output buffer, and this pass
+ * cannot be properly done if the output buffer is truncated. Thus, you
+ * cannot give the single-call decoder a too small buffer and then expect to
+ * get that amount valid data from the beginning of the stream. You must use
+ * the multi-call decoder if you don't want to uncompress the whole stream.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b);
+
+/**
+ * xz_dec_reset() - Reset an already allocated decoder state
+ * @s: Decoder state allocated using xz_dec_init()
+ *
+ * This function can be used to reset the multi-call decoder state without
+ * freeing and reallocating memory with xz_dec_end() and xz_dec_init().
+ *
+ * In single-call mode, xz_dec_reset() is always called in the beginning of
+ * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
+ * multi-call mode.
+ */
+XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s);
+
+/**
+ * xz_dec_end() - Free the memory allocated for the decoder state
+ * @s: Decoder state allocated using xz_dec_init(). If s is NULL,
+ * this function does nothing.
+ */
+XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s);
+
+/*
+ * Standalone build (userspace build or in-kernel build for boot time use)
+ * needs a CRC32 implementation. For normal in-kernel use, kernel's own
+ * CRC32 module is used instead, and users of this module don't need to
+ * care about the functions below.
+ */
+#ifndef XZ_INTERNAL_CRC32
+# ifdef __KERNEL__
+# define XZ_INTERNAL_CRC32 0
+# else
+# define XZ_INTERNAL_CRC32 1
+# endif
+#endif
+
+#if XZ_INTERNAL_CRC32
+/*
+ * This must be called before any other xz_* function to initialize
+ * the CRC32 lookup table.
+ */
+XZ_EXTERN void XZ_FUNC xz_crc32_init(void);
+
+/*
+ * Update CRC32 value using the polynomial from IEEE-802.3. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint32_t XZ_FUNC xz_crc32(
+ const uint8_t *buf, size_t size, uint32_t crc);
+#endif
+#endif
diff --git a/lib/qt-tar-xz/xz_config.h b/lib/qt-tar-xz/xz_config.h
new file mode 100644
index 0000000..9d714f3
--- /dev/null
+++ b/lib/qt-tar-xz/xz_config.h
@@ -0,0 +1,123 @@
+/*
+ * Private includes and definitions for userspace use of XZ Embedded
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_CONFIG_H
+#define XZ_CONFIG_H
+
+/* Uncomment as needed to enable BCJ filter decoders. */
+/* #define XZ_DEC_X86 */
+/* #define XZ_DEC_POWERPC */
+/* #define XZ_DEC_IA64 */
+/* #define XZ_DEC_ARM */
+/* #define XZ_DEC_ARMTHUMB */
+/* #define XZ_DEC_SPARC */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xz.h"
+
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
+#ifndef min
+# define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+#define min_t(type, x, y) min(x, y)
+
+/*
+ * Some functions have been marked with __always_inline to keep the
+ * performance reasonable even when the compiler is optimizing for
+ * small code size. You may be able to save a few bytes by #defining
+ * __always_inline to plain inline, but don't complain if the code
+ * becomes slow.
+ *
+ * NOTE: System headers on GNU/Linux may #define this macro already,
+ * so if you want to change it, you need to #undef it first.
+ */
+#ifndef __always_inline
+# ifdef __GNUC__
+# define __always_inline \
+ inline __attribute__((__always_inline__))
+# else
+# define __always_inline inline
+# endif
+#endif
+
+/*
+ * Some functions are marked to never be inlined to reduce stack usage.
+ * If you don't care about stack usage, you may want to modify this so
+ * that noinline_for_stack is #defined to be empty even when using GCC.
+ * Doing so may save a few bytes in binary size.
+ */
+#ifndef noinline_for_stack
+# ifdef __GNUC__
+# define noinline_for_stack __attribute__((__noinline__))
+# else
+# define noinline_for_stack
+# endif
+#endif
+
+/* Inline functions to access unaligned unsigned 32-bit integers */
+#ifndef get_unaligned_le32
+static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf)
+{
+ return (uint32_t)buf[0]
+ | ((uint32_t)buf[1] << 8)
+ | ((uint32_t)buf[2] << 16)
+ | ((uint32_t)buf[3] << 24);
+}
+#endif
+
+#ifndef get_unaligned_be32
+static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf)
+{
+ return (uint32_t)(buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | (uint32_t)buf[3];
+}
+#endif
+
+#ifndef put_unaligned_le32
+static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)val;
+ buf[1] = (uint8_t)(val >> 8);
+ buf[2] = (uint8_t)(val >> 16);
+ buf[3] = (uint8_t)(val >> 24);
+}
+#endif
+
+#ifndef put_unaligned_be32
+static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)(val >> 24);
+ buf[1] = (uint8_t)(val >> 16);
+ buf[2] = (uint8_t)(val >> 8);
+ buf[3] = (uint8_t)val;
+}
+#endif
+
+/*
+ * Use get_unaligned_le32() also for aligned access for simplicity. On
+ * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
+ * could save a few bytes in code size.
+ */
+#ifndef get_le32
+# define get_le32 get_unaligned_le32
+#endif
+
+#endif
diff --git a/lib/qt-tar-xz/xz_crc32.c b/lib/qt-tar-xz/xz_crc32.c
new file mode 100644
index 0000000..eea7b33
--- /dev/null
+++ b/lib/qt-tar-xz/xz_crc32.c
@@ -0,0 +1,52 @@
+/*
+ * CRC32 using the polynomial from IEEE-802.3
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * This is not the fastest implementation, but it is pretty compact.
+ * The fastest versions of xz_crc32() on modern CPUs without hardware
+ * accelerated CRC instruction are 3-5 times as fast as this version,
+ * but they are bigger and use more memory for the lookup table.
+ */
+
+#include "xz_private.h"
+
+static uint32_t xz_crc32_table[256];
+
+XZ_EXTERN void XZ_FUNC xz_crc32_init(void)
+{
+ const uint32_t poly = 0xEDB88320;
+
+ uint32_t i;
+ uint32_t j;
+ uint32_t r;
+
+ for (i = 0; i < 256; ++i) {
+ r = i;
+ for (j = 0; j < 8; ++j)
+ r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+ xz_crc32_table[i] = r;
+ }
+
+ return;
+}
+
+XZ_EXTERN uint32_t XZ_FUNC xz_crc32(
+ const uint8_t *buf, size_t size, uint32_t crc)
+{
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
diff --git a/lib/qt-tar-xz/xz_dec_bcj.c b/lib/qt-tar-xz/xz_dec_bcj.c
new file mode 100644
index 0000000..09162b5
--- /dev/null
+++ b/lib/qt-tar-xz/xz_dec_bcj.c
@@ -0,0 +1,564 @@
+/*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+/*
+ * The rest of the file is inside this ifdef. It makes things a little more
+ * convenient when building without support for any BCJ filters.
+ */
+#ifdef XZ_DEC_BCJ
+
+struct xz_dec_bcj {
+ /* Type of the BCJ filter being used */
+ enum {
+ BCJ_X86 = 4, /* x86 or x86-64 */
+ BCJ_POWERPC = 5, /* Big endian only */
+ BCJ_IA64 = 6, /* Big or little endian */
+ BCJ_ARM = 7, /* Little endian only */
+ BCJ_ARMTHUMB = 8, /* Little endian only */
+ BCJ_SPARC = 9 /* Big or little endian */
+ } type;
+
+ /*
+ * Return value of the next filter in the chain. We need to preserve
+ * this information across calls, because we must not call the next
+ * filter anymore once it has returned XZ_STREAM_END.
+ */
+ enum xz_ret ret;
+
+ /* True if we are operating in single-call mode. */
+ bool single_call;
+
+ /*
+ * Absolute position relative to the beginning of the uncompressed
+ * data (in a single .xz Block). We care only about the lowest 32
+ * bits so this doesn't need to be uint64_t even with big files.
+ */
+ uint32_t pos;
+
+ /* x86 filter state */
+ uint32_t x86_prev_mask;
+
+ /* Temporary space to hold the variables from struct xz_buf */
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+
+ struct {
+ /* Amount of already filtered data in the beginning of buf */
+ size_t filtered;
+
+ /* Total amount of data currently stored in buf */
+ size_t size;
+
+ /*
+ * Buffer to hold a mix of filtered and unfiltered data. This
+ * needs to be big enough to hold Alignment + 2 * Look-ahead:
+ *
+ * Type Alignment Look-ahead
+ * x86 1 4
+ * PowerPC 4 0
+ * IA-64 16 0
+ * ARM 4 0
+ * ARM-Thumb 2 2
+ * SPARC 4 0
+ */
+ uint8_t buf[16];
+ } temp;
+};
+
+#ifdef XZ_DEC_X86
+/*
+ * This is macro used to test the most significant byte of a memory address
+ * in an x86 instruction.
+ */
+#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF)
+
+static noinline_for_stack size_t XZ_FUNC bcj_x86(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const bool mask_to_allowed_status[8]
+ = { true, true, true, false, true, false, false, false };
+
+ static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+ size_t i;
+ size_t prev_pos = (size_t)-1;
+ uint32_t prev_mask = s->x86_prev_mask;
+ uint32_t src;
+ uint32_t dest;
+ uint32_t j;
+ uint8_t b;
+
+ if (size <= 4)
+ return 0;
+
+ size -= 4;
+ for (i = 0; i < size; ++i) {
+ if ((buf[i] & 0xFE) != 0xE8)
+ continue;
+
+ prev_pos = i - prev_pos;
+ if (prev_pos > 3) {
+ prev_mask = 0;
+ } else {
+ prev_mask = (prev_mask << (prev_pos - 1)) & 7;
+ if (prev_mask != 0) {
+ b = buf[i + 4 - mask_to_bit_num[prev_mask]];
+ if (!mask_to_allowed_status[prev_mask]
+ || bcj_x86_test_msbyte(b)) {
+ prev_pos = i;
+ prev_mask = (prev_mask << 1) | 1;
+ continue;
+ }
+ }
+ }
+
+ prev_pos = i;
+
+ if (bcj_x86_test_msbyte(buf[i + 4])) {
+ src = get_unaligned_le32(buf + i + 1);
+ while (true) {
+ dest = src - (s->pos + (uint32_t)i + 5);
+ if (prev_mask == 0)
+ break;
+
+ j = mask_to_bit_num[prev_mask] * 8;
+ b = (uint8_t)(dest >> (24 - j));
+ if (!bcj_x86_test_msbyte(b))
+ break;
+
+ src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
+ }
+
+ dest &= 0x01FFFFFF;
+ dest |= (uint32_t)0 - (dest & 0x01000000);
+ put_unaligned_le32(dest, buf + i + 1);
+ i += 4;
+ } else {
+ prev_mask = (prev_mask << 1) | 1;
+ }
+ }
+
+ prev_pos = i - prev_pos;
+ s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_POWERPC
+static noinline_for_stack size_t XZ_FUNC bcj_powerpc(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr & 0xFC000003) == 0x48000001) {
+ instr &= 0x03FFFFFC;
+ instr -= s->pos + (uint32_t)i;
+ instr &= 0x03FFFFFC;
+ instr |= 0x48000001;
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_IA64
+static noinline_for_stack size_t XZ_FUNC bcj_ia64(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const uint8_t branch_table[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+ };
+
+ /*
+ * The local variables take a little bit stack space, but it's less
+ * than what LZMA2 decoder takes, so it doesn't make sense to reduce
+ * stack usage here without doing that for the LZMA2 decoder too.
+ */
+
+ /* Loop counters */
+ size_t i;
+ size_t j;
+
+ /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
+ uint32_t slot;
+
+ /* Bitwise offset of the instruction indicated by slot */
+ uint32_t bit_pos;
+
+ /* bit_pos split into byte and bit parts */
+ uint32_t byte_pos;
+ uint32_t bit_res;
+
+ /* Address part of an instruction */
+ uint32_t addr;
+
+ /* Mask used to detect which instructions to convert */
+ uint32_t mask;
+
+ /* 41-bit instruction stored somewhere in the lowest 48 bits */
+ uint64_t instr;
+
+ /* Instruction normalized with bit_res for easier manipulation */
+ uint64_t norm;
+
+ for (i = 0; i + 16 <= size; i += 16) {
+ mask = branch_table[buf[i] & 0x1F];
+ for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
+ if (((mask >> slot) & 1) == 0)
+ continue;
+
+ byte_pos = bit_pos >> 3;
+ bit_res = bit_pos & 7;
+ instr = 0;
+ for (j = 0; j < 6; ++j)
+ instr |= (uint64_t)(buf[i + j + byte_pos])
+ << (8 * j);
+
+ norm = instr >> bit_res;
+
+ if (((norm >> 37) & 0x0F) == 0x05
+ && ((norm >> 9) & 0x07) == 0) {
+ addr = (norm >> 13) & 0x0FFFFF;
+ addr |= ((uint32_t)(norm >> 36) & 1) << 20;
+ addr <<= 4;
+ addr -= s->pos + (uint32_t)i;
+ addr >>= 4;
+
+ norm &= ~((uint64_t)0x8FFFFF << 13);
+ norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
+ norm |= (uint64_t)(addr & 0x100000)
+ << (36 - 20);
+
+ instr &= (1 << bit_res) - 1;
+ instr |= norm << bit_res;
+
+ for (j = 0; j < 6; j++)
+ buf[i + j + byte_pos]
+ = (uint8_t)(instr >> (8 * j));
+ }
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARM
+static noinline_for_stack size_t XZ_FUNC bcj_arm(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ if (buf[i + 3] == 0xEB) {
+ addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+ | ((uint32_t)buf[i + 2] << 16);
+ addr <<= 2;
+ addr -= s->pos + (uint32_t)i + 8;
+ addr >>= 2;
+ buf[i] = (uint8_t)addr;
+ buf[i + 1] = (uint8_t)(addr >> 8);
+ buf[i + 2] = (uint8_t)(addr >> 16);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARMTHUMB
+static noinline_for_stack size_t XZ_FUNC bcj_armthumb(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 2) {
+ if ((buf[i + 1] & 0xF8) == 0xF0
+ && (buf[i + 3] & 0xF8) == 0xF8) {
+ addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
+ | ((uint32_t)buf[i] << 11)
+ | (((uint32_t)buf[i + 3] & 0x07) << 8)
+ | (uint32_t)buf[i + 2];
+ addr <<= 1;
+ addr -= s->pos + (uint32_t)i + 4;
+ addr >>= 1;
+ buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
+ buf[i] = (uint8_t)(addr >> 11);
+ buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
+ buf[i + 2] = (uint8_t)addr;
+ i += 2;
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_SPARC
+static noinline_for_stack size_t XZ_FUNC bcj_sparc(
+ struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
+ instr <<= 2;
+ instr -= s->pos + (uint32_t)i;
+ instr >>= 2;
+ instr = ((uint32_t)0x40000000 - (instr & 0x400000))
+ | 0x40000000 | (instr & 0x3FFFFF);
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+/*
+ * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
+ * of data that got filtered.
+ *
+ * NOTE: This is implemented as a switch statement to avoid using function
+ * pointers, which could be problematic in the kernel boot code, which must
+ * avoid pointers to static data (at least on x86).
+ */
+static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s,
+ uint8_t *buf, size_t *pos, size_t size)
+{
+ size_t filtered;
+
+ buf += *pos;
+ size -= *pos;
+
+ switch (s->type) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+ filtered = bcj_x86(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+ filtered = bcj_powerpc(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+ filtered = bcj_ia64(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+ filtered = bcj_arm(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+ filtered = bcj_armthumb(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+ filtered = bcj_sparc(s, buf, size);
+ break;
+#endif
+ default:
+ /* Never reached but silence compiler warnings. */
+ filtered = 0;
+ break;
+ }
+
+ *pos += filtered;
+ s->pos += filtered;
+}
+
+/*
+ * Flush pending filtered data from temp to the output buffer.
+ * Move the remaining mixture of possibly filtered and unfiltered
+ * data to the beginning of temp.
+ */
+static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
+{
+ size_t copy_size;
+
+ copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+ memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
+ b->out_pos += copy_size;
+
+ s->temp.filtered -= copy_size;
+ s->temp.size -= copy_size;
+ memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
+}
+
+/*
+ * The BCJ filter functions are primitive in sense that they process the
+ * data in chunks of 1-16 bytes. To hide this issue, this function does
+ * some buffering.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
+ struct xz_dec_lzma2 *lzma2, struct xz_buf *b)
+{
+ size_t out_start;
+
+ /*
+ * Flush pending already filtered data to the output buffer. Return
+ * immediatelly if we couldn't flush everything, or if the next
+ * filter in the chain had already returned XZ_STREAM_END.
+ */
+ if (s->temp.filtered > 0) {
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+ }
+
+ /*
+ * If we have more output space than what is currently pending in
+ * temp, copy the unfiltered data from temp to the output buffer
+ * and try to fill the output buffer by decoding more data from the
+ * next filter in the chain. Apply the BCJ filter on the new data
+ * in the output buffer. If everything cannot be filtered, copy it
+ * to temp and rewind the output buffer position accordingly.
+ */
+ if (s->temp.size < b->out_size - b->out_pos) {
+ out_start = b->out_pos;
+ memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
+ b->out_pos += s->temp.size;
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+ if (s->ret != XZ_STREAM_END
+ && (s->ret != XZ_OK || s->single_call))
+ return s->ret;
+
+ bcj_apply(s, b->out, &out_start, b->out_pos);
+
+ /*
+ * As an exception, if the next filter returned XZ_STREAM_END,
+ * we can do that too, since the last few bytes that remain
+ * unfiltered are meant to remain unfiltered.
+ */
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+
+ s->temp.size = b->out_pos - out_start;
+ b->out_pos -= s->temp.size;
+ memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+ }
+
+ /*
+ * If we have unfiltered data in temp, try to fill by decoding more
+ * data from the next filter. Apply the BCJ filter on temp. Then we
+ * hopefully can fill the actual output buffer by copying filtered
+ * data from temp. A mix of filtered and unfiltered data may be left
+ * in temp; it will be taken care on the next call to this function.
+ */
+ if (s->temp.size > 0) {
+ /* Make b->out{,_pos,_size} temporarily point to s->temp. */
+ s->out = b->out;
+ s->out_pos = b->out_pos;
+ s->out_size = b->out_size;
+ b->out = s->temp.buf;
+ b->out_pos = s->temp.size;
+ b->out_size = sizeof(s->temp.buf);
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+
+ s->temp.size = b->out_pos;
+ b->out = s->out;
+ b->out_pos = s->out_pos;
+ b->out_size = s->out_size;
+
+ if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+ return s->ret;
+
+ bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
+
+ /*
+ * If the next filter returned XZ_STREAM_END, we mark that
+ * everything is filtered, since the last unfiltered bytes
+ * of the stream are meant to be left as is.
+ */
+ if (s->ret == XZ_STREAM_END)
+ s->temp.filtered = s->temp.size;
+
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+ }
+
+ return s->ret;
+}
+
+XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call)
+{
+ struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s != NULL)
+ s->single_call = single_call;
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
+ struct xz_dec_bcj *s, uint8_t id)
+{
+ switch (id) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+#endif
+ break;
+
+ default:
+ /* Unsupported Filter ID */
+ return XZ_OPTIONS_ERROR;
+ }
+
+ s->type = id;
+ s->ret = XZ_OK;
+ s->pos = 0;
+ s->x86_prev_mask = 0;
+ s->temp.filtered = 0;
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+#endif
diff --git a/lib/qt-tar-xz/xz_dec_lzma2.c b/lib/qt-tar-xz/xz_dec_lzma2.c
new file mode 100644
index 0000000..ad36e29
--- /dev/null
+++ b/lib/qt-tar-xz/xz_dec_lzma2.c
@@ -0,0 +1,1175 @@
+/*
+ * LZMA2 decoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_lzma2.h"
+
+/*
+ * Range decoder initialization eats the first five bytes of each LZMA chunk.
+ */
+#define RC_INIT_BYTES 5
+
+/*
+ * Minimum number of usable input buffer to safely decode one LZMA symbol.
+ * The worst case is that we decode 22 bits using probabilities and 26
+ * direct bits. This may decode at maximum of 20 bytes of input. However,
+ * lzma_main() does an extra normalization before returning, thus we
+ * need to put 21 here.
+ */
+#define LZMA_IN_REQUIRED 21
+
+/*
+ * Dictionary (history buffer)
+ *
+ * These are always true:
+ * start <= pos <= full <= end
+ * pos <= limit <= end
+ *
+ * In multi-call mode, also these are true:
+ * end == size
+ * size <= size_max
+ * allocated <= size
+ *
+ * Most of these variables are size_t to support single-call mode,
+ * in which the dictionary variables address the actual output
+ * buffer directly.
+ */
+struct dictionary {
+ /* Beginning of the history buffer */
+ uint8_t *buf;
+
+ /* Old position in buf (before decoding more data) */
+ size_t start;
+
+ /* Position in buf */
+ size_t pos;
+
+ /*
+ * How full dictionary is. This is used to detect corrupt input that
+ * would read beyond the beginning of the uncompressed stream.
+ */
+ size_t full;
+
+ /* Write limit; we don't write to buf[limit] or later bytes. */
+ size_t limit;
+
+ /*
+ * End of the dictionary buffer. In multi-call mode, this is
+ * the same as the dictionary size. In single-call mode, this
+ * indicates the size of the output buffer.
+ */
+ size_t end;
+
+ /*
+ * Size of the dictionary as specified in Block Header. This is used
+ * together with "full" to detect corrupt input that would make us
+ * read beyond the beginning of the uncompressed stream.
+ */
+ uint32_t size;
+
+ /*
+ * Maximum allowed dictionary size in multi-call mode.
+ * This is ignored in single-call mode.
+ */
+ uint32_t size_max;
+
+ /*
+ * Amount of memory currently allocated for the dictionary.
+ * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
+ * size_max is always the same as the allocated size.)
+ */
+ uint32_t allocated;
+
+ /* Operation mode */
+ enum xz_mode mode;
+};
+
+/* Range decoder */
+struct rc_dec {
+ uint32_t range;
+ uint32_t code;
+
+ /*
+ * Number of initializing bytes remaining to be read
+ * by rc_read_init().
+ */
+ uint32_t init_bytes_left;
+
+ /*
+ * Buffer from which we read our input. It can be either
+ * temp.buf or the caller-provided input buffer.
+ */
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_limit;
+};
+
+/* Probabilities for a length decoder. */
+struct lzma_len_dec {
+ /* Probability of match length being at least 10 */
+ uint16_t choice;
+
+ /* Probability of match length being at least 18 */
+ uint16_t choice2;
+
+ /* Probabilities for match lengths 2-9 */
+ uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+
+ /* Probabilities for match lengths 10-17 */
+ uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+
+ /* Probabilities for match lengths 18-273 */
+ uint16_t high[LEN_HIGH_SYMBOLS];
+};
+
+struct lzma_dec {
+ /* Distances of latest four matches */
+ uint32_t rep0;
+ uint32_t rep1;
+ uint32_t rep2;
+ uint32_t rep3;
+
+ /* Types of the most recently seen LZMA symbols */
+ enum lzma_state state;
+
+ /*
+ * Length of a match. This is updated so that dict_repeat can
+ * be called again to finish repeating the whole match.
+ */
+ uint32_t len;
+
+ /*
+ * LZMA properties or related bit masks (number of literal
+ * context bits, a mask dervied from the number of literal
+ * position bits, and a mask dervied from the number
+ * position bits)
+ */
+ uint32_t lc;
+ uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+ uint32_t pos_mask; /* (1 << pb) - 1 */
+
+ /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+ uint16_t is_match[STATES][POS_STATES_MAX];
+
+ /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+ uint16_t is_rep[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep0.
+ * Otherwise check is_rep1.
+ */
+ uint16_t is_rep0[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep1.
+ * Otherwise check is_rep2.
+ */
+ uint16_t is_rep1[STATES];
+
+ /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+ uint16_t is_rep2[STATES];
+
+ /*
+ * If 1, the repeated match has length of one byte. Otherwise
+ * the length is decoded from rep_len_decoder.
+ */
+ uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+ /*
+ * Probability tree for the highest two bits of the match
+ * distance. There is a separate probability tree for match
+ * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ */
+ uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+ /*
+ * Probility trees for additional bits for match distance
+ * when the distance is in the range [4, 127].
+ */
+ uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+ /*
+ * Probability tree for the lowest four bits of a match
+ * distance that is equal to or greater than 128.
+ */
+ uint16_t dist_align[ALIGN_SIZE];
+
+ /* Length of a normal match */
+ struct lzma_len_dec match_len_dec;
+
+ /* Length of a repeated match */
+ struct lzma_len_dec rep_len_dec;
+
+ /* Probabilities of literals */
+ uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+};
+
+struct lzma2_dec {
+ /* Position in xz_dec_lzma2_run(). */
+ enum lzma2_seq {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA_PREPARE,
+ SEQ_LZMA_RUN,
+ SEQ_COPY
+ } sequence;
+
+ /* Next position after decoding the compressed size of the chunk. */
+ enum lzma2_seq next_sequence;
+
+ /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+ uint32_t uncompressed;
+
+ /*
+ * Compressed size of LZMA chunk or compressed/uncompressed
+ * size of uncompressed chunk (64 KiB at maximum)
+ */
+ uint32_t compressed;
+
+ /*
+ * True if dictionary reset is needed. This is false before
+ * the first chunk (LZMA or uncompressed).
+ */
+ bool need_dict_reset;
+
+ /*
+ * True if new LZMA properties are needed. This is false
+ * before the first LZMA chunk.
+ */
+ bool need_props;
+};
+
+struct xz_dec_lzma2 {
+ /*
+ * The order below is important on x86 to reduce code size and
+ * it shouldn't hurt on other platforms. Everything up to and
+ * including lzma.pos_mask are in the first 128 bytes on x86-32,
+ * which allows using smaller instructions to access those
+ * variables. On x86-64, fewer variables fit into the first 128
+ * bytes, but this is still the best order without sacrificing
+ * the readability by splitting the structures.
+ */
+ struct rc_dec rc;
+ struct dictionary dict;
+ struct lzma2_dec lzma2;
+ struct lzma_dec lzma;
+
+ /*
+ * Temporary buffer which holds small number of input bytes between
+ * decoder calls. See lzma2_lzma() for details.
+ */
+ struct {
+ uint32_t size;
+ uint8_t buf[3 * LZMA_IN_REQUIRED];
+ } temp;
+};
+
+/**************
+ * Dictionary *
+ **************/
+
+/*
+ * Reset the dictionary state. When in single-call mode, set up the beginning
+ * of the dictionary to point to the actual output buffer.
+ */
+static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b)
+{
+ if (DEC_IS_SINGLE(dict->mode)) {
+ dict->buf = b->out + b->out_pos;
+ dict->end = b->out_size - b->out_pos;
+ }
+
+ dict->start = 0;
+ dict->pos = 0;
+ dict->limit = 0;
+ dict->full = 0;
+}
+
+/* Set dictionary write limit */
+static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max)
+{
+ if (dict->end - dict->pos <= out_max)
+ dict->limit = dict->end;
+ else
+ dict->limit = dict->pos + out_max;
+}
+
+/* Return true if at least one byte can be written into the dictionary. */
+static inline bool XZ_FUNC dict_has_space(const struct dictionary *dict)
+{
+ return dict->pos < dict->limit;
+}
+
+/*
+ * Get a byte from the dictionary at the given distance. The distance is
+ * assumed to valid, or as a special case, zero when the dictionary is
+ * still empty. This special case is needed for single-call decoding to
+ * avoid writing a '\0' to the end of the destination buffer.
+ */
+static inline uint32_t XZ_FUNC dict_get(
+ const struct dictionary *dict, uint32_t dist)
+{
+ size_t offset = dict->pos - dist - 1;
+
+ if (dist >= dict->pos)
+ offset += dict->end;
+
+ return dict->full > 0 ? dict->buf[offset] : 0;
+}
+
+/*
+ * Put one byte into the dictionary. It is assumed that there is space for it.
+ */
+static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte)
+{
+ dict->buf[dict->pos++] = byte;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+}
+
+/*
+ * Repeat given number of bytes from the given distance. If the distance is
+ * invalid, false is returned. On success, true is returned and *len is
+ * updated to indicate how many bytes were left to be repeated.
+ */
+static bool XZ_FUNC dict_repeat(
+ struct dictionary *dict, uint32_t *len, uint32_t dist)
+{
+ size_t back;
+ uint32_t left;
+
+ if (dist >= dict->full || dist >= dict->size)
+ return false;
+
+ left = min_t(size_t, dict->limit - dict->pos, *len);
+ *len -= left;
+
+ back = dict->pos - dist - 1;
+ if (dist >= dict->pos)
+ back += dict->end;
+
+ do {
+ dict->buf[dict->pos++] = dict->buf[back++];
+ if (back == dict->end)
+ back = 0;
+ } while (--left > 0);
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ return true;
+}
+
+/* Copy uncompressed data as is from input to dictionary and output buffers. */
+static void XZ_FUNC dict_uncompressed(
+ struct dictionary *dict, struct xz_buf *b, uint32_t *left)
+{
+ size_t copy_size;
+
+ while (*left > 0 && b->in_pos < b->in_size
+ && b->out_pos < b->out_size) {
+ copy_size = min(b->in_size - b->in_pos,
+ b->out_size - b->out_pos);
+ if (copy_size > dict->end - dict->pos)
+ copy_size = dict->end - dict->pos;
+ if (copy_size > *left)
+ copy_size = *left;
+
+ *left -= copy_size;
+
+ memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+ dict->pos += copy_size;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, b->in + b->in_pos,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+
+ b->out_pos += copy_size;
+ b->in_pos += copy_size;
+
+ }
+}
+
+/*
+ * Flush pending data from dictionary to b->out. It is assumed that there is
+ * enough space in b->out. This is guaranteed because caller uses dict_limit()
+ * before decoding data into the dictionary.
+ */
+static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b)
+{
+ size_t copy_size = dict->pos - dict->start;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, dict->buf + dict->start,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+ b->out_pos += copy_size;
+ return copy_size;
+}
+
+/*****************
+ * Range decoder *
+ *****************/
+
+/* Reset the range decoder. */
+static void XZ_FUNC rc_reset(struct rc_dec *rc)
+{
+ rc->range = (uint32_t)-1;
+ rc->code = 0;
+ rc->init_bytes_left = RC_INIT_BYTES;
+}
+
+/*
+ * Read the first five initial bytes into rc->code if they haven't been
+ * read already. (Yes, the first byte gets completely ignored.)
+ */
+static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b)
+{
+ while (rc->init_bytes_left > 0) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ rc->code = (rc->code << 8) + b->in[b->in_pos++];
+ --rc->init_bytes_left;
+ }
+
+ return true;
+}
+
+/* Return true if there may not be enough input for the next decoding loop. */
+static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc)
+{
+ return rc->in_pos > rc->in_limit;
+}
+
+/*
+ * Return true if it is possible (from point of view of range decoder) that
+ * we have reached the end of the LZMA chunk.
+ */
+static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc)
+{
+ return rc->code == 0;
+}
+
+/* Read the next input byte if needed. */
+static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc)
+{
+ if (rc->range < RC_TOP_VALUE) {
+ rc->range <<= RC_SHIFT_BITS;
+ rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+ }
+}
+
+/*
+ * Decode one bit. In some versions, this function has been splitted in three
+ * functions so that the compiler is supposed to be able to more easily avoid
+ * an extra branch. In this particular version of the LZMA decoder, this
+ * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3
+ * on x86). Using a non-splitted version results in nicer looking code too.
+ *
+ * NOTE: This must return an int. Do not make it return a bool or the speed
+ * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care,
+ * and it generates 10-20 % faster code than GCC 3.x from this file anyway.)
+ */
+static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob)
+{
+ uint32_t bound;
+ int bit;
+
+ rc_normalize(rc);
+ bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+ if (rc->code < bound) {
+ rc->range = bound;
+ *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+ bit = 0;
+ } else {
+ rc->range -= bound;
+ rc->code -= bound;
+ *prob -= *prob >> RC_MOVE_BITS;
+ bit = 1;
+ }
+
+ return bit;
+}
+
+/* Decode a bittree starting from the most significant bit. */
+static __always_inline uint32_t XZ_FUNC rc_bittree(
+ struct rc_dec *rc, uint16_t *probs, uint32_t limit)
+{
+ uint32_t symbol = 1;
+
+ do {
+ if (rc_bit(rc, &probs[symbol]))
+ symbol = (symbol << 1) + 1;
+ else
+ symbol <<= 1;
+ } while (symbol < limit);
+
+ return symbol;
+}
+
+/* Decode a bittree starting from the least significant bit. */
+static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc,
+ uint16_t *probs, uint32_t *dest, uint32_t limit)
+{
+ uint32_t symbol = 1;
+ uint32_t i = 0;
+
+ do {
+ if (rc_bit(rc, &probs[symbol])) {
+ symbol = (symbol << 1) + 1;
+ *dest += 1 << i;
+ } else {
+ symbol <<= 1;
+ }
+ } while (++i < limit);
+}
+
+/* Decode direct bits (fixed fifty-fifty probability) */
+static inline void XZ_FUNC rc_direct(
+ struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+{
+ uint32_t mask;
+
+ do {
+ rc_normalize(rc);
+ rc->range >>= 1;
+ rc->code -= rc->range;
+ mask = (uint32_t)0 - (rc->code >> 31);
+ rc->code += rc->range & mask;
+ *dest = (*dest << 1) + (mask + 1);
+ } while (--limit > 0);
+}
+
+/********
+ * LZMA *
+ ********/
+
+/* Get pointer to literal coder probability array. */
+static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s)
+{
+ uint32_t prev_byte = dict_get(&s->dict, 0);
+ uint32_t low = prev_byte >> (8 - s->lzma.lc);
+ uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+ return s->lzma.literal[low + high];
+}
+
+/* Decode a literal (one 8-bit byte) */
+static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ uint32_t symbol;
+ uint32_t match_byte;
+ uint32_t match_bit;
+ uint32_t offset;
+ uint32_t i;
+
+ probs = lzma_literal_probs(s);
+
+ if (lzma_state_is_literal(s->lzma.state)) {
+ symbol = rc_bittree(&s->rc, probs, 0x100);
+ } else {
+ symbol = 1;
+ match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+ offset = 0x100;
+
+ do {
+ match_bit = match_byte & offset;
+ match_byte <<= 1;
+ i = offset + match_bit + symbol;
+
+ if (rc_bit(&s->rc, &probs[i])) {
+ symbol = (symbol << 1) + 1;
+ offset &= match_bit;
+ } else {
+ symbol <<= 1;
+ offset &= ~match_bit;
+ }
+ } while (symbol < 0x100);
+ }
+
+ dict_put(&s->dict, (uint8_t)symbol);
+ lzma_state_literal(&s->lzma.state);
+}
+
+/* Decode the length of the match into s->lzma.len. */
+static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
+ uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t limit;
+
+ if (!rc_bit(&s->rc, &l->choice)) {
+ probs = l->low[pos_state];
+ limit = LEN_LOW_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN;
+ } else {
+ if (!rc_bit(&s->rc, &l->choice2)) {
+ probs = l->mid[pos_state];
+ limit = LEN_MID_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+ } else {
+ probs = l->high;
+ limit = LEN_HIGH_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+ + LEN_MID_SYMBOLS;
+ }
+ }
+
+ s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+}
+
+/* Decode a match. The distance will be stored in s->lzma.rep0. */
+static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t dist_slot;
+ uint32_t limit;
+
+ lzma_state_match(&s->lzma.state);
+
+ s->lzma.rep3 = s->lzma.rep2;
+ s->lzma.rep2 = s->lzma.rep1;
+ s->lzma.rep1 = s->lzma.rep0;
+
+ lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+ probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+ dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+ if (dist_slot < DIST_MODEL_START) {
+ s->lzma.rep0 = dist_slot;
+ } else {
+ limit = (dist_slot >> 1) - 1;
+ s->lzma.rep0 = 2 + (dist_slot & 1);
+
+ if (dist_slot < DIST_MODEL_END) {
+ s->lzma.rep0 <<= limit;
+ probs = s->lzma.dist_special + s->lzma.rep0
+ - dist_slot - 1;
+ rc_bittree_reverse(&s->rc, probs,
+ &s->lzma.rep0, limit);
+ } else {
+ rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+ s->lzma.rep0 <<= ALIGN_BITS;
+ rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+ &s->lzma.rep0, ALIGN_BITS);
+ }
+ }
+}
+
+/*
+ * Decode a repeated match. The distance is one of the four most recently
+ * seen matches. The distance will be stored in s->lzma.rep0.
+ */
+static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint32_t tmp;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+ s->lzma.state][pos_state])) {
+ lzma_state_short_rep(&s->lzma.state);
+ s->lzma.len = 1;
+ return;
+ }
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+ tmp = s->lzma.rep1;
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+ tmp = s->lzma.rep2;
+ } else {
+ tmp = s->lzma.rep3;
+ s->lzma.rep3 = s->lzma.rep2;
+ }
+
+ s->lzma.rep2 = s->lzma.rep1;
+ }
+
+ s->lzma.rep1 = s->lzma.rep0;
+ s->lzma.rep0 = tmp;
+ }
+
+ lzma_state_long_rep(&s->lzma.state);
+ lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+}
+
+/* LZMA decoder core */
+static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s)
+{
+ uint32_t pos_state;
+
+ /*
+ * If the dictionary was reached during the previous call, try to
+ * finish the possibly pending repeat in the dictionary.
+ */
+ if (dict_has_space(&s->dict) && s->lzma.len > 0)
+ dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+ /*
+ * Decode more LZMA symbols. One iteration may consume up to
+ * LZMA_IN_REQUIRED - 1 bytes.
+ */
+ while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+ pos_state = s->dict.pos & s->lzma.pos_mask;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_match[
+ s->lzma.state][pos_state])) {
+ lzma_literal(s);
+ } else {
+ if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+ lzma_rep_match(s, pos_state);
+ else
+ lzma_match(s, pos_state);
+
+ if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+ return false;
+ }
+ }
+
+ /*
+ * Having the range decoder always normalized when we are outside
+ * this function makes it easier to correctly handle end of the chunk.
+ */
+ rc_normalize(&s->rc);
+
+ return true;
+}
+
+/*
+ * Reset the LZMA decoder and range decoder state. Dictionary is nore reset
+ * here, because LZMA state may be reset without resetting the dictionary.
+ */
+static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ size_t i;
+
+ s->lzma.state = STATE_LIT_LIT;
+ s->lzma.rep0 = 0;
+ s->lzma.rep1 = 0;
+ s->lzma.rep2 = 0;
+ s->lzma.rep3 = 0;
+
+ /*
+ * All probabilities are initialized to the same value. This hack
+ * makes the code smaller by avoiding a separate loop for each
+ * probability array.
+ *
+ * This could be optimized so that only that part of literal
+ * probabilities that are actually required. In the common case
+ * we would write 12 KiB less.
+ */
+ probs = s->lzma.is_match[0];
+ for (i = 0; i < PROBS_TOTAL; ++i)
+ probs[i] = RC_BIT_MODEL_TOTAL / 2;
+
+ rc_reset(&s->rc);
+}
+
+/*
+ * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks
+ * from the decoded lp and pb values. On success, the LZMA decoder state is
+ * reset and true is returned.
+ */
+static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
+{
+ if (props > (4 * 5 + 4) * 9 + 8)
+ return false;
+
+ s->lzma.pos_mask = 0;
+ while (props >= 9 * 5) {
+ props -= 9 * 5;
+ ++s->lzma.pos_mask;
+ }
+
+ s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+
+ s->lzma.literal_pos_mask = 0;
+ while (props >= 9) {
+ props -= 9;
+ ++s->lzma.literal_pos_mask;
+ }
+
+ s->lzma.lc = props;
+
+ if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+ return false;
+
+ s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+
+ lzma_reset(s);
+
+ return true;
+}
+
+/*********
+ * LZMA2 *
+ *********/
+
+/*
+ * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't
+ * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This
+ * wrapper function takes care of making the LZMA decoder's assumption safe.
+ *
+ * As long as there is plenty of input left to be decoded in the current LZMA
+ * chunk, we decode directly from the caller-supplied input buffer until
+ * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into
+ * s->temp.buf, which (hopefully) gets filled on the next call to this
+ * function. We decode a few bytes from the temporary buffer so that we can
+ * continue decoding from the caller-supplied input buffer again.
+ */
+static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+ size_t in_avail;
+ uint32_t tmp;
+
+ in_avail = b->in_size - b->in_pos;
+ if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+ tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+ if (tmp > s->lzma2.compressed - s->temp.size)
+ tmp = s->lzma2.compressed - s->temp.size;
+ if (tmp > in_avail)
+ tmp = in_avail;
+
+ memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+ if (s->temp.size + tmp == s->lzma2.compressed) {
+ memzero(s->temp.buf + s->temp.size + tmp,
+ sizeof(s->temp.buf)
+ - s->temp.size - tmp);
+ s->rc.in_limit = s->temp.size + tmp;
+ } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+ s->temp.size += tmp;
+ b->in_pos += tmp;
+ return true;
+ } else {
+ s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+ }
+
+ s->rc.in = s->temp.buf;
+ s->rc.in_pos = 0;
+
+ if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+ return false;
+
+ s->lzma2.compressed -= s->rc.in_pos;
+
+ if (s->rc.in_pos < s->temp.size) {
+ s->temp.size -= s->rc.in_pos;
+ memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+ s->temp.size);
+ return true;
+ }
+
+ b->in_pos += s->rc.in_pos - s->temp.size;
+ s->temp.size = 0;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail >= LZMA_IN_REQUIRED) {
+ s->rc.in = b->in;
+ s->rc.in_pos = b->in_pos;
+
+ if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+ s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+ else
+ s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+ if (!lzma_main(s))
+ return false;
+
+ in_avail = s->rc.in_pos - b->in_pos;
+ if (in_avail > s->lzma2.compressed)
+ return false;
+
+ s->lzma2.compressed -= in_avail;
+ b->in_pos = s->rc.in_pos;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail < LZMA_IN_REQUIRED) {
+ if (in_avail > s->lzma2.compressed)
+ in_avail = s->lzma2.compressed;
+
+ memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+ s->temp.size = in_avail;
+ b->in_pos += in_avail;
+ }
+
+ return true;
+}
+
+/*
+ * Take care of the LZMA2 control layer, and forward the job of actual LZMA
+ * decoding or copying of uncompressed chunks to other functions.
+ */
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run(
+ struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+ uint32_t tmp;
+
+ while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+ switch (s->lzma2.sequence) {
+ case SEQ_CONTROL:
+ /*
+ * LZMA2 control byte
+ *
+ * Exact values:
+ * 0x00 End marker
+ * 0x01 Dictionary reset followed by
+ * an uncompressed chunk
+ * 0x02 Uncompressed chunk (no dictionary reset)
+ *
+ * Highest three bits (s->control & 0xE0):
+ * 0xE0 Dictionary reset, new properties and state
+ * reset, followed by LZMA compressed chunk
+ * 0xC0 New properties and state reset, followed
+ * by LZMA compressed chunk (no dictionary
+ * reset)
+ * 0xA0 State reset using old properties,
+ * followed by LZMA compressed chunk (no
+ * dictionary reset)
+ * 0x80 LZMA chunk (no dictionary or state reset)
+ *
+ * For LZMA compressed chunks, the lowest five bits
+ * (s->control & 1F) are the highest bits of the
+ * uncompressed size (bits 16-20).
+ *
+ * A new LZMA2 stream must begin with a dictionary
+ * reset. The first LZMA chunk must set new
+ * properties and reset the LZMA state.
+ *
+ * Values that don't match anything described above
+ * are invalid and we return XZ_DATA_ERROR.
+ */
+ tmp = b->in[b->in_pos++];
+
+ if (tmp >= 0xE0 || tmp == 0x01) {
+ s->lzma2.need_props = true;
+ s->lzma2.need_dict_reset = false;
+ dict_reset(&s->dict, b);
+ } else if (s->lzma2.need_dict_reset) {
+ return XZ_DATA_ERROR;
+ }
+
+ if (tmp >= 0x80) {
+ s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+ if (tmp >= 0xC0) {
+ /*
+ * When there are new properties,
+ * state reset is done at
+ * SEQ_PROPERTIES.
+ */
+ s->lzma2.need_props = false;
+ s->lzma2.next_sequence
+ = SEQ_PROPERTIES;
+
+ } else if (s->lzma2.need_props) {
+ return XZ_DATA_ERROR;
+
+ } else {
+ s->lzma2.next_sequence
+ = SEQ_LZMA_PREPARE;
+ if (tmp >= 0xA0)
+ lzma_reset(s);
+ }
+ } else {
+ if (tmp == 0x00)
+ return XZ_STREAM_END;
+
+ if (tmp > 0x02)
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ s->lzma2.next_sequence = SEQ_COPY;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_1:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ break;
+
+ case SEQ_COMPRESSED_0:
+ s->lzma2.compressed
+ = (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ s->lzma2.compressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = s->lzma2.next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (!lzma_props(s, b->in[b->in_pos++]))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_LZMA_PREPARE;
+
+ case SEQ_LZMA_PREPARE:
+ if (s->lzma2.compressed < RC_INIT_BYTES)
+ return XZ_DATA_ERROR;
+
+ if (!rc_read_init(&s->rc, b))
+ return XZ_OK;
+
+ s->lzma2.compressed -= RC_INIT_BYTES;
+ s->lzma2.sequence = SEQ_LZMA_RUN;
+
+ case SEQ_LZMA_RUN:
+ /*
+ * Set dictionary limit to indicate how much we want
+ * to be encoded at maximum. Decode new data into the
+ * dictionary. Flush the new data from dictionary to
+ * b->out. Check if we finished decoding this chunk.
+ * In case the dictionary got full but we didn't fill
+ * the output buffer yet, we may run this loop
+ * multiple times without changing s->lzma2.sequence.
+ */
+ dict_limit(&s->dict, min_t(size_t,
+ b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
+ if (!lzma2_lzma(s, b))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+ if (s->lzma2.uncompressed == 0) {
+ if (s->lzma2.compressed > 0 || s->lzma.len > 0
+ || !rc_is_finished(&s->rc))
+ return XZ_DATA_ERROR;
+
+ rc_reset(&s->rc);
+ s->lzma2.sequence = SEQ_CONTROL;
+
+ } else if (b->out_pos == b->out_size
+ || (b->in_pos == b->in_size
+ && s->temp.size
+ < s->lzma2.compressed)) {
+ return XZ_OK;
+ }
+
+ break;
+
+ case SEQ_COPY:
+ dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+ if (s->lzma2.compressed > 0)
+ return XZ_OK;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ break;
+ }
+ }
+
+ return XZ_OK;
+}
+
+XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(
+ enum xz_mode mode, uint32_t dict_max)
+{
+ struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->dict.mode = mode;
+ s->dict.size_max = dict_max;
+
+ if (DEC_IS_PREALLOC(mode)) {
+ s->dict.buf = vmalloc(dict_max);
+ if (s->dict.buf == NULL) {
+ kfree(s);
+ return NULL;
+ }
+ } else if (DEC_IS_DYNALLOC(mode)) {
+ s->dict.buf = NULL;
+ s->dict.allocated = 0;
+ }
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset(
+ struct xz_dec_lzma2 *s, uint8_t props)
+{
+ /* This limits dictionary size to 3 GiB to keep parsing simpler. */
+ if (props > 39)
+ return XZ_OPTIONS_ERROR;
+
+ s->dict.size = 2 + (props & 1);
+ s->dict.size <<= (props >> 1) + 11;
+
+ if (DEC_IS_MULTI(s->dict.mode)) {
+ if (s->dict.size > s->dict.size_max)
+ return XZ_MEMLIMIT_ERROR;
+
+ s->dict.end = s->dict.size;
+
+ if (DEC_IS_DYNALLOC(s->dict.mode)) {
+ if (s->dict.allocated < s->dict.size) {
+ vfree(s->dict.buf);
+ s->dict.buf = vmalloc(s->dict.size);
+ if (s->dict.buf == NULL) {
+ s->dict.allocated = 0;
+ return XZ_MEM_ERROR;
+ }
+ }
+ }
+ }
+
+ s->lzma.len = 0;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ s->lzma2.need_dict_reset = true;
+
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
+{
+ if (DEC_IS_MULTI(s->dict.mode))
+ vfree(s->dict.buf);
+
+ kfree(s);
+}
diff --git a/lib/qt-tar-xz/xz_dec_stream.c b/lib/qt-tar-xz/xz_dec_stream.c
new file mode 100644
index 0000000..bdcbf1b
--- /dev/null
+++ b/lib/qt-tar-xz/xz_dec_stream.c
@@ -0,0 +1,822 @@
+/*
+ * .xz Stream decoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_stream.h"
+
+/* Hash used to validate the Index field */
+struct xz_dec_hash {
+ vli_type unpadded;
+ vli_type uncompressed;
+ uint32_t crc32;
+};
+
+struct xz_dec {
+ /* Position in dec_main() */
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_START,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK_UNCOMPRESS,
+ SEQ_BLOCK_PADDING,
+ SEQ_BLOCK_CHECK,
+ SEQ_INDEX,
+ SEQ_INDEX_PADDING,
+ SEQ_INDEX_CRC32,
+ SEQ_STREAM_FOOTER
+ } sequence;
+
+ /* Position in variable-length integers and Check fields */
+ uint32_t pos;
+
+ /* Variable-length integer decoded by dec_vli() */
+ vli_type vli;
+
+ /* Saved in_pos and out_pos */
+ size_t in_start;
+ size_t out_start;
+
+ /* CRC32 value in Block or Index */
+ uint32_t crc32;
+
+ /* Type of the integrity check calculated from uncompressed data */
+ enum xz_check check_type;
+
+ /* Operation mode */
+ enum xz_mode mode;
+
+ /*
+ * True if the next call to xz_dec_run() is allowed to return
+ * XZ_BUF_ERROR.
+ */
+ bool allow_buf_error;
+
+ /* Information stored in Block Header */
+ struct {
+ /*
+ * Value stored in the Compressed Size field, or
+ * VLI_UNKNOWN if Compressed Size is not present.
+ */
+ vli_type compressed;
+
+ /*
+ * Value stored in the Uncompressed Size field, or
+ * VLI_UNKNOWN if Uncompressed Size is not present.
+ */
+ vli_type uncompressed;
+
+ /* Size of the Block Header field */
+ uint32_t size;
+ } block_header;
+
+ /* Information collected when decoding Blocks */
+ struct {
+ /* Observed compressed size of the current Block */
+ vli_type compressed;
+
+ /* Observed uncompressed size of the current Block */
+ vli_type uncompressed;
+
+ /* Number of Blocks decoded so far */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Block sizes. This is used to
+ * validate the Index field.
+ */
+ struct xz_dec_hash hash;
+ } block;
+
+ /* Variables needed when verifying the Index field */
+ struct {
+ /* Position in dec_index() */
+ enum {
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_UNPADDED,
+ SEQ_INDEX_UNCOMPRESSED
+ } sequence;
+
+ /* Size of the Index in bytes */
+ vli_type size;
+
+ /* Number of Records (matches block.count in valid files) */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Records (matches block.hash in
+ * valid files).
+ */
+ struct xz_dec_hash hash;
+ } index;
+
+ /*
+ * Temporary buffer needed to hold Stream Header, Block Header,
+ * and Stream Footer. The Block Header is the biggest (1 KiB)
+ * so we reserve space according to that. buf[] has to be aligned
+ * to a multiple of four bytes; the size_t variables before it
+ * should guarantee this.
+ */
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buf[1024];
+ } temp;
+
+ struct xz_dec_lzma2 *lzma2;
+
+#ifdef XZ_DEC_BCJ
+ struct xz_dec_bcj *bcj;
+ bool bcj_active;
+#endif
+};
+
+#ifdef XZ_DEC_ANY_CHECK
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+ 0,
+ 4, 4, 4,
+ 8, 8, 8,
+ 16, 16, 16,
+ 32, 32, 32,
+ 64, 64, 64
+};
+#endif
+
+/*
+ * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
+ * must have set s->temp.pos to indicate how much data we are supposed
+ * to copy into s->temp.buf. Return true once s->temp.pos has reached
+ * s->temp.size.
+ */
+static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b)
+{
+ size_t copy_size = min_t(size_t,
+ b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+
+ memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+ b->in_pos += copy_size;
+ s->temp.pos += copy_size;
+
+ if (s->temp.pos == s->temp.size) {
+ s->temp.pos = 0;
+ return true;
+ }
+
+ return false;
+}
+
+/* Decode a variable-length integer (little-endian base-128 encoding) */
+static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ uint8_t byte;
+
+ if (s->pos == 0)
+ s->vli = 0;
+
+ while (*in_pos < in_size) {
+ byte = in[*in_pos];
+ ++*in_pos;
+
+ s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+
+ if ((byte & 0x80) == 0) {
+ /* Don't allow non-minimal encodings. */
+ if (byte == 0 && s->pos != 0)
+ return XZ_DATA_ERROR;
+
+ s->pos = 0;
+ return XZ_STREAM_END;
+ }
+
+ s->pos += 7;
+ if (s->pos == 7 * VLI_BYTES_MAX)
+ return XZ_DATA_ERROR;
+ }
+
+ return XZ_OK;
+}
+
+/*
+ * Decode the Compressed Data field from a Block. Update and validate
+ * the observed compressed and uncompressed sizes of the Block so that
+ * they don't exceed the values possibly stored in the Block Header
+ * (validation assumes that no integer overflow occurs, since vli_type
+ * is normally uint64_t). Update the CRC32 if presence of the CRC32
+ * field was indicated in Stream Header.
+ *
+ * Once the decoding is finished, validate that the observed sizes match
+ * the sizes possibly stored in the Block Header. Update the hash and
+ * Block count, which are later used to validate the Index field.
+ */
+static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ s->in_start = b->in_pos;
+ s->out_start = b->out_pos;
+
+#ifdef XZ_DEC_BCJ
+ if (s->bcj_active)
+ ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+ else
+#endif
+ ret = xz_dec_lzma2_run(s->lzma2, b);
+
+ s->block.compressed += b->in_pos - s->in_start;
+ s->block.uncompressed += b->out_pos - s->out_start;
+
+ /*
+ * There is no need to separately check for VLI_UNKNOWN, since
+ * the observed sizes are always smaller than VLI_UNKNOWN.
+ */
+ if (s->block.compressed > s->block_header.compressed
+ || s->block.uncompressed
+ > s->block_header.uncompressed)
+ return XZ_DATA_ERROR;
+
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->crc32 = xz_crc32(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc32);
+
+ if (ret == XZ_STREAM_END) {
+ if (s->block_header.compressed != VLI_UNKNOWN
+ && s->block_header.compressed
+ != s->block.compressed)
+ return XZ_DATA_ERROR;
+
+ if (s->block_header.uncompressed != VLI_UNKNOWN
+ && s->block_header.uncompressed
+ != s->block.uncompressed)
+ return XZ_DATA_ERROR;
+
+ s->block.hash.unpadded += s->block_header.size
+ + s->block.compressed;
+
+#ifdef XZ_DEC_ANY_CHECK
+ s->block.hash.unpadded += check_sizes[s->check_type];
+#else
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->block.hash.unpadded += 4;
+#endif
+
+ s->block.hash.uncompressed += s->block.uncompressed;
+ s->block.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->block.hash,
+ sizeof(s->block.hash), s->block.hash.crc32);
+
+ ++s->block.count;
+ }
+
+ return ret;
+}
+
+/* Update the Index size and the CRC32 value. */
+static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b)
+{
+ size_t in_used = b->in_pos - s->in_start;
+ s->index.size += in_used;
+ s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
+}
+
+/*
+ * Decode the Number of Records, Unpadded Size, and Uncompressed Size
+ * fields from the Index field. That is, Index Padding and CRC32 are not
+ * decoded by this function.
+ *
+ * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
+ * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
+ */
+static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ do {
+ ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+ if (ret != XZ_STREAM_END) {
+ index_update(s, b);
+ return ret;
+ }
+
+ switch (s->index.sequence) {
+ case SEQ_INDEX_COUNT:
+ s->index.count = s->vli;
+
+ /*
+ * Validate that the Number of Records field
+ * indicates the same number of Records as
+ * there were Blocks in the Stream.
+ */
+ if (s->index.count != s->block.count)
+ return XZ_DATA_ERROR;
+
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+
+ case SEQ_INDEX_UNPADDED:
+ s->index.hash.unpadded += s->vli;
+ s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+ break;
+
+ case SEQ_INDEX_UNCOMPRESSED:
+ s->index.hash.uncompressed += s->vli;
+ s->index.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->index.hash,
+ sizeof(s->index.hash),
+ s->index.hash.crc32);
+ --s->index.count;
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+ }
+ } while (s->index.count > 0);
+
+ return XZ_STREAM_END;
+}
+
+/*
+ * Validate that the next four input bytes match the value of s->crc32.
+ * s->pos must be zero when starting to validate the first byte.
+ */
+static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b)
+{
+ do {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
+ return XZ_DATA_ERROR;
+
+ s->pos += 8;
+
+ } while (s->pos < 32);
+
+ s->crc32 = 0;
+ s->pos = 0;
+
+ return XZ_STREAM_END;
+}
+
+#ifdef XZ_DEC_ANY_CHECK
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+ while (s->pos < check_sizes[s->check_type]) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ ++b->in_pos;
+ ++s->pos;
+ }
+
+ s->pos = 0;
+
+ return true;
+}
+#endif
+
+/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
+static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+ return XZ_FORMAT_ERROR;
+
+ if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+ != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+ return XZ_OPTIONS_ERROR;
+
+ /*
+ * Of integrity checks, we support only none (Check ID = 0) and
+ * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
+ * we will accept other check types too, but then the check won't
+ * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
+ */
+ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (s->check_type > XZ_CHECK_MAX)
+ return XZ_OPTIONS_ERROR;
+
+ if (s->check_type > XZ_CHECK_CRC32)
+ return XZ_UNSUPPORTED_CHECK;
+#else
+ if (s->check_type > XZ_CHECK_CRC32)
+ return XZ_OPTIONS_ERROR;
+#endif
+
+ return XZ_OK;
+}
+
+/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
+static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+ return XZ_DATA_ERROR;
+
+ if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+ return XZ_DATA_ERROR;
+