mirror of
https://github.com/linuxmint/timeshift.git
synced 2024-08-16 20:10:39 +03:00
Revert "Remove trailing spaces"
This reverts commit f04fb67bab
.
I thought Tony was done updating his repository when committing this.
I revert it for now as it makes merging difficult and it isn't urgent to fix.
This commit is contained in:
parent
f04fb67bab
commit
cad8820865
10
makefile
10
makefile
@ -3,13 +3,13 @@ all:
|
||||
|
||||
app-gtk:
|
||||
cd src; make app-gtk
|
||||
|
||||
|
||||
app-console:
|
||||
cd src; make app-console
|
||||
|
||||
manpage:
|
||||
cd src; make manpage
|
||||
|
||||
|
||||
dist-release:
|
||||
build-release
|
||||
|
||||
@ -17,18 +17,18 @@ dist-publish:
|
||||
build-update-repo-debian
|
||||
build-update-repo-redhat
|
||||
build-update-repo-archlinux
|
||||
|
||||
|
||||
dist-upload:
|
||||
build-upload
|
||||
|
||||
dist-deb:
|
||||
build-deb amd64
|
||||
|
||||
|
||||
clean:
|
||||
cd src; make clean
|
||||
|
||||
install:
|
||||
cd src; make install
|
||||
|
||||
|
||||
uninstall:
|
||||
cd src; make uninstall
|
||||
|
@ -52,11 +52,11 @@ public class AppConsole : GLib.Object {
|
||||
public int snapshot_list_start_index = 0;
|
||||
|
||||
public static int main (string[] args) {
|
||||
|
||||
|
||||
set_locale();
|
||||
|
||||
LOG_TIMESTAMP = false;
|
||||
|
||||
|
||||
if (args.length > 1) {
|
||||
switch (args[1].down()) {
|
||||
case "--help":
|
||||
@ -73,13 +73,13 @@ public class AppConsole : GLib.Object {
|
||||
LOG_ENABLE = false;
|
||||
init_tmp(AppShortName);
|
||||
LOG_ENABLE = true;
|
||||
|
||||
|
||||
check_if_admin();
|
||||
|
||||
App = new Main(args, false);
|
||||
parse_arguments(args);
|
||||
App.initialize();
|
||||
|
||||
|
||||
var console = new AppConsole();
|
||||
bool ok = console.start_application();
|
||||
App.exit_app((ok) ? 0 : 1);
|
||||
@ -88,7 +88,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
private static void set_locale() {
|
||||
|
||||
|
||||
log_debug("setting locale...");
|
||||
Intl.setlocale(GLib.LocaleCategory.MESSAGES, "timeshift");
|
||||
Intl.textdomain(GETTEXT_PACKAGE);
|
||||
@ -97,7 +97,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
public static void check_if_admin(){
|
||||
|
||||
|
||||
if (!user_is_admin()) {
|
||||
log_msg(_("Application needs admin access."));
|
||||
log_msg(_("Please run the application as admin (using 'sudo' or 'su')"));
|
||||
@ -111,7 +111,7 @@ public class AppConsole : GLib.Object {
|
||||
private static void parse_arguments(string[] args){
|
||||
|
||||
log_debug("AppConsole: parse_arguments()");
|
||||
|
||||
|
||||
for (int k = 1; k < args.length; k++) // Oth arg is app path
|
||||
{
|
||||
switch (args[k].down()){
|
||||
@ -158,7 +158,7 @@ public class AppConsole : GLib.Object {
|
||||
case "--comment":
|
||||
case "--comments":
|
||||
App.cmd_comments = args[++k];
|
||||
break;
|
||||
break;
|
||||
|
||||
case "--skip-grub":
|
||||
App.cmd_skip_grub = true;
|
||||
@ -245,7 +245,7 @@ public class AppConsole : GLib.Object {
|
||||
log_error("Run 'timeshift --help' to list all available options");
|
||||
App.exit_app(1);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
LOG_TIMESTAMP = false;
|
||||
log_error("%s: %s".printf(
|
||||
@ -274,7 +274,7 @@ public class AppConsole : GLib.Object {
|
||||
public bool start_application(){
|
||||
|
||||
log_debug("AppConsole: start_application()");
|
||||
|
||||
|
||||
bool is_success = true;
|
||||
|
||||
if (App.live_system()){
|
||||
@ -335,10 +335,10 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
private static string help_message (){
|
||||
|
||||
|
||||
string msg = "\n%s v%s by Tony George (%s)\n".printf(
|
||||
AppName, AppVersion, AppAuthorEmail);
|
||||
|
||||
|
||||
msg += "\n";
|
||||
msg += "Syntax:\n";
|
||||
msg += "\n";
|
||||
@ -445,7 +445,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
private void list_devices(Gee.ArrayList<Device> device_list){
|
||||
|
||||
|
||||
string[,] grid = new string[device_list.size+1,6];
|
||||
bool[] right_align = { false, false, false, true, true, false};
|
||||
|
||||
@ -523,7 +523,7 @@ public class AppConsole : GLib.Object {
|
||||
if (dev.type == "disk"){
|
||||
grub_device_list.add(dev);
|
||||
}
|
||||
else if (dev.type == "part"){
|
||||
else if (dev.type == "part"){
|
||||
if (dev.has_linux_filesystem()){
|
||||
grub_device_list.add(dev);
|
||||
}
|
||||
@ -599,15 +599,15 @@ public class AppConsole : GLib.Object {
|
||||
select_snapshot_device(false);
|
||||
return App.create_snapshot(ondemand, null);
|
||||
}
|
||||
|
||||
|
||||
// restore
|
||||
|
||||
|
||||
private bool restore_snapshot(){
|
||||
|
||||
select_snapshot_device(true);
|
||||
|
||||
select_snapshot_for_restore();
|
||||
|
||||
|
||||
stdout.printf("\n\n");
|
||||
log_msg(string.nfill(78, '*'));
|
||||
stdout.printf(_("To restore with default options, press the ENTER key for all prompts!") + "\n");
|
||||
@ -617,7 +617,7 @@ public class AppConsole : GLib.Object {
|
||||
stdin.read_line();
|
||||
|
||||
init_mounts();
|
||||
|
||||
|
||||
if (!App.btrfs_mode){
|
||||
|
||||
map_devices();
|
||||
@ -647,13 +647,13 @@ public class AppConsole : GLib.Object {
|
||||
list.add(pi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((App.repo.device == null) || (prompt_if_empty && (App.repo.snapshots.size == 0))){
|
||||
//prompt user for backup device
|
||||
log_msg("");
|
||||
|
||||
if (App.cmd_scripted){
|
||||
|
||||
|
||||
if (App.repo.device == null){
|
||||
if (App.backup_uuid.length == 0){
|
||||
log_debug("device is null");
|
||||
@ -694,7 +694,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
log_msg("");
|
||||
|
||||
|
||||
if (dev == null){
|
||||
log_error(_("Failed to get input from user in 3 attempts"));
|
||||
log_msg(_("Aborted."));
|
||||
@ -711,13 +711,13 @@ public class AppConsole : GLib.Object {
|
||||
private Snapshot? select_snapshot(){
|
||||
|
||||
Snapshot selected_snapshot = null;
|
||||
|
||||
|
||||
log_debug("AppConsole: select_snapshot()");
|
||||
|
||||
|
||||
if (App.mirror_system){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (App.cmd_snapshot.length > 0){
|
||||
|
||||
//check command line arguments
|
||||
@ -758,7 +758,7 @@ public class AppConsole : GLib.Object {
|
||||
selected_snapshot = read_stdin_snapshot();
|
||||
}
|
||||
log_msg("");
|
||||
|
||||
|
||||
if (selected_snapshot == null){
|
||||
log_error(_("Failed to get input from user in 3 attempts"));
|
||||
log_msg(_("Aborted."));
|
||||
@ -784,18 +784,18 @@ public class AppConsole : GLib.Object {
|
||||
App.exit_app(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void init_mounts(){
|
||||
|
||||
log_debug("AppConsole: init_mounts()");
|
||||
|
||||
|
||||
App.init_mount_list();
|
||||
|
||||
// remove mount points which will remain on root fs
|
||||
for(int i = App.mount_list.size-1; i >= 0; i--){
|
||||
|
||||
|
||||
var entry = App.mount_list[i];
|
||||
|
||||
|
||||
if (entry.device == null){
|
||||
App.mount_list.remove(entry);
|
||||
}
|
||||
@ -805,15 +805,15 @@ public class AppConsole : GLib.Object {
|
||||
private void map_devices(){
|
||||
|
||||
log_debug("AppConsole: map_devices()");
|
||||
|
||||
|
||||
if (App.cmd_target_device.length > 0){
|
||||
|
||||
//check command line arguments
|
||||
bool found = false;
|
||||
foreach(Device pi in App.partitions) {
|
||||
|
||||
|
||||
if (!pi.has_linux_filesystem()) { continue; }
|
||||
|
||||
|
||||
if ((pi.device == App.cmd_target_device)||((pi.uuid == App.cmd_target_device))){
|
||||
App.dst_root = pi;
|
||||
found = true;
|
||||
@ -840,7 +840,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
for(int i = 0; i < App.mount_list.size; i++){
|
||||
|
||||
|
||||
MountEntry mnt = App.mount_list[i];
|
||||
Device dev = null;
|
||||
string default_device = "";
|
||||
@ -850,7 +850,7 @@ public class AppConsole : GLib.Object {
|
||||
// no need to ask user to map remaining devices if restoring same system
|
||||
if ((App.dst_root != null) && (App.sys_root != null)
|
||||
&& (App.dst_root.uuid == App.sys_root.uuid)){
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -878,14 +878,14 @@ public class AppConsole : GLib.Object {
|
||||
while (dev == null){
|
||||
attempts++;
|
||||
if (attempts > 3) { break; }
|
||||
|
||||
|
||||
stdout.printf("" +
|
||||
_("[ENTER = Default (%s), r = Root device, a = Abort]").printf(default_device) + "\n\n");
|
||||
|
||||
|
||||
stdout.printf(
|
||||
_("Enter device name or number")
|
||||
+ ": ");
|
||||
|
||||
|
||||
stdout.flush();
|
||||
dev = read_stdin_device_mounts(device_list, mnt);
|
||||
}
|
||||
@ -901,26 +901,26 @@ public class AppConsole : GLib.Object {
|
||||
if (dev != null){
|
||||
|
||||
log_debug("selected: %s".printf(dev.uuid));
|
||||
|
||||
|
||||
mnt.device = dev;
|
||||
|
||||
log_msg(string.nfill(78, '*'));
|
||||
|
||||
|
||||
if ((mnt.mount_point != "/")
|
||||
&& (App.dst_root != null)
|
||||
&& (dev.device == App.dst_root.device)){
|
||||
|
||||
|
||||
log_msg(_("'%s' will be on root device").printf(mnt.mount_point), true);
|
||||
}
|
||||
else{
|
||||
log_msg(_("'%s' will be on '%s'").printf(
|
||||
mnt.mount_point, mnt.device.short_name_with_alias), true);
|
||||
|
||||
|
||||
//log_debug("UUID=%s".printf(dst_root.uuid));
|
||||
}
|
||||
log_msg(string.nfill(78, '*'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,17 +930,17 @@ public class AppConsole : GLib.Object {
|
||||
bool grub_reinstall_default = App.reinstall_grub2;
|
||||
App.reinstall_grub2 = false;
|
||||
App.grub_device = "";
|
||||
|
||||
|
||||
if (App.cmd_grub_device.length > 0){
|
||||
|
||||
log_debug("Grub device is specified as command argument");
|
||||
|
||||
|
||||
//check command line arguments
|
||||
bool found = false;
|
||||
var device_list = list_grub_devices(false);
|
||||
|
||||
|
||||
foreach(Device dev in device_list) {
|
||||
|
||||
|
||||
if ((dev.device == App.cmd_grub_device)
|
||||
||((dev.uuid.length > 0) && (dev.uuid == App.cmd_grub_device))){
|
||||
|
||||
@ -969,7 +969,7 @@ public class AppConsole : GLib.Object {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (App.mirror_system){
|
||||
App.reinstall_grub2 = true;
|
||||
}
|
||||
@ -995,7 +995,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
if ((App.reinstall_grub2) && (App.grub_device.length == 0)){
|
||||
|
||||
|
||||
log_msg("");
|
||||
log_msg(_("Select GRUB device") + ":\n");
|
||||
var device_list = list_grub_devices();
|
||||
@ -1003,7 +1003,7 @@ public class AppConsole : GLib.Object {
|
||||
|
||||
int attempts = 0;
|
||||
while (App.grub_device.length == 0){
|
||||
|
||||
|
||||
attempts++;
|
||||
if (attempts > 3) { break; }
|
||||
|
||||
@ -1023,15 +1023,15 @@ public class AppConsole : GLib.Object {
|
||||
list.add(pi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Device dev = read_stdin_device(device_list, grub_device_default);
|
||||
if (dev != null) { App.grub_device = dev.device; }
|
||||
}
|
||||
|
||||
|
||||
log_msg("");
|
||||
|
||||
if (App.grub_device.length == 0){
|
||||
|
||||
|
||||
log_error(_("Failed to get input from user in 3 attempts"));
|
||||
log_msg(_("Aborted."));
|
||||
App.exit_app(0);
|
||||
@ -1039,7 +1039,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
if ((App.reinstall_grub2) && (App.grub_device.length > 0)){
|
||||
|
||||
|
||||
log_msg(string.nfill(78, '*'));
|
||||
log_msg(_("GRUB Device") + ": %s".printf(App.grub_device));
|
||||
log_msg(string.nfill(78, '*'));
|
||||
@ -1052,7 +1052,7 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
private void confirm_restore(){
|
||||
|
||||
|
||||
if (App.cmd_confirm == false){
|
||||
|
||||
string msg_devices = "";
|
||||
@ -1079,9 +1079,9 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Device? read_stdin_device(Gee.ArrayList<Device> device_list, string device_default){
|
||||
|
||||
|
||||
var counter = new TimeoutCounter();
|
||||
counter.exit_on_timeout();
|
||||
string? line = stdin.read_line();
|
||||
@ -1272,7 +1272,7 @@ public class AppConsole : GLib.Object {
|
||||
private bool read_stdin_restore_confirm(){
|
||||
var counter = new TimeoutCounter();
|
||||
counter.exit_on_timeout();
|
||||
|
||||
|
||||
string? line = stdin.read_line();
|
||||
counter.stop();
|
||||
|
||||
@ -1317,11 +1317,11 @@ public class AppConsole : GLib.Object {
|
||||
}
|
||||
|
||||
public bool delete_all_snapshots(){
|
||||
|
||||
|
||||
select_snapshot_device(true);
|
||||
|
||||
|
||||
//return App.repo.remove_all();
|
||||
|
||||
|
||||
foreach(var snap in App.repo.snapshots){
|
||||
snap.remove(true);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class AppExcludeEntry : GLib.Object{
|
||||
|
||||
|
||||
public string name = "";
|
||||
public bool is_include = false;
|
||||
public bool is_file = false;
|
||||
@ -42,7 +42,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
public static Gee.HashMap<string, AppExcludeEntry> app_map;
|
||||
|
||||
public AppExcludeEntry(string _name, bool _is_include = false){
|
||||
|
||||
|
||||
name = _name;
|
||||
is_include = _is_include;
|
||||
|
||||
@ -51,7 +51,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public string tooltip_text(){
|
||||
|
||||
|
||||
string txt = "";
|
||||
foreach(var item in items){
|
||||
txt += "%s\n".printf(item);
|
||||
@ -60,14 +60,14 @@ public class AppExcludeEntry : GLib.Object{
|
||||
txt = txt[0:txt.length - 1];
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
|
||||
public static void clear(){
|
||||
|
||||
log_debug("AppExcludeEntry: clear()");
|
||||
|
||||
|
||||
if (app_map == null){
|
||||
app_map = new Gee.HashMap<string, AppExcludeEntry>();
|
||||
}
|
||||
@ -80,14 +80,14 @@ public class AppExcludeEntry : GLib.Object{
|
||||
|
||||
log_debug("AppExcludeEntry: add_app_exclude_entries_from_home()");
|
||||
log_debug("path=%s".printf(home));
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File f_home = File.new_for_path (home);
|
||||
if (!f_home.query_exists()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FileEnumerator enumerator = f_home.enumerate_children ("standard::*", 0);
|
||||
FileInfo file;
|
||||
while ((file = enumerator.next_file ()) != null) {
|
||||
@ -97,7 +97,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
if (name.has_suffix(".log")){ continue; }
|
||||
if (name.has_suffix(".old")){ continue; }
|
||||
if (name.has_suffix("~")){ continue; }
|
||||
|
||||
|
||||
add_app_exclude_entries_from_path(item);
|
||||
}
|
||||
}
|
||||
@ -105,19 +105,19 @@ public class AppExcludeEntry : GLib.Object{
|
||||
log_error (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void add_app_exclude_entries_from_path(string user_home){
|
||||
|
||||
log_debug("AppExcludeEntry: add_app_exclude_entries_from_path()");
|
||||
log_debug("path=%s".printf(user_home));
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File f_home = File.new_for_path (user_home);
|
||||
if (!f_home.query_exists()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FileEnumerator enumerator = f_home.enumerate_children ("standard::*", 0);
|
||||
FileInfo file;
|
||||
while ((file = enumerator.next_file ()) != null) {
|
||||
@ -136,7 +136,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
if (name.has_suffix(".log")){ continue; }
|
||||
if (name.has_suffix(".old")){ continue; }
|
||||
if (name.has_suffix("~")){ continue; }
|
||||
|
||||
|
||||
var relpath = "~/%s".printf(name);
|
||||
add_item(relpath, !dir_exists(item), false);
|
||||
}
|
||||
@ -151,7 +151,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
if (name.has_suffix(".log")){ continue; }
|
||||
if (name.has_suffix(".old")){ continue; }
|
||||
if (name.has_suffix("~")){ continue; }
|
||||
|
||||
|
||||
var relpath = "~/.config/%s".printf(name);
|
||||
add_item(relpath, !dir_exists(item), false);
|
||||
}
|
||||
@ -169,7 +169,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
if (name.has_suffix("~")){ continue; }
|
||||
if (name == "applications"){ continue; }
|
||||
if (name == "Trash"){ continue; }
|
||||
|
||||
|
||||
var relpath = "~/.local/share/%s".printf(name);
|
||||
add_item(relpath, !dir_exists(item), false);
|
||||
}
|
||||
@ -187,7 +187,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
}
|
||||
|
||||
var name = file_basename(item_path);
|
||||
|
||||
|
||||
if (name.has_suffix(".ini")){
|
||||
name = name[0:name.length - ".ini".length];
|
||||
}
|
||||
@ -275,7 +275,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
if (app_map == null){
|
||||
app_map = new Gee.HashMap<string, AppExcludeEntry>();
|
||||
}
|
||||
|
||||
|
||||
foreach(var selected_name in selected_app_names){
|
||||
if (app_map.has_key(selected_name)){
|
||||
app_map[selected_name].enabled = true;
|
||||
@ -284,7 +284,7 @@ public class AppExcludeEntry : GLib.Object{
|
||||
app_map[selected_name].enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<AppExcludeEntry>();
|
||||
foreach(var key in app_map.keys){
|
||||
list.add(app_map[key]);
|
||||
@ -294,11 +294,11 @@ public class AppExcludeEntry : GLib.Object{
|
||||
GLib.CompareDataFunc<AppExcludeEntry> entry_compare = (a, b) => {
|
||||
return strcmp(a.name.down(),b.name.down());
|
||||
};
|
||||
|
||||
|
||||
list.sort((owned) entry_compare);
|
||||
|
||||
log_debug("apps: %d".printf(list.size));
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@ using TeeJee.Misc;
|
||||
using Json;
|
||||
|
||||
public class Snapshot : GLib.Object{
|
||||
|
||||
|
||||
public string path = "";
|
||||
public string name = "";
|
||||
public DateTime date;
|
||||
@ -51,13 +51,13 @@ public class Snapshot : GLib.Object{
|
||||
public bool marked_for_deletion = false;
|
||||
public LinuxDistro distro;
|
||||
public SnapshotRepo repo;
|
||||
|
||||
|
||||
//btrfs
|
||||
public bool btrfs_mode = false;
|
||||
public Gee.HashMap<string,string> paths; // for btrfs snapshots only
|
||||
public string mount_path_root = "";
|
||||
public string mount_path_home = "";
|
||||
|
||||
|
||||
public DeleteFileTask delete_file_task;
|
||||
|
||||
public Snapshot(string dir_path, bool btrfs_snapshot, SnapshotRepo _repo){
|
||||
@ -71,7 +71,7 @@ public class Snapshot : GLib.Object{
|
||||
description = "";
|
||||
btrfs_mode = btrfs_snapshot;
|
||||
repo = _repo;
|
||||
|
||||
|
||||
date = new DateTime.from_unix_utc(0);
|
||||
tags = new Gee.ArrayList<string>();
|
||||
exclude_list = new Gee.ArrayList<string>();
|
||||
@ -79,7 +79,7 @@ public class Snapshot : GLib.Object{
|
||||
delete_file_task = new DeleteFileTask();
|
||||
subvolumes = new Gee.HashMap<string,Subvolume>();
|
||||
paths = new Gee.HashMap<string,string>();
|
||||
|
||||
|
||||
read_control_file();
|
||||
read_exclude_list();
|
||||
read_fstab_file();
|
||||
@ -91,7 +91,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
|
||||
public string date_formatted{
|
||||
owned get{
|
||||
return date.format(App.date_format);//.format("%Y-%m-%d %H:%M:%S");
|
||||
@ -101,41 +101,41 @@ public class Snapshot : GLib.Object{
|
||||
public string rsync_log_file{
|
||||
owned get {
|
||||
return path_combine(path, "rsync-log");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string rsync_changes_log_file{
|
||||
owned get {
|
||||
return path_combine(path, "rsync-log-changes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string rsync_restore_log_file{
|
||||
owned get {
|
||||
return path_combine(path, "rsync-log-restore");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string rsync_restore_changes_log_file{
|
||||
owned get {
|
||||
return path_combine(path, "rsync-log-restore-changes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string exclude_file_for_backup {
|
||||
owned get {
|
||||
return path_combine(path, "exclude.list");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string exclude_file_for_restore {
|
||||
owned get {
|
||||
return path_combine(path, "exclude-restore.list");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// manage tags
|
||||
|
||||
|
||||
public string taglist{
|
||||
owned get{
|
||||
string str = "";
|
||||
@ -165,7 +165,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
public void add_tag(string tag){
|
||||
|
||||
|
||||
if (!tags.contains(tag.strip())){
|
||||
tags.add(tag.strip());
|
||||
update_control_file();
|
||||
@ -173,7 +173,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
public void remove_tag(string tag){
|
||||
|
||||
|
||||
if (tags.contains(tag.strip())){
|
||||
tags.remove(tag.strip());
|
||||
update_control_file();
|
||||
@ -181,30 +181,30 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
public bool has_tag(string tag){
|
||||
|
||||
|
||||
return tags.contains(tag.strip());
|
||||
}
|
||||
|
||||
// control files
|
||||
|
||||
|
||||
public void read_control_file(){
|
||||
|
||||
|
||||
//log_debug("read_control_file()");
|
||||
|
||||
|
||||
string ctl_file = path + "/info.json";
|
||||
|
||||
var f = File.new_for_path(ctl_file);
|
||||
|
||||
|
||||
if (f.query_exists()) {
|
||||
|
||||
|
||||
var parser = new Json.Parser();
|
||||
|
||||
|
||||
try{
|
||||
parser.load_from_file(ctl_file);
|
||||
} catch (Error e) {
|
||||
log_error (e.message);
|
||||
}
|
||||
|
||||
|
||||
var node = parser.get_root();
|
||||
var config = node.get_object();
|
||||
|
||||
@ -236,24 +236,24 @@ public class Snapshot : GLib.Object{
|
||||
var subvols = (Json.Object) config.get_object_member("subvolumes");
|
||||
|
||||
foreach(string subvol_name in subvols.get_members()){
|
||||
|
||||
|
||||
if ((subvol_name != "@")&&(subvol_name != "@home")){ continue; }
|
||||
|
||||
|
||||
paths[subvol_name] = path.replace(repo.mount_path, repo.mount_paths[subvol_name]);
|
||||
|
||||
|
||||
var subvol_path = path_combine(paths[subvol_name], subvol_name);
|
||||
|
||||
|
||||
if (!dir_exists(subvol_path)){ continue; }
|
||||
|
||||
//log_debug("subvol_path: %s".printf(subvol_path));
|
||||
|
||||
|
||||
var subvolume = new Subvolume(subvol_name, subvol_path, "", repo); //subvolumes.get(subvol_name);
|
||||
subvolumes.set(subvol_name, subvolume);
|
||||
|
||||
|
||||
int index = -1;
|
||||
|
||||
|
||||
foreach(Json.Node jnode in subvols.get_array_member(subvol_name).get_elements()) {
|
||||
|
||||
|
||||
string item = jnode.get_string();
|
||||
switch (++index){
|
||||
case 0:
|
||||
@ -275,7 +275,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string delete_trigger_file = path + "/delete";
|
||||
if (file_exists(delete_trigger_file)){
|
||||
marked_for_deletion = true;
|
||||
@ -284,24 +284,24 @@ public class Snapshot : GLib.Object{
|
||||
else{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
|
||||
//log_debug("read_control_file(): exit");
|
||||
}
|
||||
|
||||
public void read_exclude_list(){
|
||||
|
||||
|
||||
string list_file = path + "/exclude.list";
|
||||
|
||||
exclude_list.clear();
|
||||
|
||||
var f = File.new_for_path(list_file);
|
||||
|
||||
|
||||
if (f.query_exists()) {
|
||||
|
||||
|
||||
foreach(string path in file_read(list_file).split("\n")){
|
||||
|
||||
|
||||
path = path.strip();
|
||||
|
||||
|
||||
if (!exclude_list.contains(path) && path.length > 0){
|
||||
exclude_list.add(path);
|
||||
}
|
||||
@ -315,30 +315,30 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
public void read_fstab_file(){
|
||||
|
||||
|
||||
string fstab_path = path_combine(path, "/localhost/etc/fstab");
|
||||
|
||||
|
||||
if (btrfs_mode){
|
||||
fstab_path = path_combine(path, "/@/etc/fstab");
|
||||
}
|
||||
|
||||
|
||||
fstab_list = FsTabEntry.read_file(fstab_path);
|
||||
}
|
||||
|
||||
public void read_crypttab_file(){
|
||||
|
||||
|
||||
string crypttab_path = path_combine(path, "/localhost/etc/crypttab");
|
||||
|
||||
|
||||
if (btrfs_mode){
|
||||
crypttab_path = path_combine(path, "/@/etc/crypttab");
|
||||
}
|
||||
|
||||
|
||||
cryttab_list = CryptTabEntry.read_file(crypttab_path);
|
||||
}
|
||||
|
||||
public void update_control_file(){
|
||||
/* Updates tag and comments */
|
||||
|
||||
|
||||
try{
|
||||
string ctl_file = path + "/info.json";
|
||||
var f = File.new_for_path(ctl_file);
|
||||
@ -371,7 +371,7 @@ public class Snapshot : GLib.Object{
|
||||
subvols.set_array_member(subvol.name,arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var json = new Json.Generator();
|
||||
json.pretty = true;
|
||||
json.indent = 2;
|
||||
@ -386,15 +386,15 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
public void remove_control_file(){
|
||||
|
||||
|
||||
string ctl_file = path + "/info.json";
|
||||
file_delete(ctl_file);
|
||||
}
|
||||
|
||||
|
||||
public static Snapshot write_control_file(
|
||||
string snapshot_path, DateTime dt_created, string root_uuid, string distro_full_name,
|
||||
string snapshot_path, DateTime dt_created, string root_uuid, string distro_full_name,
|
||||
string tag, string comments, int64 item_count, bool is_btrfs, bool is_live, SnapshotRepo repo, bool silent = false){
|
||||
|
||||
|
||||
var ctl_path = snapshot_path + "/info.json";
|
||||
var config = new Json.Object();
|
||||
|
||||
@ -434,7 +434,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
// check
|
||||
|
||||
|
||||
public bool has_subvolumes(){
|
||||
foreach(FsTabEntry en in fstab_list){
|
||||
if (en.options.contains("subvol=@")){
|
||||
@ -456,7 +456,7 @@ public class Snapshot : GLib.Object{
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// actions
|
||||
|
||||
public bool remove(bool wait){
|
||||
@ -466,7 +466,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
bool status = true;
|
||||
|
||||
|
||||
if (btrfs_mode){
|
||||
status = remove_btrfs();
|
||||
}
|
||||
@ -476,21 +476,21 @@ public class Snapshot : GLib.Object{
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
public bool remove_rsync(bool wait){
|
||||
|
||||
log_msg(string.nfill(78, '-'));
|
||||
|
||||
|
||||
var message = _("Removing") + " '%s'...".printf(name);
|
||||
log_msg(message);
|
||||
|
||||
|
||||
delete_file_task.dest_path = "%s/".printf(path);
|
||||
delete_file_task.status_message = message;
|
||||
delete_file_task.prg_count_total = Main.first_snapshot_count;
|
||||
delete_file_task.execute();
|
||||
|
||||
if (wait){
|
||||
|
||||
|
||||
while (delete_file_task.status == AppStatus.RUNNING){
|
||||
|
||||
sleep(1000);
|
||||
@ -499,14 +499,14 @@ public class Snapshot : GLib.Object{
|
||||
stdout.printf("%6.2f%% %s (%s %s)\r".printf(
|
||||
delete_file_task.progress * 100.0, _("complete"),
|
||||
delete_file_task.stat_time_remaining, _("remaining")));
|
||||
|
||||
|
||||
stdout.flush();
|
||||
}
|
||||
|
||||
stdout.printf(string.nfill(80, ' ') + "\r");
|
||||
stdout.flush();
|
||||
|
||||
message = "%s '%s'".printf(_("Removed"), name);
|
||||
message = "%s '%s'".printf(_("Removed"), name);
|
||||
log_msg(message);
|
||||
log_msg(string.nfill(78, '-'));
|
||||
}
|
||||
@ -517,14 +517,14 @@ public class Snapshot : GLib.Object{
|
||||
public bool remove_btrfs(){
|
||||
|
||||
log_msg(string.nfill(78, '-'));
|
||||
|
||||
|
||||
var message = _("Removing snapshot") + ": %s".printf(name);
|
||||
log_msg(message);
|
||||
|
||||
|
||||
// delete subvolumes
|
||||
|
||||
|
||||
foreach(var subvol in subvolumes.values){
|
||||
|
||||
|
||||
bool ok = subvol.remove();
|
||||
if (!ok) {
|
||||
log_error(_("Failed to remove snapshot") + ": %s".printf(name));
|
||||
@ -536,7 +536,7 @@ public class Snapshot : GLib.Object{
|
||||
// delete directories after **all** subvolumes have been deleted
|
||||
|
||||
foreach(var subvol in subvolumes.values){
|
||||
|
||||
|
||||
bool ok = dir_delete(paths[subvol.name], true);
|
||||
if (!ok) {
|
||||
log_error(_("Failed to remove snapshot") + ": %s".printf(name));
|
||||
@ -546,7 +546,7 @@ public class Snapshot : GLib.Object{
|
||||
}
|
||||
|
||||
if (!dir_delete(path, true)){
|
||||
|
||||
|
||||
log_error(_("Failed to remove snapshot") + ": %s".printf(name));
|
||||
log_msg(string.nfill(78, '-'));
|
||||
return false;
|
||||
@ -554,14 +554,14 @@ public class Snapshot : GLib.Object{
|
||||
|
||||
log_msg(_("Removed snapshot") + ": %s".printf(name));
|
||||
log_msg(string.nfill(78, '-'));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void mark_for_deletion(){
|
||||
|
||||
|
||||
string delete_trigger_file = path + "/delete";
|
||||
|
||||
|
||||
if (!file_exists(delete_trigger_file)){
|
||||
file_write(delete_trigger_file, "");
|
||||
marked_for_deletion = true;
|
||||
|
@ -30,7 +30,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class SnapshotRepo : GLib.Object{
|
||||
|
||||
|
||||
public Device device = null;
|
||||
public Device device_home = null; // used for btrfs mode only
|
||||
public string mount_path = "";
|
||||
@ -53,46 +53,46 @@ public class SnapshotRepo : GLib.Object{
|
||||
public SnapshotRepo.from_path(string path, Gtk.Window? parent_win, bool _btrfs_mode){
|
||||
|
||||
log_debug("SnapshotRepo: from_path()");
|
||||
|
||||
|
||||
//this.snapshot_path_user = path;
|
||||
//this.use_snapshot_path_custom = true;
|
||||
|
||||
this.mount_path = path;
|
||||
this.parent_window = parent_win;
|
||||
this.btrfs_mode = _btrfs_mode;
|
||||
|
||||
|
||||
snapshots = new Gee.ArrayList<Snapshot>();
|
||||
invalid_snapshots = new Gee.ArrayList<Snapshot>();
|
||||
mount_paths = new Gee.HashMap<string,string>();
|
||||
|
||||
|
||||
//log_debug("Selected snapshot repo path: %s".printf(path));
|
||||
|
||||
|
||||
var list = Device.get_disk_space_using_df(path);
|
||||
|
||||
|
||||
if (list.size > 0){
|
||||
|
||||
|
||||
device = list[0];
|
||||
|
||||
|
||||
log_debug(_("Device") + ": %s".printf(device.device));
|
||||
log_debug(_("Free space") + ": %s".printf(format_file_size(device.free_bytes)));
|
||||
}
|
||||
|
||||
|
||||
check_status();
|
||||
}
|
||||
|
||||
public SnapshotRepo.from_device(Device dev, Gtk.Window? parent_win, bool btrfs_repo){
|
||||
|
||||
log_debug("SnapshotRepo: from_device(): %s".printf(btrfs_repo ? "BTRFS" : "RSYNC"));
|
||||
|
||||
|
||||
this.device = dev;
|
||||
//this.use_snapshot_path_custom = false;
|
||||
this.parent_window = parent_win;
|
||||
this.btrfs_mode = btrfs_repo;
|
||||
|
||||
|
||||
snapshots = new Gee.ArrayList<Snapshot>();
|
||||
invalid_snapshots = new Gee.ArrayList<Snapshot>();
|
||||
mount_paths = new Gee.HashMap<string,string>();
|
||||
|
||||
|
||||
init_from_device();
|
||||
}
|
||||
|
||||
@ -100,17 +100,17 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
log_debug("SnapshotRepo: from_uuid(): %s".printf(btrfs_repo ? "BTRFS" : "RSYNC"));
|
||||
log_debug("uuid=%s".printf(uuid));
|
||||
|
||||
|
||||
device = Device.get_device_by_uuid(uuid);
|
||||
if (device == null){
|
||||
device = new Device();
|
||||
device.uuid = uuid;
|
||||
}
|
||||
|
||||
|
||||
//this.use_snapshot_path_custom = false;
|
||||
this.parent_window = parent_win;
|
||||
this.btrfs_mode = btrfs_repo;
|
||||
|
||||
|
||||
snapshots = new Gee.ArrayList<Snapshot>();
|
||||
invalid_snapshots = new Gee.ArrayList<Snapshot>();
|
||||
mount_paths = new Gee.HashMap<string,string>();
|
||||
@ -124,7 +124,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
log_debug("SnapshotRepo: from_null()");
|
||||
log_debug("device not set");
|
||||
|
||||
|
||||
snapshots = new Gee.ArrayList<Snapshot>();
|
||||
invalid_snapshots = new Gee.ArrayList<Snapshot>();
|
||||
mount_paths = new Gee.HashMap<string,string>();
|
||||
@ -135,21 +135,21 @@ public class SnapshotRepo : GLib.Object{
|
||||
private void init_from_device(){
|
||||
|
||||
log_debug("SnapshotRepo: init_from_device()");
|
||||
|
||||
|
||||
if ((device != null) && (device.uuid.length > 0) && (Device.get_device_by_uuid(device.uuid) != null)){
|
||||
|
||||
|
||||
log_debug("");
|
||||
unlock_and_mount_devices();
|
||||
|
||||
if ((device != null) && (device.device.length > 0)){
|
||||
|
||||
|
||||
log_debug(_("Selected snapshot device") + ": %s".printf(device.device));
|
||||
log_debug(_("Free space") + ": %s".printf(format_file_size(device.free_bytes)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((device != null) && (device.device.length > 0)){
|
||||
|
||||
|
||||
check_status();
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
|
||||
public string timeshift_path {
|
||||
owned get{
|
||||
if (btrfs_mode){
|
||||
@ -168,13 +168,13 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string snapshots_path {
|
||||
owned get{
|
||||
return path_combine(timeshift_path, "snapshots");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// load ---------------------------------------
|
||||
|
||||
public bool unlock_and_mount_devices(){
|
||||
@ -189,7 +189,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
mount_path = unlock_and_mount_device(device, "/run/timeshift/backup");
|
||||
|
||||
|
||||
if (mount_path.length == 0){
|
||||
return false;
|
||||
}
|
||||
@ -197,28 +197,28 @@ public class SnapshotRepo : GLib.Object{
|
||||
// rsync
|
||||
mount_paths["@"] = "";
|
||||
mount_paths["@home"] = "";
|
||||
|
||||
|
||||
if (btrfs_mode){
|
||||
|
||||
|
||||
mount_paths["@"] = mount_path;
|
||||
mount_paths["@home"] = mount_path; //default
|
||||
device_home = device; //default
|
||||
|
||||
|
||||
// mount @home if on different disk -------
|
||||
|
||||
|
||||
var repo_subvolumes = Subvolume.detect_subvolumes_for_system_by_path(path_combine(mount_path,"@"), this, parent_window);
|
||||
|
||||
|
||||
if (repo_subvolumes.has_key("@home")){
|
||||
|
||||
|
||||
var subvol = repo_subvolumes["@home"];
|
||||
|
||||
|
||||
if (subvol.device_uuid != device.uuid){
|
||||
|
||||
|
||||
// @home is on a separate device
|
||||
device_home = subvol.get_device();
|
||||
|
||||
|
||||
mount_paths["@home"] = unlock_and_mount_device(device_home, "/run/timeshift/backup-home");
|
||||
|
||||
|
||||
if (mount_paths["@home"].length == 0){
|
||||
return false;
|
||||
}
|
||||
@ -229,31 +229,31 @@ public class SnapshotRepo : GLib.Object{
|
||||
load_snapshots();
|
||||
|
||||
log_debug("SnapshotRepo: unlock_and_mount_device(): exit");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string unlock_and_mount_device(Device device_to_mount, string path_to_mount){
|
||||
|
||||
// mounts the device and returns mount path
|
||||
|
||||
|
||||
log_debug("SnapshotRepo: unlock_and_mount_device()");
|
||||
|
||||
Device dev = device_to_mount;
|
||||
|
||||
|
||||
if (dev == null){
|
||||
log_debug("device=null");
|
||||
}
|
||||
else{
|
||||
log_debug("device=%s".printf(dev.device));
|
||||
}
|
||||
|
||||
|
||||
// unlock encrypted device
|
||||
if (dev.is_encrypted_partition()){
|
||||
|
||||
dev = unlock_encrypted_device(dev);
|
||||
device = dev; // set repo device to unlocked child disk
|
||||
|
||||
|
||||
if (dev == null){
|
||||
log_debug("device is null");
|
||||
log_debug("SnapshotRepo: unlock_and_mount_device(): exit");
|
||||
@ -263,7 +263,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
// mount
|
||||
bool ok = Device.mount(dev.uuid, path_to_mount, ""); // TODO: check if already mounted
|
||||
|
||||
|
||||
if (ok){
|
||||
return path_to_mount;
|
||||
}
|
||||
@ -275,7 +275,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
public Device? unlock_encrypted_device(Device luks_device){
|
||||
|
||||
log_debug("SnapshotRepo: unlock_encrypted_device()");
|
||||
|
||||
|
||||
if (luks_device == null){
|
||||
log_debug("luks_device=null");
|
||||
return null;
|
||||
@ -290,14 +290,14 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
return luks_unlocked;
|
||||
}
|
||||
|
||||
|
||||
public bool load_snapshots(){
|
||||
|
||||
log_debug("SnapshotRepo: load_snapshots()");
|
||||
|
||||
|
||||
snapshots.clear();
|
||||
invalid_snapshots.clear();
|
||||
|
||||
|
||||
if ((device == null) || !dir_exists(snapshots_path)){
|
||||
return false;
|
||||
}
|
||||
@ -310,9 +310,9 @@ public class SnapshotRepo : GLib.Object{
|
||||
while (info != null) {
|
||||
if (info.get_file_type() == FileType.DIRECTORY) {
|
||||
if (info.get_name() != ".sync") {
|
||||
|
||||
|
||||
//log_debug("load_snapshots():" + snapshots_path + "/" + info.get_name());
|
||||
|
||||
|
||||
Snapshot bak = new Snapshot(snapshots_path + "/" + info.get_name(), btrfs_mode, this);
|
||||
if (bak.valid){
|
||||
snapshots.add(bak);
|
||||
@ -337,7 +337,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
});
|
||||
|
||||
// reset the 'live' flag ------------
|
||||
|
||||
|
||||
DateTime dt_boot = new DateTime.now_local();
|
||||
dt_boot = dt_boot.add_seconds(-1.0 * get_system_uptime_seconds());
|
||||
foreach(var bak in snapshots){
|
||||
@ -363,16 +363,16 @@ public class SnapshotRepo : GLib.Object{
|
||||
if (btrfs_mode){
|
||||
App.query_subvolume_info(this);
|
||||
}
|
||||
|
||||
|
||||
log_debug("loading snapshots from '%s': %d found".printf(snapshots_path, snapshots.size));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get tagged snapshots ----------------------------------
|
||||
|
||||
|
||||
public Gee.ArrayList<Snapshot?> get_snapshots_by_tag(string tag = ""){
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<Snapshot?>();
|
||||
|
||||
foreach(Snapshot bak in snapshots){
|
||||
@ -390,9 +390,9 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
public Snapshot? get_latest_snapshot(string tag, string sys_uuid){
|
||||
|
||||
|
||||
var list = get_snapshots_by_tag(tag);
|
||||
|
||||
|
||||
for(int i = list.size - 1; i >= 0; i--){
|
||||
var bak = list[i];
|
||||
if (bak.sys_uuid == sys_uuid){
|
||||
@ -404,7 +404,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
public Snapshot? get_oldest_snapshot(string tag, string sys_uuid){
|
||||
|
||||
|
||||
var list = get_snapshots_by_tag(tag);
|
||||
|
||||
for(int i = 0; i < list.size; i++){
|
||||
@ -413,7 +413,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
return bak;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -422,7 +422,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
public void check_status(){
|
||||
|
||||
log_debug("SnapshotRepo: check_status()");
|
||||
|
||||
|
||||
status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE;
|
||||
status_message = "";
|
||||
status_details = "";
|
||||
@ -437,17 +437,17 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
if ((App != null) && (App.app_mode.length == 0)){
|
||||
|
||||
|
||||
log_debug("%s: '%s'".printf(
|
||||
_("Snapshot device"),
|
||||
(device == null) ? " UNKNOWN" : device.device));
|
||||
|
||||
|
||||
log_debug("%s: %s".printf(
|
||||
_("Snapshot location"), mount_path));
|
||||
|
||||
log_debug(status_message);
|
||||
log_debug(status_details);
|
||||
|
||||
|
||||
log_debug("%s: %s".printf(
|
||||
_("Status"),
|
||||
status_code.to_string().replace("SNAPSHOT_LOCATION_STATUS_","")));
|
||||
@ -461,11 +461,11 @@ public class SnapshotRepo : GLib.Object{
|
||||
public bool available(){
|
||||
|
||||
log_debug("SnapshotRepo: available()");
|
||||
|
||||
|
||||
/*if (use_snapshot_path_custom){
|
||||
|
||||
log_debug("checking selected path");
|
||||
|
||||
|
||||
if (snapshot_path_user.strip().length == 0){
|
||||
status_message = _("Snapshot device not selected");
|
||||
status_details = _("Select the snapshot device");
|
||||
@ -473,13 +473,13 @@ public class SnapshotRepo : GLib.Object{
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
|
||||
|
||||
log_debug("path: %s".printf(snapshot_path_user));
|
||||
|
||||
|
||||
if (!dir_exists(snapshot_path_user)){
|
||||
|
||||
log_debug("path not found");
|
||||
|
||||
|
||||
status_message = _("Snapshot location not available");
|
||||
status_details = _("Path not found") + ": '%s'".printf(snapshot_path_user);
|
||||
status_code = SnapshotLocationStatus.NOT_AVAILABLE;
|
||||
@ -487,7 +487,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
else{
|
||||
log_debug("path exists");
|
||||
|
||||
|
||||
bool is_readonly;
|
||||
bool hardlink_supported =
|
||||
filesystem_supports_hardlinks(snapshot_path_user, out is_readonly);
|
||||
@ -515,7 +515,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
}
|
||||
else{*/
|
||||
|
||||
|
||||
//log_debug("checking selected device");
|
||||
|
||||
if (device == null){
|
||||
@ -553,7 +553,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
public bool has_btrfs_system(){
|
||||
|
||||
|
||||
log_debug("SnapshotRepo: has_btrfs_system()");
|
||||
|
||||
var root_path = path_combine(mount_paths["@"],"@");
|
||||
@ -571,11 +571,11 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public bool has_snapshots(){
|
||||
|
||||
|
||||
log_debug("SnapshotRepo: has_snapshots()");
|
||||
|
||||
|
||||
//load_snapshots();
|
||||
return (snapshots.size > 0);
|
||||
}
|
||||
@ -583,7 +583,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
public bool has_space(){
|
||||
|
||||
log_debug("SnapshotRepo: has_space()");
|
||||
|
||||
|
||||
if ((device != null) && (device.device.length > 0)){
|
||||
device.query_disk_space();
|
||||
}
|
||||
@ -591,28 +591,28 @@ public class SnapshotRepo : GLib.Object{
|
||||
log_debug("device is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (snapshots.size > 0){
|
||||
// has snapshots, check minimum space
|
||||
|
||||
//log_debug("has snapshots");
|
||||
|
||||
|
||||
if (device.free_bytes < Main.MIN_FREE_SPACE){
|
||||
status_message = _("Not enough disk space");
|
||||
status_message += " (< %s)".printf(format_file_size(Main.MIN_FREE_SPACE, false, "", true, 0));
|
||||
|
||||
|
||||
status_details = _("Select another device or free up some space");
|
||||
|
||||
|
||||
status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE;
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
//ok
|
||||
status_message = _("OK");
|
||||
|
||||
|
||||
status_details = _("%d snapshots, %s free").printf(
|
||||
snapshots.size, format_file_size(device.free_bytes));
|
||||
|
||||
|
||||
status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE;
|
||||
return true;
|
||||
}
|
||||
@ -621,24 +621,24 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
// no snapshots, check estimated space
|
||||
log_debug("no snapshots");
|
||||
|
||||
|
||||
var required_space = Main.first_snapshot_size;
|
||||
|
||||
if (device.free_bytes < required_space){
|
||||
status_message = _("Not enough disk space");
|
||||
status_message += " (< %s)".printf(format_file_size(required_space));
|
||||
|
||||
|
||||
status_details = _("Select another device or free up some space");
|
||||
|
||||
|
||||
status_code = SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE;
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
status_message = _("No snapshots on this device");
|
||||
|
||||
|
||||
status_details = _("First snapshot requires:");
|
||||
status_details += " %s".printf(format_file_size(required_space));
|
||||
|
||||
|
||||
status_code = SnapshotLocationStatus.NO_SNAPSHOTS_HAS_SPACE;
|
||||
return true;
|
||||
}
|
||||
@ -646,11 +646,11 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
public void print_status(){
|
||||
|
||||
|
||||
check_status();
|
||||
|
||||
|
||||
//log_msg("");
|
||||
|
||||
|
||||
if (device == null){
|
||||
log_msg("%-6s : %s".printf(_("Device"), _("Not Selected")));
|
||||
}
|
||||
@ -665,17 +665,17 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
log_msg("");
|
||||
}
|
||||
|
||||
|
||||
// actions -------------------------------------
|
||||
|
||||
public void auto_remove(){
|
||||
|
||||
log_debug("SnapshotRepo: auto_remove()");
|
||||
|
||||
|
||||
DateTime now = new DateTime.now_local();
|
||||
DateTime dt_limit;
|
||||
int count_limit;
|
||||
|
||||
|
||||
// remove tags from older backups - boot ---------------
|
||||
|
||||
var list = get_snapshots_by_tag("boot");
|
||||
@ -694,7 +694,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
string[] levels = { "hourly","daily","weekly","monthly" };
|
||||
|
||||
foreach(string level in levels){
|
||||
|
||||
|
||||
list = get_snapshots_by_tag(level);
|
||||
|
||||
if (list.size == 0) { continue; }
|
||||
@ -727,16 +727,16 @@ public class SnapshotRepo : GLib.Object{
|
||||
log_msg(_("Maximum backups exceeded for backup level") + " '%s'".printf(level));
|
||||
|
||||
int snaps_count = list.size;
|
||||
|
||||
|
||||
foreach(var snap in list){
|
||||
|
||||
if (snap.description.strip().length > 0){ continue; } // don't delete snapshots with comments
|
||||
|
||||
|
||||
if ((snap.date.compare(dt_limit) < 0) && (snaps_count > count_limit)){
|
||||
|
||||
snap.remove_tag(level);
|
||||
snaps_count--;
|
||||
|
||||
|
||||
log_msg(_("Snapshot") + " '%s' ".printf(list[0].name) + _("un-tagged") + " '%s'".printf(level));
|
||||
}
|
||||
}
|
||||
@ -765,7 +765,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}*/
|
||||
|
||||
// delete untagged snapshots
|
||||
|
||||
|
||||
remove_untagged();
|
||||
|
||||
// delete older backups - minimum space -------
|
||||
@ -776,9 +776,9 @@ public class SnapshotRepo : GLib.Object{
|
||||
show_msg = true;
|
||||
count = 0;
|
||||
while ((device.size_bytes - device.used_bytes) < App.minimum_free_disk_space){
|
||||
|
||||
|
||||
load_snapshots();
|
||||
|
||||
|
||||
if (snapshots.size > 0){
|
||||
if (!snapshots[0].has_tag("ondemand")){
|
||||
|
||||
@ -792,7 +792,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
snapshots[0].remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
device.query_disk_space();
|
||||
}
|
||||
* */
|
||||
@ -809,7 +809,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
public void remove_untagged(){
|
||||
|
||||
log_debug("SnapshotRepo: remove_untagged()");
|
||||
|
||||
|
||||
bool show_msg = true;
|
||||
|
||||
foreach(Snapshot bak in snapshots){
|
||||
@ -830,22 +830,22 @@ public class SnapshotRepo : GLib.Object{
|
||||
public void remove_marked_for_deletion(){
|
||||
|
||||
bool show_msg = true;
|
||||
|
||||
|
||||
foreach(var bak in snapshots){
|
||||
if (bak.marked_for_deletion){
|
||||
|
||||
|
||||
if (show_msg){
|
||||
log_msg("%s (%s):".printf(_("Removing snapshots"), _("marked for deletion")));
|
||||
show_msg = false;
|
||||
}
|
||||
|
||||
|
||||
bak.remove(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
load_snapshots(); // update the list
|
||||
}
|
||||
|
||||
|
||||
public void remove_invalid(){
|
||||
|
||||
bool show_msg = true;
|
||||
@ -856,10 +856,10 @@ public class SnapshotRepo : GLib.Object{
|
||||
log_msg("%s (%s):".printf(_("Removing snapshots"), _("incomplete")));
|
||||
show_msg = false;
|
||||
}
|
||||
|
||||
|
||||
bak.remove(true);
|
||||
}
|
||||
|
||||
|
||||
load_snapshots(); // update the list
|
||||
}
|
||||
|
||||
@ -868,7 +868,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
if (dir_exists(timeshift_path)){
|
||||
|
||||
log_msg(_("Removing snapshots") + " > " + _("all") + "...");
|
||||
|
||||
|
||||
//delete snapshots
|
||||
foreach(var bak in snapshots){
|
||||
bak.remove(true);
|
||||
@ -879,7 +879,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
bool ok = delete_directory(timeshift_path);
|
||||
|
||||
load_snapshots(); // update the list
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
else{
|
||||
@ -890,14 +890,14 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
public bool remove_sync_dir(){
|
||||
string sync_dir = mount_path + "/timeshift/snapshots/.sync";
|
||||
|
||||
|
||||
//delete .sync
|
||||
if (dir_exists(sync_dir)){
|
||||
if (!delete_directory(sync_dir)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -909,12 +909,12 @@ public class SnapshotRepo : GLib.Object{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// private -------------------------------------------
|
||||
|
||||
|
||||
private bool delete_directory(string dir_path){
|
||||
thr_args1 = dir_path;
|
||||
|
||||
@ -981,7 +981,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
}
|
||||
|
||||
// symlinks ----------------------------------------
|
||||
|
||||
|
||||
public void create_symlinks(){
|
||||
string cmd = "";
|
||||
string std_out;
|
||||
@ -999,7 +999,7 @@ public class SnapshotRepo : GLib.Object{
|
||||
|
||||
foreach(var bak in snapshots){
|
||||
foreach(string tag in bak.tags){
|
||||
|
||||
|
||||
path = "%s-%s".printf(snapshots_path, tag);
|
||||
cmd = "ln --symbolic \"../snapshots/%s\" -t \"%s\"".printf(bak.name, path);
|
||||
|
||||
|
@ -42,9 +42,9 @@ public class Subvolume : GLib.Object{
|
||||
|
||||
//parent
|
||||
public SnapshotRepo? repo;
|
||||
|
||||
|
||||
public Subvolume(string name, string path, string parent_dev_uuid, SnapshotRepo? parent_repo){
|
||||
|
||||
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.device_uuid = parent_dev_uuid;
|
||||
@ -68,10 +68,10 @@ public class Subvolume : GLib.Object{
|
||||
}
|
||||
|
||||
public Device? get_device(){
|
||||
|
||||
|
||||
return Device.get_device_by_uuid(device_uuid);
|
||||
}
|
||||
|
||||
|
||||
public bool exists_on_disk{
|
||||
get {
|
||||
return dir_exists(path);
|
||||
@ -83,29 +83,29 @@ public class Subvolume : GLib.Object{
|
||||
return (repo == null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Gee.HashMap<string, Subvolume> detect_subvolumes_for_system_by_path(
|
||||
string system_path, SnapshotRepo? repo, Gtk.Window? parent_window){
|
||||
|
||||
var map = new Gee.HashMap<string, Subvolume>();
|
||||
|
||||
|
||||
log_debug("Searching subvolume for system at path: %s".printf(system_path));
|
||||
|
||||
|
||||
var fstab = FsTabEntry.read_file(path_combine(system_path, "/etc/fstab"));
|
||||
var crypttab = CryptTabEntry.read_file(path_combine(system_path, "/etc/crypttab"));
|
||||
|
||||
|
||||
foreach(var item in fstab){
|
||||
|
||||
|
||||
if (!item.is_for_system_directory()){ continue; }
|
||||
|
||||
|
||||
if (item.subvolume_name().length > 0){
|
||||
|
||||
|
||||
var dev = item.resolve_device(crypttab, parent_window);
|
||||
var dev_name = (dev == null) ? "" : dev.device;
|
||||
var dev_uuid = (dev == null) ? "" : dev.uuid;
|
||||
|
||||
|
||||
log_debug("Found subvolume: %s, on device: %s".printf(item.subvolume_name(), dev_name));
|
||||
|
||||
|
||||
var subvol = new Subvolume(item.subvolume_name(), item.mount_point, dev_uuid, repo);
|
||||
map.set(subvol.name, subvol);
|
||||
}
|
||||
@ -115,12 +115,12 @@ public class Subvolume : GLib.Object{
|
||||
}
|
||||
|
||||
public void print_info(){
|
||||
|
||||
|
||||
log_debug("name=%s, uuid=%s, id=%ld, path=%s".printf(name, device_uuid, id, path));
|
||||
}
|
||||
|
||||
// actions ----------------------------------
|
||||
|
||||
|
||||
public bool remove(){
|
||||
|
||||
if (is_system_subvolume){
|
||||
@ -131,7 +131,7 @@ public class Subvolume : GLib.Object{
|
||||
path = path_combine("/run/timeshift/backup-home", "@home");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string cmd = "";
|
||||
string std_out, std_err, subpath;
|
||||
int ret_val;
|
||||
@ -141,7 +141,7 @@ public class Subvolume : GLib.Object{
|
||||
log_msg("%s: %s (Id:%ld)".printf(_("Deleting subvolume"), name, id));
|
||||
|
||||
string options = App.use_option_raw ? "--commit-after" : "";
|
||||
|
||||
|
||||
subpath = path_combine(path, name);
|
||||
if (dir_exists(subpath)) { // there is a nested subvol to remove first
|
||||
cmd = "btrfs subvolume delete %s '%s'".printf(options, subpath);
|
||||
@ -154,7 +154,7 @@ public class Subvolume : GLib.Object{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cmd = "btrfs subvolume delete %s '%s'".printf(options, path);
|
||||
log_debug(cmd);
|
||||
ret_val = exec_sync(cmd, out std_out, out std_err);
|
||||
@ -165,11 +165,11 @@ public class Subvolume : GLib.Object{
|
||||
}
|
||||
|
||||
log_msg("%s: %s (Id:%ld)\n".printf(_("Deleted subvolume"), name, id));
|
||||
|
||||
|
||||
if ((id > 0) && (repo != null)){
|
||||
|
||||
log_msg("%s: 0/%ld".printf(_("Destroying qgroup"), id));
|
||||
|
||||
|
||||
cmd = "btrfs qgroup destroy 0/%ld '%s'".printf(id, repo.mount_paths[name]);
|
||||
log_debug(cmd);
|
||||
ret_val = exec_sync(cmd, out std_out, out std_err);
|
||||
@ -189,7 +189,7 @@ public class Subvolume : GLib.Object{
|
||||
if (is_system_subvolume) { return false; }
|
||||
|
||||
// restore snapshot subvolume by creating new subvolume snapshots ----------------------
|
||||
|
||||
|
||||
string src_path = path;
|
||||
string dst_path = path_combine(mount_path, name);
|
||||
|
||||
@ -202,13 +202,13 @@ public class Subvolume : GLib.Object{
|
||||
log_error("%s: %s".printf(_("Subvolume exists at destination"), dst_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
string cmd = "btrfs subvolume snapshot '%s' '%s'".printf(src_path, dst_path);
|
||||
log_debug(cmd);
|
||||
|
||||
string std_out, std_err;
|
||||
int status = exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
if (status != 0){
|
||||
log_error(std_err);
|
||||
log_error(_("btrfs returned an error") + ": %d".printf(status));
|
||||
@ -217,7 +217,7 @@ public class Subvolume : GLib.Object{
|
||||
}
|
||||
|
||||
log_msg(_("Restored system subvolume") + ": %s".printf(name));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ extern void exit(int exit_code);
|
||||
public class AppGtk : GLib.Object {
|
||||
|
||||
public static int main (string[] args) {
|
||||
|
||||
|
||||
set_locale();
|
||||
|
||||
Gtk.init(ref args);
|
||||
@ -71,7 +71,7 @@ public class AppGtk : GLib.Object {
|
||||
}
|
||||
|
||||
private static void set_locale() {
|
||||
|
||||
|
||||
log_debug("setting locale...");
|
||||
Intl.setlocale(GLib.LocaleCategory.MESSAGES, "timeshift");
|
||||
Intl.textdomain(GETTEXT_PACKAGE);
|
||||
@ -80,7 +80,7 @@ public class AppGtk : GLib.Object {
|
||||
}
|
||||
|
||||
public static bool parse_arguments(string[] args) {
|
||||
|
||||
|
||||
//parse options
|
||||
for (int k = 1; k < args.length; k++) // Oth arg is app path
|
||||
{
|
||||
@ -107,7 +107,7 @@ public class AppGtk : GLib.Object {
|
||||
}
|
||||
|
||||
public static string help_message() {
|
||||
|
||||
|
||||
string msg = "\n%s v%s by Tony George (%s)\n".printf(AppName, AppVersion, AppAuthorEmail);
|
||||
msg += "\n";
|
||||
msg += _("Syntax") + ": timeshift-gtk [options]\n";
|
||||
@ -122,9 +122,9 @@ public class AppGtk : GLib.Object {
|
||||
}
|
||||
|
||||
public static void check_if_admin(){
|
||||
|
||||
|
||||
if (!user_is_admin()){
|
||||
|
||||
|
||||
var msg = _("Admin access is required to backup and restore system files.") + "\n";
|
||||
msg += _("Please re-run the application as admin (using 'sudo' or 'su')");
|
||||
|
||||
@ -138,7 +138,7 @@ public class AppGtk : GLib.Object {
|
||||
}
|
||||
|
||||
public static void start_application(){
|
||||
|
||||
|
||||
// show main window
|
||||
var window = new MainWindow ();
|
||||
window.destroy.connect(Gtk.main_quit);
|
||||
|
@ -37,7 +37,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class BackupBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.Spinner spinner;
|
||||
public Gtk.Label lbl_msg;
|
||||
public Gtk.Label lbl_status;
|
||||
@ -62,25 +62,25 @@ class BackupBox : Gtk.Box{
|
||||
public BackupBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("BackupBox: BackupBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
|
||||
add_label_header(this, _("Creating Snapshot..."), true);
|
||||
|
||||
add_progress_area();
|
||||
|
||||
// add count labels ---------------------------------
|
||||
|
||||
|
||||
Gtk.SizeGroup sg_label = null;
|
||||
Gtk.SizeGroup sg_value = null;
|
||||
|
||||
var label = add_label(this, _("File and directory counts:"), true);
|
||||
label.margin_bottom = 6;
|
||||
label.margin_top = 12;
|
||||
|
||||
|
||||
lbl_unchanged = add_count_label(this, _("No Change"), ref sg_label, ref sg_value);
|
||||
lbl_created = add_count_label(this, _("Created"), ref sg_label, ref sg_value);
|
||||
lbl_deleted = add_count_label(this, _("Deleted"), ref sg_label, ref sg_value);
|
||||
@ -88,7 +88,7 @@ class BackupBox : Gtk.Box{
|
||||
|
||||
label = add_label(this, _("Changed items:"), true);
|
||||
label.margin_bottom = 6;
|
||||
|
||||
|
||||
lbl_checksum = add_count_label(this, _("Checksum"), ref sg_label, ref sg_value);
|
||||
lbl_size = add_count_label(this, _("Size"), ref sg_label, ref sg_value);
|
||||
lbl_timestamp = add_count_label(this, _("Timestamp"), ref sg_label, ref sg_value);
|
||||
@ -102,14 +102,14 @@ class BackupBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void add_progress_area(){
|
||||
|
||||
|
||||
var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
add (hbox_status);
|
||||
|
||||
|
||||
spinner = new Gtk.Spinner();
|
||||
spinner.active = true;
|
||||
hbox_status.add(spinner);
|
||||
|
||||
|
||||
//lbl_msg
|
||||
lbl_msg = add_label(hbox_status, _("Preparing..."));
|
||||
lbl_msg.hexpand = true;
|
||||
@ -128,11 +128,11 @@ class BackupBox : Gtk.Box{
|
||||
lbl_status.max_width_chars = 45;
|
||||
lbl_status.margin_bottom = 6;
|
||||
}
|
||||
|
||||
|
||||
private Gtk.Label add_count_label(Gtk.Box box, string text,
|
||||
ref Gtk.SizeGroup? sg_label, ref Gtk.SizeGroup? sg_value,
|
||||
int add_margin_bottom = 0){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
box.add (hbox);
|
||||
|
||||
@ -141,7 +141,7 @@ class BackupBox : Gtk.Box{
|
||||
label.margin_left = 12;
|
||||
label.margin_right = 6;
|
||||
var text_label = label;
|
||||
|
||||
|
||||
if (add_margin_bottom > 0){
|
||||
label.margin_bottom = add_margin_bottom;
|
||||
}
|
||||
@ -184,9 +184,9 @@ class BackupBox : Gtk.Box{
|
||||
}
|
||||
|
||||
if (App.btrfs_mode){
|
||||
|
||||
|
||||
while (thread_is_running){
|
||||
|
||||
|
||||
gtk_do_events();
|
||||
sleep(200);
|
||||
|
||||
@ -200,7 +200,7 @@ class BackupBox : Gtk.Box{
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
|
||||
|
||||
//string last_message = "";
|
||||
int wait_interval_millis = 100;
|
||||
int status_line_counter = 0;
|
||||
@ -208,7 +208,7 @@ class BackupBox : Gtk.Box{
|
||||
string status_line = "";
|
||||
string last_status_line = "";
|
||||
int remaining_counter = 10;
|
||||
|
||||
|
||||
while (thread_is_running){
|
||||
|
||||
status_line = escape_html(App.task.status_line);
|
||||
@ -234,8 +234,8 @@ class BackupBox : Gtk.Box{
|
||||
App.task.stat_time_remaining + " " + _("remaining");
|
||||
|
||||
remaining_counter = 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fraction < 0.99){
|
||||
progressbar.fraction = fraction;
|
||||
#if XAPP
|
||||
@ -271,9 +271,9 @@ class BackupBox : Gtk.Box{
|
||||
|
||||
//TODO: low: check if snapshot was created successfully.
|
||||
}
|
||||
|
||||
|
||||
private void take_snapshot_thread(){
|
||||
|
||||
|
||||
thread_status_success = App.create_snapshot(true,parent_window);
|
||||
thread_is_running = false;
|
||||
}
|
||||
|
@ -38,13 +38,13 @@ class BackupDeviceBox : Gtk.Box{
|
||||
private Gtk.InfoBar infobar_location;
|
||||
private Gtk.Label lbl_infobar_location;
|
||||
private Gtk.Label lbl_common;
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public BackupDeviceBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("BackupDeviceBox: BackupDeviceBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -58,9 +58,9 @@ class BackupDeviceBox : Gtk.Box{
|
||||
// buffer
|
||||
var label = add_label(hbox, "");
|
||||
label.hexpand = true;
|
||||
|
||||
|
||||
// refresh device button
|
||||
|
||||
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
var btn_refresh = add_button(hbox, _("Refresh"), "", size_group, null);
|
||||
btn_refresh.clicked.connect(()=>{
|
||||
@ -69,7 +69,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// TODO: show this message somewhere
|
||||
|
||||
|
||||
//var msg = _("Only Linux partitions are supported.");
|
||||
//msg += "\n" + _("Snapshots will be saved in folder /timeshift");
|
||||
|
||||
@ -86,13 +86,13 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
public void refresh(){
|
||||
|
||||
|
||||
tv_devices_refresh();
|
||||
|
||||
|
||||
check_backup_location();
|
||||
|
||||
if (App.btrfs_mode){
|
||||
|
||||
|
||||
lbl_common.label = "<i>• %s\n• %s\n• %s</i>".printf(
|
||||
_("Devices displayed above have BTRFS file systems."),
|
||||
_("BTRFS snapshots are saved on system partition. Other partitions are not supported."),
|
||||
@ -110,16 +110,16 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void init_tv_devices(){
|
||||
|
||||
|
||||
tv_devices = add_treeview(this);
|
||||
tv_devices.vexpand = true;
|
||||
tv_devices.headers_clickable = true;
|
||||
//tv_devices.rules_hint = true;
|
||||
tv_devices.activate_on_single_click = true;
|
||||
//tv_devices.headers_clickable = true;
|
||||
|
||||
|
||||
// device name
|
||||
|
||||
|
||||
Gtk.CellRendererPixbuf cell_pix;
|
||||
Gtk.CellRendererToggle cell_radio;
|
||||
Gtk.CellRendererText cell_text;
|
||||
@ -128,13 +128,13 @@ class BackupDeviceBox : Gtk.Box{
|
||||
out cell_pix, out cell_radio, out cell_text);
|
||||
|
||||
col.resizable = true;
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_pix, (cell_layout, cell, model, iter)=>{
|
||||
Device dev;
|
||||
model.get (iter, 0, out dev, -1);
|
||||
|
||||
(cell as Gtk.CellRendererPixbuf).visible = (dev.type == "disk");
|
||||
|
||||
|
||||
});
|
||||
|
||||
col.add_attribute(cell_pix, "icon-name", 2);
|
||||
@ -184,9 +184,9 @@ class BackupDeviceBox : Gtk.Box{
|
||||
//(cell as Gtk.CellRendererText).sensitive = (dev.type != "disk");
|
||||
});
|
||||
|
||||
|
||||
|
||||
// type
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Type"), out cell_text);
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
@ -198,10 +198,10 @@ class BackupDeviceBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// size
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Size"), out cell_text);
|
||||
cell_text.xalign = (float) 1.0;
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
Device dev;
|
||||
model.get (iter, 0, out dev, -1);
|
||||
@ -211,10 +211,10 @@ class BackupDeviceBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// free
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Free"), out cell_text);
|
||||
cell_text.xalign = (float) 1.0;
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
Device dev;
|
||||
model.get (iter, 0, out dev, -1);
|
||||
@ -231,10 +231,10 @@ class BackupDeviceBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// name
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Name"), out cell_text);
|
||||
cell_text.xalign = 0.0f;
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
Device dev;
|
||||
model.get (iter, 0, out dev, -1);
|
||||
@ -250,10 +250,10 @@ class BackupDeviceBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// label
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Label"), out cell_text);
|
||||
cell_text.xalign = 0.0f;
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
Device dev;
|
||||
model.get (iter, 0, out dev, -1);
|
||||
@ -267,14 +267,14 @@ class BackupDeviceBox : Gtk.Box{
|
||||
|
||||
(cell as Gtk.CellRendererText).sensitive = (dev.type != "disk");
|
||||
});
|
||||
|
||||
|
||||
// buffer
|
||||
|
||||
col = add_column_text(tv_devices, "", out cell_text);
|
||||
col.expand = true;
|
||||
|
||||
|
||||
/*// label
|
||||
|
||||
|
||||
col = add_column_text(tv_devices, _("Label"), out cell_text);
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
@ -285,8 +285,8 @@ class BackupDeviceBox : Gtk.Box{
|
||||
(cell as Gtk.CellRendererText).sensitive = (dev.type != "disk");
|
||||
});*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// events
|
||||
|
||||
tv_devices.row_activated.connect((path, column) => {
|
||||
@ -308,7 +308,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
store.foreach((model, path, iter) => {
|
||||
Device dev;
|
||||
store.get (iter, 0, out dev);
|
||||
|
||||
|
||||
if ((App.repo.device != null) && (App.repo.device.uuid == dev.uuid)){
|
||||
store.set (iter, 3, true);
|
||||
//tv_devices.get_selection().select_iter(iter);
|
||||
@ -323,12 +323,12 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void init_infobar_location(){
|
||||
|
||||
|
||||
var infobar = new Gtk.InfoBar();
|
||||
infobar.no_show_all = true;
|
||||
add(infobar);
|
||||
infobar_location = infobar;
|
||||
|
||||
|
||||
var content = (Gtk.Box) infobar.get_content_area();
|
||||
var label = add_label(content, "");
|
||||
lbl_infobar_location = label;
|
||||
@ -340,7 +340,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scrolled.set_size_request(-1, 100);
|
||||
this.add(scrolled);
|
||||
|
||||
|
||||
label = new Gtk.Label("");
|
||||
label.set_use_markup(true);
|
||||
label.xalign = (float) 0.0;
|
||||
@ -354,13 +354,13 @@ class BackupDeviceBox : Gtk.Box{
|
||||
private void try_change_device(Device dev){
|
||||
|
||||
log_debug("try_change_device: %s".printf(dev.device));
|
||||
|
||||
|
||||
if (dev.type == "disk"){
|
||||
|
||||
bool found_child = false;
|
||||
|
||||
if ((App.btrfs_mode && (dev.fstype == "btrfs")) || (!App.btrfs_mode && dev.has_linux_filesystem())){
|
||||
|
||||
|
||||
change_backup_device(dev);
|
||||
found_child = true;
|
||||
}
|
||||
@ -368,26 +368,26 @@ class BackupDeviceBox : Gtk.Box{
|
||||
if (!found_child){
|
||||
|
||||
// find first valid partition
|
||||
|
||||
|
||||
foreach (var child in dev.children){
|
||||
|
||||
|
||||
if ((App.btrfs_mode && (child.fstype == "btrfs")) || (!App.btrfs_mode && child.has_linux_filesystem())){
|
||||
|
||||
|
||||
change_backup_device(child);
|
||||
found_child = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found_child){
|
||||
|
||||
|
||||
string msg = _("Selected device does not have Linux partition");
|
||||
|
||||
|
||||
if (App.btrfs_mode){
|
||||
msg = _("Selected device does not have BTRFS partition");
|
||||
}
|
||||
|
||||
|
||||
lbl_infobar_location.label = "<span weight=\"bold\">%s</span>".printf(msg);
|
||||
infobar_location.message_type = Gtk.MessageType.ERROR;
|
||||
infobar_location.no_show_all = false;
|
||||
@ -395,17 +395,17 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
}
|
||||
else if (dev.has_children()){
|
||||
|
||||
|
||||
// select the child instead of parent
|
||||
change_backup_device(dev.children[0]);
|
||||
}
|
||||
else if (!dev.has_children()){
|
||||
|
||||
|
||||
// select the device
|
||||
change_backup_device(dev);
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
// ask user to select
|
||||
lbl_infobar_location.label = "<span weight=\"bold\">%s</span>".printf(_("Select a partition on this disk"));
|
||||
infobar_location.message_type = Gtk.MessageType.ERROR;
|
||||
@ -415,7 +415,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void change_backup_device(Device pi){
|
||||
|
||||
|
||||
// return if device has not changed
|
||||
if ((App.repo.device != null) && (pi.uuid == App.repo.device.uuid)){ return; }
|
||||
|
||||
@ -428,20 +428,20 @@ class BackupDeviceBox : Gtk.Box{
|
||||
App.repo = new SnapshotRepo.from_device(pi, parent_window, App.btrfs_mode);
|
||||
|
||||
if (pi.fstype == "luks"){
|
||||
|
||||
|
||||
App.update_partitions();
|
||||
|
||||
var dev = Device.find_device_in_list(App.partitions, pi.uuid);
|
||||
|
||||
|
||||
if (dev.has_children()){
|
||||
|
||||
|
||||
log_debug("has children");
|
||||
|
||||
|
||||
if (dev.children[0].has_linux_filesystem()){
|
||||
|
||||
|
||||
log_debug("has linux filesystem: %s".printf(dev.children[0].fstype));
|
||||
log_msg("selecting child device: %s".printf(dev.children[0].device));
|
||||
|
||||
|
||||
App.repo = new SnapshotRepo.from_device(dev.children[0], parent_window, App.btrfs_mode);
|
||||
tv_devices_refresh();
|
||||
}
|
||||
@ -457,21 +457,21 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private bool check_backup_location(){
|
||||
|
||||
|
||||
bool ok = true;
|
||||
|
||||
App.repo.check_status();
|
||||
string message = App.repo.status_message;
|
||||
string details = App.repo.status_details;
|
||||
int status_code = App.repo.status_code;
|
||||
|
||||
|
||||
// TODO: call check on repo directly
|
||||
|
||||
|
||||
message = escape_html(message);
|
||||
details = escape_html(details);
|
||||
|
||||
|
||||
if (App.live_system()){
|
||||
|
||||
|
||||
switch (status_code){
|
||||
case SnapshotLocationStatus.NOT_SELECTED:
|
||||
lbl_infobar_location.label = "<span weight=\"bold\">%s</span>".printf(details);
|
||||
@ -480,7 +480,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
infobar_location.show_all();
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
|
||||
case SnapshotLocationStatus.NOT_AVAILABLE:
|
||||
lbl_infobar_location.label = "<span weight=\"bold\">%s</span>".printf(message);
|
||||
infobar_location.message_type = Gtk.MessageType.ERROR;
|
||||
@ -531,7 +531,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
infobar_location.show_all();
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
|
||||
case SnapshotLocationStatus.NOT_AVAILABLE:
|
||||
case SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE:
|
||||
case SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE:
|
||||
@ -568,12 +568,12 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void tv_devices_refresh(){
|
||||
|
||||
|
||||
App.update_partitions();
|
||||
|
||||
var model = new Gtk.TreeStore(4,
|
||||
@ -581,13 +581,13 @@ class BackupDeviceBox : Gtk.Box{
|
||||
typeof(string),
|
||||
typeof(string),
|
||||
typeof(bool));
|
||||
|
||||
|
||||
tv_devices.set_model (model);
|
||||
|
||||
TreeIter iter0;
|
||||
|
||||
foreach(var disk in App.partitions) {
|
||||
|
||||
|
||||
if (disk.type != "disk") { continue; }
|
||||
|
||||
model.append(out iter0, null);
|
||||
@ -624,15 +624,15 @@ class BackupDeviceBox : Gtk.Box{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (part.pkname == parent.kname) {
|
||||
|
||||
|
||||
TreeIter iter1;
|
||||
model.append(out iter1, iter0);
|
||||
model.set(iter1, 0, part, -1);
|
||||
model.set(iter1, 1, part.tooltip_text(), -1);
|
||||
model.set(iter1, 2, (part.fstype == "luks") ? "locked" : IconManager.ICON_HARDDRIVE, -1);
|
||||
|
||||
|
||||
if (parent.fstype == "luks"){
|
||||
// change parent's icon to unlocked
|
||||
model.set(iter0, 2, "unlocked", -1);
|
||||
@ -649,7 +649,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
}
|
||||
else if ((part.kname == parent.kname) && (part.type == "disk")
|
||||
&& part.has_linux_filesystem() && !part.has_children()){
|
||||
|
||||
|
||||
// partition-less disk with linux filesystem
|
||||
|
||||
// create a dummy partition
|
||||
@ -664,7 +664,7 @@ class BackupDeviceBox : Gtk.Box{
|
||||
model.set(iter1, 0, part2, -1);
|
||||
model.set(iter1, 1, part2.tooltip_text(), -1);
|
||||
model.set(iter1, 2, (part2.fstype == "luks") ? "locked" : IconManager.ICON_HARDDRIVE, -1);
|
||||
|
||||
|
||||
if ((App.repo.device != null) && (part2.uuid == App.repo.device.uuid)){
|
||||
model.set(iter1, 3, true, -1);
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ class BackupFinishBox : Gtk.Box{
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public BackupFinishBox (Gtk.Window _parent_window) {
|
||||
|
||||
|
||||
log_debug("BackupFinishBox: BackupFinishBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -56,7 +56,7 @@ class BackupFinishBox : Gtk.Box{
|
||||
public void update_message(bool success){
|
||||
|
||||
var txt = "";
|
||||
|
||||
|
||||
txt = _("Snapshot Created");
|
||||
|
||||
if (!success){
|
||||
@ -64,11 +64,11 @@ class BackupFinishBox : Gtk.Box{
|
||||
}
|
||||
|
||||
lbl_header.label = format_text(txt, true, false, true);
|
||||
|
||||
|
||||
var msg = "";
|
||||
|
||||
msg += _("Close window to exit") + "\n\n";
|
||||
|
||||
|
||||
lbl_message.label = msg;
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,11 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class BackupWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Notebook notebook;
|
||||
private Gtk.ButtonBox bbox_action;
|
||||
|
||||
|
||||
// tabs
|
||||
private EstimateBox estimate_box;
|
||||
private BackupDeviceBox backup_dev_box;
|
||||
@ -58,7 +58,7 @@ class BackupWindow : Gtk.Window{
|
||||
public BackupWindow() {
|
||||
|
||||
log_debug("BackupWindow: BackupWindow()");
|
||||
|
||||
|
||||
this.title = _("Create Snapshot");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -78,7 +78,7 @@ class BackupWindow : Gtk.Window{
|
||||
notebook = add_notebook(vbox_main, false, false);
|
||||
|
||||
Gtk.Label label;
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Estimate"));
|
||||
estimate_box = new EstimateBox(this);
|
||||
estimate_box.margin = 12;
|
||||
@ -107,7 +107,7 @@ class BackupWindow : Gtk.Window{
|
||||
|
||||
log_debug("BackupWindow: BackupWindow(): exit");
|
||||
}
|
||||
|
||||
|
||||
private bool init_delayed(){
|
||||
|
||||
if (tmr_init > 0){
|
||||
@ -119,48 +119,48 @@ class BackupWindow : Gtk.Window{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private bool on_delete_event(Gdk.EventAny event){
|
||||
|
||||
save_changes();
|
||||
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void save_changes(){
|
||||
|
||||
|
||||
App.cron_job_update();
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
vbox_main.add(hbox);
|
||||
|
||||
|
||||
var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
bbox.margin = 12;
|
||||
bbox.spacing = 6;
|
||||
bbox.hexpand = true;
|
||||
hbox.add(bbox);
|
||||
|
||||
|
||||
bbox_action = bbox;
|
||||
|
||||
#if GTK3_18
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
#endif
|
||||
|
||||
|
||||
Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// previous
|
||||
|
||||
|
||||
btn_prev = add_button(bbox, _("Previous"), "", size_group, null);
|
||||
|
||||
|
||||
btn_prev.clicked.connect(()=>{
|
||||
go_prev();
|
||||
});
|
||||
|
||||
// next
|
||||
|
||||
|
||||
btn_next = add_button(bbox, _("Next"), "", size_group, null);
|
||||
|
||||
btn_next.clicked.connect(()=>{
|
||||
@ -168,7 +168,7 @@ class BackupWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// close
|
||||
|
||||
|
||||
btn_close = add_button(bbox, _("Close"), "", size_group, null);
|
||||
|
||||
btn_close.clicked.connect(()=>{
|
||||
@ -177,14 +177,14 @@ class BackupWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// cancel
|
||||
|
||||
|
||||
btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null);
|
||||
|
||||
btn_cancel.clicked.connect(()=>{
|
||||
if (App.task != null){
|
||||
App.task.stop(AppStatus.CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
this.destroy(); // TODO: Show error page
|
||||
});
|
||||
|
||||
@ -192,18 +192,18 @@ class BackupWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private void action_buttons_set_no_show_all(bool val){
|
||||
|
||||
|
||||
btn_prev.no_show_all = val;
|
||||
btn_next.no_show_all = val;
|
||||
btn_close.no_show_all = val;
|
||||
btn_cancel.no_show_all = val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// navigation
|
||||
|
||||
private void go_first(){
|
||||
|
||||
|
||||
// set initial tab
|
||||
|
||||
if (App.btrfs_mode){
|
||||
@ -223,9 +223,9 @@ class BackupWindow : Gtk.Window{
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_prev(){
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.ESTIMATE:
|
||||
case Tabs.BACKUP_DEVICE:
|
||||
@ -233,16 +233,16 @@ class BackupWindow : Gtk.Window{
|
||||
// btn_previous is disabled for this page
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_next(){
|
||||
|
||||
|
||||
if (!validate_current_tab()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.ESTIMATE:
|
||||
notebook.page = Tabs.BACKUP_DEVICE;
|
||||
@ -257,7 +257,7 @@ class BackupWindow : Gtk.Window{
|
||||
destroy();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ class BackupWindow : Gtk.Window{
|
||||
// show/hide actions -----------------------------------
|
||||
|
||||
action_buttons_set_no_show_all(false);
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.ESTIMATE:
|
||||
case Tabs.BACKUP:
|
||||
@ -320,16 +320,16 @@ class BackupWindow : Gtk.Window{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private bool validate_current_tab(){
|
||||
|
||||
|
||||
if (notebook.page == Tabs.BACKUP_DEVICE){
|
||||
if (!App.repo.available() || !App.repo.has_space()){
|
||||
|
||||
|
||||
gtk_messagebox(App.repo.status_message,
|
||||
App.repo.status_details, this, true);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class BootOptionsBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.Box option_box;
|
||||
private Gtk.ComboBox cmb_grub_dev;
|
||||
|
||||
@ -45,7 +45,7 @@ class BootOptionsBox : Gtk.Box{
|
||||
public BootOptionsBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("BootOptionsBox: BootOptionsBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -68,7 +68,7 @@ class BootOptionsBox : Gtk.Box{
|
||||
//var label = add_label_header(this, _("Select Bootloader Options"), true);
|
||||
|
||||
add_chk_reinstall_grub();
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
hbox.margin_left = 12;
|
||||
add (hbox);
|
||||
@ -77,7 +77,7 @@ class BootOptionsBox : Gtk.Box{
|
||||
cmb_grub_dev = new ComboBox ();
|
||||
cmb_grub_dev.hexpand = true;
|
||||
hbox.add(cmb_grub_dev);
|
||||
|
||||
|
||||
var cell_text = new CellRendererText ();
|
||||
cell_text.text = "";
|
||||
cmb_grub_dev.pack_start(cell_text, false);
|
||||
@ -107,14 +107,14 @@ class BootOptionsBox : Gtk.Box{
|
||||
|
||||
hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
add (hbox);
|
||||
|
||||
|
||||
add_chk_update_initramfs(hbox);
|
||||
|
||||
add_chk_update_grub(hbox);
|
||||
}
|
||||
|
||||
private void add_chk_reinstall_grub(){
|
||||
|
||||
|
||||
var chk = new CheckButton.with_label(_("(Re)install GRUB2 on:"));
|
||||
chk.active = false;
|
||||
chk.set_tooltip_markup(_("Re-installs the GRUB2 bootloader on the selected device."));
|
||||
@ -130,7 +130,7 @@ class BootOptionsBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void add_chk_update_initramfs(Gtk.Box hbox){
|
||||
|
||||
|
||||
//chk_update_initramfs
|
||||
var chk = new CheckButton.with_label(_("Update initramfs"));
|
||||
chk.active = false;
|
||||
@ -145,7 +145,7 @@ class BootOptionsBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void add_chk_update_grub(Gtk.Box hbox){
|
||||
|
||||
|
||||
//chk_update_grub
|
||||
var chk = new CheckButton.with_label(_("Update GRUB menu"));
|
||||
chk.active = false;
|
||||
@ -160,9 +160,9 @@ class BootOptionsBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void save_grub_device_selection(){
|
||||
|
||||
|
||||
App.grub_device = "";
|
||||
|
||||
|
||||
if (App.reinstall_grub2){
|
||||
Device entry;
|
||||
TreeIter iter;
|
||||
@ -177,16 +177,16 @@ class BootOptionsBox : Gtk.Box{
|
||||
private void refresh_options(){
|
||||
|
||||
refresh_cmb_grub_dev();
|
||||
|
||||
|
||||
chk_reinstall_grub.active = App.reinstall_grub2;
|
||||
cmb_grub_dev.sensitive = chk_reinstall_grub.active;
|
||||
chk_update_initramfs.active = App.update_initramfs;
|
||||
chk_update_grub.active = App.update_grub;
|
||||
|
||||
|
||||
chk_reinstall_grub.sensitive = true;
|
||||
chk_update_initramfs.sensitive = true;
|
||||
chk_update_grub.sensitive = true;
|
||||
|
||||
|
||||
if (App.mirror_system){
|
||||
// bootloader must be re-installed
|
||||
chk_reinstall_grub.sensitive = false;
|
||||
@ -200,14 +200,14 @@ class BootOptionsBox : Gtk.Box{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void refresh_cmb_grub_dev(){
|
||||
|
||||
|
||||
var store = new Gtk.ListStore(2, typeof(Device), typeof(string));
|
||||
|
||||
TreeIter iter;
|
||||
foreach(Device dev in Device.get_block_devices_using_lsblk()) {
|
||||
|
||||
|
||||
// select disk and normal partitions, skip others (loop crypt rom lvm)
|
||||
if ((dev.type != "disk") && (dev.type != "part")){
|
||||
continue;
|
||||
@ -238,9 +238,9 @@ class BootOptionsBox : Gtk.Box{
|
||||
if ((cmb_grub_dev == null) || (cmb_grub_dev.model == null)){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
log_debug("BootOptionsBox: cmb_grub_dev_select_default()");
|
||||
|
||||
|
||||
if (App.grub_device.length == 0){
|
||||
cmb_grub_dev.active = -1;
|
||||
return;
|
||||
@ -250,14 +250,14 @@ class BootOptionsBox : Gtk.Box{
|
||||
var store = (Gtk.ListStore) cmb_grub_dev.model;
|
||||
int index = -1;
|
||||
int active = -1;
|
||||
|
||||
|
||||
for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) {
|
||||
|
||||
|
||||
Device dev_iter;
|
||||
store.get(iter, 0, out dev_iter);
|
||||
|
||||
|
||||
index++;
|
||||
|
||||
|
||||
if (dev_iter.device == App.grub_device){
|
||||
active = index;
|
||||
break;
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class BootOptionsWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.ButtonBox bbox_action;
|
||||
private BootOptionsBox boot_options_box;
|
||||
@ -45,7 +45,7 @@ class BootOptionsWindow : Gtk.Window{
|
||||
public BootOptionsWindow() {
|
||||
|
||||
log_debug("BootOptionsWindow: BootOptionsWindow()");
|
||||
|
||||
|
||||
this.title = _("Bootloader Options");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -62,7 +62,7 @@ class BootOptionsWindow : Gtk.Window{
|
||||
boot_options_box = new BootOptionsBox(this);
|
||||
boot_options_box.margin = 0;
|
||||
vbox_main.add(boot_options_box);
|
||||
|
||||
|
||||
create_actions();
|
||||
|
||||
show_all();
|
||||
@ -81,31 +81,31 @@ class BootOptionsWindow : Gtk.Window{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private bool on_delete_event(Gdk.EventAny event){
|
||||
|
||||
//save_changes();
|
||||
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void save_changes(){
|
||||
//App.cron_job_update();
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
|
||||
var hbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
hbox.margin = 0;
|
||||
hbox.margin_top = 24;
|
||||
vbox_main.add(hbox);
|
||||
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// close
|
||||
var btn_close = add_button(hbox, _("Close"), "", size_group, null);
|
||||
//hbox.set_child_packing(btn_close, false, true, 6, Gtk.PackType.END);
|
||||
|
||||
|
||||
btn_close.clicked.connect(()=>{
|
||||
save_changes();
|
||||
this.destroy();
|
||||
|
@ -48,22 +48,22 @@ class DeleteBox : Gtk.Box{
|
||||
public DeleteBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("DeleteBox: DeleteBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
|
||||
// header
|
||||
add_label_header(this, _("Deleting Snapshots..."), true);
|
||||
|
||||
var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
add (hbox_status);
|
||||
|
||||
|
||||
spinner = new Gtk.Spinner();
|
||||
spinner.active = true;
|
||||
hbox_status.add(spinner);
|
||||
|
||||
|
||||
//lbl_msg
|
||||
lbl_msg = add_label(hbox_status, _("Preparing..."));
|
||||
lbl_msg.hexpand = true;
|
||||
@ -97,9 +97,9 @@ class DeleteBox : Gtk.Box{
|
||||
}
|
||||
|
||||
if (App.btrfs_mode){
|
||||
|
||||
|
||||
while (App.thread_delete_running){
|
||||
|
||||
|
||||
lbl_msg.label = App.progress_text;
|
||||
gtk_do_events();
|
||||
sleep(200);
|
||||
@ -114,14 +114,14 @@ class DeleteBox : Gtk.Box{
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
|
||||
|
||||
int wait_interval_millis = 100;
|
||||
int status_line_counter = 0;
|
||||
int status_line_counter_default = 1000 / wait_interval_millis;
|
||||
string status_line = "";
|
||||
string last_status_line = "";
|
||||
int remaining_counter = 10;
|
||||
|
||||
|
||||
while (App.thread_delete_running){
|
||||
|
||||
status_line = escape_html(App.delete_file_task.status_line);
|
||||
@ -143,14 +143,14 @@ class DeleteBox : Gtk.Box{
|
||||
|
||||
// time remaining
|
||||
remaining_counter--;
|
||||
|
||||
|
||||
if (remaining_counter == 0){
|
||||
|
||||
|
||||
lbl_remaining.label = App.delete_file_task.stat_time_remaining + " " + _("remaining");
|
||||
|
||||
remaining_counter = 10;
|
||||
}
|
||||
|
||||
|
||||
if (fraction < 0.99){
|
||||
progressbar.fraction = fraction;
|
||||
|
||||
@ -170,7 +170,7 @@ class DeleteBox : Gtk.Box{
|
||||
XApp.set_window_progress(parent_window, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//parent_window.destroy();
|
||||
|
||||
return App.thread_delete_success;
|
||||
|
@ -38,9 +38,9 @@ class DeleteFinishBox : Gtk.Box{
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public DeleteFinishBox (Gtk.Window _parent_window) {
|
||||
|
||||
|
||||
log_debug("DeleteFinishBox: DeleteFinishBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -56,7 +56,7 @@ class DeleteFinishBox : Gtk.Box{
|
||||
public void update_message(bool success){
|
||||
|
||||
var txt = "";
|
||||
|
||||
|
||||
txt = _("Snapshot(s) Deleted");
|
||||
|
||||
if (!success){
|
||||
@ -64,12 +64,12 @@ class DeleteFinishBox : Gtk.Box{
|
||||
}
|
||||
|
||||
lbl_header.label = format_text(txt, true, false, true);
|
||||
|
||||
|
||||
var msg = "";
|
||||
|
||||
msg += "\n";
|
||||
msg += "<b>" + _("Close window to exit") + "</b>\n\n";
|
||||
|
||||
|
||||
lbl_message.label = msg;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class DeleteWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Notebook notebook;
|
||||
private Gtk.ButtonBox bbox_action;
|
||||
@ -54,11 +54,11 @@ class DeleteWindow : Gtk.Window{
|
||||
private int def_width = 500;
|
||||
private int def_height = 500;
|
||||
private bool success = false;
|
||||
|
||||
|
||||
public DeleteWindow() {
|
||||
|
||||
log_debug("DeleteWindow: DeleteWindow()");
|
||||
|
||||
|
||||
this.title = _("Delete Snapshots");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -68,7 +68,7 @@ class DeleteWindow : Gtk.Window{
|
||||
this.delete_event.connect(on_delete_event);
|
||||
|
||||
this.resize(def_width, def_height);
|
||||
|
||||
|
||||
// vbox_main
|
||||
vbox_main = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox_main.margin = 0;
|
||||
@ -78,23 +78,23 @@ class DeleteWindow : Gtk.Window{
|
||||
notebook = add_notebook(vbox_main, false, false);
|
||||
|
||||
// create tab
|
||||
|
||||
|
||||
var vbox_tab = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox_tab.margin = 12;
|
||||
|
||||
|
||||
add_label_header(vbox_tab, _("Select Snapshots"), true);
|
||||
|
||||
add_label(vbox_tab, _("Select the snapshots to be deleted"));
|
||||
|
||||
|
||||
var label = new Gtk.Label(_("Snapshots"));
|
||||
|
||||
|
||||
snapshot_list_box = new SnapshotListBox(this);
|
||||
snapshot_list_box.hide_context_menu();
|
||||
snapshot_list_box.margin = 0;
|
||||
vbox_tab.add(snapshot_list_box);
|
||||
|
||||
|
||||
notebook.append_page (vbox_tab, label);
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Delete"));
|
||||
delete_box = new DeleteBox(this);
|
||||
delete_box.margin = 12;
|
||||
@ -115,7 +115,7 @@ class DeleteWindow : Gtk.Window{
|
||||
|
||||
log_debug("DeleteWindow: DeleteWindow(): exit");
|
||||
}
|
||||
|
||||
|
||||
private bool init_delayed(){
|
||||
|
||||
if (tmr_init > 0){
|
||||
@ -132,36 +132,36 @@ class DeleteWindow : Gtk.Window{
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
vbox_main.add(hbox);
|
||||
|
||||
|
||||
var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
bbox.margin = 12;
|
||||
bbox.spacing = 6;
|
||||
bbox.hexpand = true;
|
||||
hbox.add(bbox);
|
||||
|
||||
|
||||
bbox_action = bbox;
|
||||
|
||||
#if GTK3_18
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
#endif
|
||||
|
||||
|
||||
Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// previous
|
||||
|
||||
|
||||
btn_prev = add_button(bbox, _("Previous"), "", size_group, null);
|
||||
|
||||
|
||||
btn_prev.clicked.connect(()=>{
|
||||
go_prev();
|
||||
});
|
||||
|
||||
// next
|
||||
|
||||
|
||||
btn_next = add_button(bbox, _("Next"), "", size_group, null);
|
||||
|
||||
btn_next.clicked.connect(()=>{
|
||||
@ -169,7 +169,7 @@ class DeleteWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// close
|
||||
|
||||
|
||||
btn_close = add_button(bbox, _("Close"), "", size_group, null);
|
||||
|
||||
btn_close.clicked.connect(()=>{
|
||||
@ -177,16 +177,16 @@ class DeleteWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// hide
|
||||
|
||||
|
||||
btn_hide = add_button(bbox, _("Hide"), "", size_group, null);
|
||||
btn_hide.set_tooltip_text(_("Hide this window (files will be deleted in background)"));
|
||||
|
||||
|
||||
btn_hide.clicked.connect(()=>{
|
||||
this.destroy();
|
||||
});
|
||||
|
||||
|
||||
// cancel
|
||||
|
||||
|
||||
btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null);
|
||||
|
||||
btn_cancel.clicked.connect(()=>{
|
||||
@ -196,7 +196,7 @@ class DeleteWindow : Gtk.Window{
|
||||
if (App.delete_file_task != null){
|
||||
App.delete_file_task.stop(AppStatus.CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
this.destroy(); // TODO: Show error page
|
||||
});
|
||||
|
||||
@ -206,20 +206,20 @@ class DeleteWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private void action_buttons_set_no_show_all(bool val){
|
||||
|
||||
|
||||
btn_prev.no_show_all = val;
|
||||
btn_next.no_show_all = val;
|
||||
btn_hide.no_show_all = val;
|
||||
btn_close.no_show_all = val;
|
||||
btn_cancel.no_show_all = val;
|
||||
}
|
||||
|
||||
|
||||
// navigation
|
||||
|
||||
private void go_first(){
|
||||
|
||||
|
||||
// set initial tab
|
||||
|
||||
|
||||
if ((App.delete_list.size == 0) && !App.thread_delete_running){
|
||||
notebook.page = Tabs.SNAPSHOT_LIST;
|
||||
}
|
||||
@ -229,40 +229,40 @@ class DeleteWindow : Gtk.Window{
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_prev(){
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.SNAPSHOT_LIST:
|
||||
case Tabs.DELETE:
|
||||
// btn_previous is disabled for this page
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_next(){
|
||||
|
||||
|
||||
if (!validate_current_tab()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.SNAPSHOT_LIST:
|
||||
App.delete_list = snapshot_list_box.selected_snapshots();
|
||||
notebook.page = Tabs.DELETE;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.DELETE:
|
||||
notebook.page = Tabs.DELETE_FINISH;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.DELETE_FINISH:
|
||||
destroy();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
@ -278,7 +278,7 @@ class DeleteWindow : Gtk.Window{
|
||||
// show/hide actions -----------------------------------
|
||||
|
||||
action_buttons_set_no_show_all(false);
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.DELETE:
|
||||
btn_prev.hide();
|
||||
@ -287,7 +287,7 @@ class DeleteWindow : Gtk.Window{
|
||||
btn_hide.show();
|
||||
btn_cancel.show();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.SNAPSHOT_LIST:
|
||||
btn_prev.show();
|
||||
btn_next.show();
|
||||
@ -298,7 +298,7 @@ class DeleteWindow : Gtk.Window{
|
||||
btn_next.sensitive = true;
|
||||
btn_close.sensitive = true;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.DELETE_FINISH:
|
||||
btn_prev.hide();
|
||||
btn_next.hide();
|
||||
@ -326,7 +326,7 @@ class DeleteWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private bool validate_current_tab(){
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.SNAPSHOT_LIST:
|
||||
var sel = snapshot_list_box.treeview.get_selection ();
|
||||
@ -340,7 +340,7 @@ class DeleteWindow : Gtk.Window{
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -37,31 +37,31 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class EstimateBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.ProgressBar progressbar;
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
|
||||
private bool thread_is_running = false;
|
||||
|
||||
public EstimateBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("EstimateBox: EstimateBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
|
||||
// header
|
||||
add_label_header(this, _("Estimating System Size..."), true);
|
||||
|
||||
var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
add (hbox_status);
|
||||
|
||||
|
||||
var spinner = new Gtk.Spinner();
|
||||
spinner.active = true;
|
||||
hbox_status.add(spinner);
|
||||
|
||||
|
||||
//lbl_msg
|
||||
var lbl_msg = add_label(hbox_status, _("Please wait..."));
|
||||
lbl_msg.halign = Align.START;
|
||||
@ -83,14 +83,14 @@ class EstimateBox : Gtk.Box{
|
||||
log_debug("EstimateBox: size > 0");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
progressbar.fraction = 0.0;
|
||||
|
||||
// start the estimation if not already running
|
||||
if (!App.thread_estimate_running){
|
||||
|
||||
log_debug("EstimateBox: thread started");
|
||||
|
||||
|
||||
try {
|
||||
thread_is_running = true;
|
||||
Thread.create<void> (estimate_system_size_thread, true);
|
||||
@ -103,16 +103,16 @@ class EstimateBox : Gtk.Box{
|
||||
|
||||
// wait for completion and increment progressbar
|
||||
while (thread_is_running){
|
||||
|
||||
|
||||
if (progressbar.fraction < 98.0){
|
||||
|
||||
|
||||
progressbar.fraction += 0.005;
|
||||
|
||||
#if XAPP
|
||||
XApp.set_window_progress(parent_window, (int)(progressbar.fraction * 100.0));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
gtk_do_events();
|
||||
sleep(100);
|
||||
}
|
||||
@ -123,7 +123,7 @@ class EstimateBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void estimate_system_size_thread(){
|
||||
|
||||
|
||||
App.estimate_system_size();
|
||||
log_debug("EstimateBox: thread finished");
|
||||
thread_is_running = false;
|
||||
|
@ -39,7 +39,7 @@ class ExcludeAppsBox : Gtk.Box{
|
||||
public ExcludeAppsBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("ExcludeAppsBox: ExcludeAppsBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -47,7 +47,7 @@ class ExcludeAppsBox : Gtk.Box{
|
||||
|
||||
var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
add(box);
|
||||
|
||||
|
||||
add_label_header(box, _("Exclude Application Settings"), true);
|
||||
|
||||
//add_label(this, _("Selected items will be excluded"));
|
||||
@ -86,7 +86,7 @@ class ExcludeAppsBox : Gtk.Box{
|
||||
var col = new TreeViewColumn();
|
||||
col.expand = true;
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
// margin
|
||||
var cell_text = new CellRendererText();
|
||||
cell_text.text = "";
|
||||
@ -109,20 +109,20 @@ class ExcludeAppsBox : Gtk.Box{
|
||||
Gtk.TreeIter iter;
|
||||
var store = (Gtk.ListStore) treeview.model;
|
||||
store.get_iter(out iter, tree_path);
|
||||
|
||||
|
||||
AppExcludeEntry entry;
|
||||
store.get(iter, 0, out entry);
|
||||
entry.enabled = !cell_toggle.active;
|
||||
|
||||
|
||||
store.set(iter, 1, !cell_toggle.active);
|
||||
});
|
||||
|
||||
// pattern
|
||||
cell_text = new CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
|
||||
|
||||
col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
|
||||
|
||||
AppExcludeEntry entry;
|
||||
model.get (iter, 0, out entry, -1);
|
||||
(cell as Gtk.CellRendererText).text = entry.name;
|
||||
@ -130,23 +130,23 @@ class ExcludeAppsBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void init_exclude_summary_link(Gtk.Box box){
|
||||
|
||||
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
var button = add_button(box, _("Summary"), "", size_group, null);
|
||||
button.clicked.connect(()=>{
|
||||
new ExcludeListSummaryWindow(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
public void refresh(){
|
||||
|
||||
|
||||
refresh_treeview();
|
||||
}
|
||||
|
||||
|
||||
public void refresh_treeview(){
|
||||
|
||||
|
||||
var model = new Gtk.ListStore(3, typeof(AppExcludeEntry), typeof(bool), typeof(string));
|
||||
treeview.model = model;
|
||||
|
||||
|
@ -33,16 +33,16 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class ExcludeBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.TreeView treeview;
|
||||
private Gtk.Window parent_window;
|
||||
private UsersBox users_box;
|
||||
private Gtk.Label lbl_message;
|
||||
|
||||
|
||||
public ExcludeBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("ExcludeBox: ExcludeBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -50,7 +50,7 @@ class ExcludeBox : Gtk.Box{
|
||||
|
||||
var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
add(box);
|
||||
|
||||
|
||||
add_label_header(box, _("Include / Exclude Patterns"), true);
|
||||
|
||||
var buffer = add_label(box, "");
|
||||
@ -62,19 +62,19 @@ class ExcludeBox : Gtk.Box{
|
||||
init_treeview();
|
||||
|
||||
init_actions();
|
||||
|
||||
|
||||
refresh_treeview();
|
||||
|
||||
log_debug("ExcludeBox: ExcludeBox(): exit");
|
||||
}
|
||||
|
||||
public void set_users_box(UsersBox _users_box){
|
||||
|
||||
|
||||
users_box = _users_box;
|
||||
}
|
||||
|
||||
private void init_treeview(){
|
||||
|
||||
|
||||
// treeview
|
||||
treeview = new TreeView();
|
||||
treeview.get_selection().mode = SelectionMode.MULTIPLE;
|
||||
@ -95,7 +95,7 @@ class ExcludeBox : Gtk.Box{
|
||||
var col = new TreeViewColumn();
|
||||
col.title = "+";
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
// radio_include
|
||||
var cell_radio = new Gtk.CellRendererToggle();
|
||||
cell_radio.xpad = 2;
|
||||
@ -104,24 +104,24 @@ class ExcludeBox : Gtk.Box{
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
col.set_attributes(cell_radio, "active", 2);
|
||||
|
||||
|
||||
cell_radio.toggled.connect((cell, path)=>{
|
||||
|
||||
log_debug("cell_include.toggled()");
|
||||
|
||||
|
||||
var model = (Gtk.ListStore) treeview.model;
|
||||
string pattern;
|
||||
TreeIter iter;
|
||||
|
||||
model.get_iter_from_string (out iter, path);
|
||||
model.get (iter, 0, out pattern);
|
||||
|
||||
|
||||
if (!pattern.has_prefix("+ ")){
|
||||
pattern = "+ %s".printf(pattern);
|
||||
}
|
||||
|
||||
treeview_update_item(ref iter, pattern);
|
||||
|
||||
|
||||
save_changes();
|
||||
});
|
||||
|
||||
@ -136,17 +136,17 @@ class ExcludeBox : Gtk.Box{
|
||||
cell_radio.radio = true;
|
||||
cell_radio.activatable = true;
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
|
||||
col.set_attributes(cell_radio, "active", 3);
|
||||
|
||||
cell_radio.toggled.connect((cell, path)=>{
|
||||
|
||||
log_debug("cell_exclude.toggled()");
|
||||
|
||||
|
||||
var model = (Gtk.ListStore) treeview.model;
|
||||
string pattern;
|
||||
TreeIter iter;
|
||||
|
||||
|
||||
model.get_iter_from_string (out iter, path);
|
||||
model.get (iter, 0, out pattern);
|
||||
|
||||
@ -157,15 +157,15 @@ class ExcludeBox : Gtk.Box{
|
||||
}
|
||||
|
||||
treeview_update_item(ref iter, pattern);
|
||||
|
||||
|
||||
save_changes();
|
||||
});
|
||||
|
||||
|
||||
// column
|
||||
col = new TreeViewColumn();
|
||||
col.title = _("Pattern");
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
// margin
|
||||
var cell_text = new CellRendererText ();
|
||||
cell_text.text = "";
|
||||
@ -179,7 +179,7 @@ class ExcludeBox : Gtk.Box{
|
||||
// pattern
|
||||
cell_text = new CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
|
||||
|
||||
col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{
|
||||
string pattern;
|
||||
model.get (iter, 0, out pattern, -1);
|
||||
@ -208,9 +208,9 @@ class ExcludeBox : Gtk.Box{
|
||||
pattern = pattern[2:pattern.length];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
model.set (iter, 0, pattern, -1);
|
||||
|
||||
|
||||
save_changes();
|
||||
});
|
||||
}
|
||||
@ -223,7 +223,7 @@ class ExcludeBox : Gtk.Box{
|
||||
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
var button = add_button(hbox, _("Add"), _("Add custom pattern"), size_group, null);
|
||||
|
||||
|
||||
button.clicked.connect(()=>{
|
||||
|
||||
string pattern = gtk_inputbox(
|
||||
@ -235,18 +235,18 @@ class ExcludeBox : Gtk.Box{
|
||||
treeview_add_item(treeview, pattern); // don't strip
|
||||
Main.first_snapshot_size = 0; //re-calculate
|
||||
}
|
||||
|
||||
|
||||
save_changes();
|
||||
});
|
||||
|
||||
|
||||
button = add_button(hbox, _("Add Files"), _("Add files"), size_group, null);
|
||||
|
||||
|
||||
button.clicked.connect(()=>{
|
||||
add_files_clicked();
|
||||
});
|
||||
|
||||
button = add_button(hbox, _("Add Folders"), _("Add directories"), size_group, null);
|
||||
|
||||
|
||||
button.clicked.connect(()=>{
|
||||
add_folder_clicked();
|
||||
});
|
||||
@ -270,11 +270,11 @@ class ExcludeBox : Gtk.Box{
|
||||
new ExcludeListSummaryWindow(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// actions
|
||||
|
||||
|
||||
private void remove_clicked(){
|
||||
|
||||
|
||||
var sel = treeview.get_selection();
|
||||
var store = (Gtk.ListStore) treeview.model;
|
||||
|
||||
@ -284,25 +284,25 @@ class ExcludeBox : Gtk.Box{
|
||||
gtk_messagebox(title, message, parent_window, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TreeIter iter;
|
||||
var iter_list = new Gee.ArrayList<TreeIter?>();
|
||||
|
||||
|
||||
bool iterExists = store.get_iter_first (out iter);
|
||||
while (iterExists) {
|
||||
if (sel.iter_is_selected (iter)){
|
||||
string pattern;
|
||||
store.get (iter, 0, out pattern);
|
||||
|
||||
|
||||
App.exclude_list_user.remove(pattern);
|
||||
iter_list.add(iter);
|
||||
|
||||
|
||||
log_debug("removed item: %s".printf(pattern));
|
||||
Main.first_snapshot_size = 0; //re-calculate
|
||||
}
|
||||
iterExists = store.iter_next (ref iter);
|
||||
}
|
||||
|
||||
|
||||
refresh_treeview();
|
||||
|
||||
save_changes();
|
||||
@ -344,17 +344,17 @@ class ExcludeBox : Gtk.Box{
|
||||
if (!pattern.has_suffix("/***")){
|
||||
pattern = "%s/***".printf(pattern);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
|
||||
|
||||
+ <dir>/*** will include the directory along with the contents
|
||||
+ <dir>/ will include only the directory without the contents
|
||||
|
||||
|
||||
<dir>/*** will exclude the directory along with the contents
|
||||
<dir>/ is same as exclude <dir>/***
|
||||
*/
|
||||
|
||||
|
||||
if (!App.exclude_list_user.contains(pattern)){
|
||||
App.exclude_list_user.add(pattern);
|
||||
treeview_add_item(treeview, pattern);
|
||||
@ -378,21 +378,21 @@ class ExcludeBox : Gtk.Box{
|
||||
foreach(string item in list){
|
||||
|
||||
string pattern = item;
|
||||
|
||||
|
||||
if (!pattern.has_suffix("/**")){
|
||||
pattern = "%s/**".printf(pattern);
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
|
||||
|
||||
+ <dir>/** will include the directory along with the contents
|
||||
+ <dir>/ will include only the directory without the contents
|
||||
|
||||
|
||||
<dir>/** will exclude the directory contents but include the empty directory
|
||||
<dir>/ will exclude the directory along with the contents
|
||||
*/
|
||||
|
||||
|
||||
if (!App.exclude_list_user.contains(pattern)){
|
||||
App.exclude_list_user.add(pattern);
|
||||
treeview_add_item(treeview, pattern);
|
||||
@ -407,17 +407,17 @@ class ExcludeBox : Gtk.Box{
|
||||
|
||||
save_changes();
|
||||
}
|
||||
|
||||
|
||||
private SList<string> browse_files(){
|
||||
|
||||
var list = new SList<string>();
|
||||
|
||||
|
||||
var dialog = new Gtk.FileChooserDialog(
|
||||
_("Select file(s)"), parent_window,
|
||||
Gtk.FileChooserAction.OPEN,
|
||||
"gtk-cancel", Gtk.ResponseType.CANCEL,
|
||||
"gtk-open", Gtk.ResponseType.ACCEPT);
|
||||
|
||||
|
||||
dialog.action = FileChooserAction.OPEN;
|
||||
dialog.set_transient_for(parent_window);
|
||||
dialog.local_only = true;
|
||||
@ -429,7 +429,7 @@ class ExcludeBox : Gtk.Box{
|
||||
if (resp != Gtk.ResponseType.CANCEL){
|
||||
list = dialog.get_filenames();
|
||||
}
|
||||
|
||||
|
||||
dialog.destroy();
|
||||
|
||||
return list;
|
||||
@ -438,13 +438,13 @@ class ExcludeBox : Gtk.Box{
|
||||
private SList<string> browse_folder(){
|
||||
|
||||
var list = new SList<string>();
|
||||
|
||||
|
||||
var dialog = new Gtk.FileChooserDialog(
|
||||
_("Select directory"), parent_window,
|
||||
Gtk.FileChooserAction.SELECT_FOLDER,
|
||||
"gtk-cancel", Gtk.ResponseType.CANCEL,
|
||||
"gtk-open", Gtk.ResponseType.ACCEPT);
|
||||
|
||||
|
||||
dialog.action = FileChooserAction.SELECT_FOLDER;
|
||||
dialog.local_only = true;
|
||||
dialog.set_transient_for(parent_window);
|
||||
@ -456,7 +456,7 @@ class ExcludeBox : Gtk.Box{
|
||||
if (resp != Gtk.ResponseType.CANCEL){
|
||||
list = dialog.get_filenames();
|
||||
}
|
||||
|
||||
|
||||
dialog.destroy();
|
||||
|
||||
return list;
|
||||
@ -465,7 +465,7 @@ class ExcludeBox : Gtk.Box{
|
||||
// helpers
|
||||
|
||||
public void refresh_treeview(){
|
||||
|
||||
|
||||
var model = new Gtk.ListStore(4, typeof(string), typeof(string), typeof(bool), typeof(bool));
|
||||
treeview.model = model;
|
||||
|
||||
@ -475,7 +475,7 @@ class ExcludeBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void treeview_add_item(Gtk.TreeView treeview, string pattern){
|
||||
|
||||
|
||||
log_debug("treeview_add_item(): %s".printf(pattern));
|
||||
|
||||
TreeIter iter;
|
||||
@ -494,7 +494,7 @@ class ExcludeBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void treeview_update_item(ref TreeIter iter, string pattern){
|
||||
|
||||
|
||||
log_debug("treeview_update_item(): %s".printf(pattern));
|
||||
|
||||
bool include = pattern.has_prefix("+ ");
|
||||
@ -507,7 +507,7 @@ class ExcludeBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void cell_exclude_text_edited(string path, string new_text) {
|
||||
|
||||
|
||||
string old_pattern;
|
||||
string new_pattern;
|
||||
|
||||
@ -540,10 +540,10 @@ class ExcludeBox : Gtk.Box{
|
||||
if (!App.exclude_list_user.contains(pattern)
|
||||
&& !App.exclude_list_default.contains(pattern)
|
||||
&& !App.exclude_list_home.contains(pattern)){
|
||||
|
||||
|
||||
App.exclude_list_user.add(pattern);
|
||||
}
|
||||
|
||||
|
||||
iterExists = store.iter_next(ref iter);
|
||||
}
|
||||
|
||||
|
@ -33,19 +33,19 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class ExcludeListSummaryWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Label lbl_list;
|
||||
private Gtk.Button btn_close;
|
||||
private bool for_restore = false;
|
||||
|
||||
|
||||
private int def_width = 500;
|
||||
private int def_height = 450;
|
||||
|
||||
public ExcludeListSummaryWindow(bool _for_restore) {
|
||||
|
||||
log_debug("ExcludeListSummaryWindow: ExcludeListSummaryWindow()");
|
||||
|
||||
|
||||
this.title = _("Exclude List Summary");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -53,7 +53,7 @@ class ExcludeListSummaryWindow : Gtk.Window{
|
||||
this.icon = IconManager.lookup("timeshift",16);
|
||||
|
||||
for_restore = _for_restore;
|
||||
|
||||
|
||||
// vbox_main
|
||||
vbox_main = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox_main.margin = 12;
|
||||
@ -66,20 +66,20 @@ class ExcludeListSummaryWindow : Gtk.Window{
|
||||
create_actions();
|
||||
|
||||
refresh();
|
||||
|
||||
|
||||
show_all();
|
||||
|
||||
log_debug("ExcludeListSummaryWindow: ExcludeListSummaryWindow(): exit");
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
vbox_main.add(hbox);
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// close
|
||||
|
||||
|
||||
var img = new Image.from_stock("gtk-ok", Gtk.IconSize.BUTTON);
|
||||
btn_close = add_button(hbox, _("OK"), "", size_group, img);
|
||||
|
||||
@ -91,21 +91,21 @@ class ExcludeListSummaryWindow : Gtk.Window{
|
||||
public void refresh(){
|
||||
|
||||
Gee.ArrayList<string> list;
|
||||
|
||||
|
||||
if (for_restore){
|
||||
list = App.create_exclude_list_for_restore();
|
||||
}
|
||||
else{
|
||||
list = App.create_exclude_list_for_backup();
|
||||
}
|
||||
|
||||
|
||||
var txt = "";
|
||||
foreach(var pattern in list){
|
||||
if (pattern.strip().length > 0){
|
||||
txt += "%s\n".printf(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lbl_list.label = txt;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class ExcludeMessageWindow : Gtk.Dialog{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Box hbox_action;
|
||||
|
||||
@ -52,7 +52,7 @@ public class ExcludeMessageWindow : Gtk.Dialog{
|
||||
public ExcludeMessageWindow () {
|
||||
|
||||
log_debug("ExcludeMessageWindow: ExcludeMessageWindow()");
|
||||
|
||||
|
||||
this.title = _("Excluded Directories");
|
||||
this.window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
this.set_destroy_with_parent (true);
|
||||
@ -153,14 +153,14 @@ public class ExcludeMessageWindow : Gtk.Dialog{
|
||||
}
|
||||
|
||||
private void cell_exclude_text_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
string pattern;
|
||||
model.get (iter, 0, out pattern, -1);
|
||||
(cell as Gtk.CellRendererText).text = pattern.has_prefix("+ ") ? pattern[2:pattern.length] : pattern;
|
||||
}
|
||||
|
||||
private void tv_exclude_add_item(string path){
|
||||
|
||||
|
||||
string icon_name = null;
|
||||
|
||||
TreeIter iter;
|
||||
@ -181,7 +181,7 @@ public class ExcludeMessageWindow : Gtk.Dialog{
|
||||
}
|
||||
|
||||
private void btn_ok_clicked(){
|
||||
|
||||
|
||||
this.response(Gtk.ResponseType.OK);
|
||||
return;
|
||||
}
|
||||
|
@ -33,23 +33,23 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class FinishBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.Label lbl_header;
|
||||
private Gtk.Label lbl_message;
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
private bool show_notes = true;
|
||||
|
||||
public FinishBox (Gtk.Window _parent_window, bool _show_notes) {
|
||||
|
||||
log_debug("FinishBox: FinishBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
show_notes = _show_notes;
|
||||
|
||||
|
||||
// header
|
||||
if (show_notes){
|
||||
lbl_header = add_label_header(this, _("Notes"), true);
|
||||
@ -69,7 +69,7 @@ class FinishBox : Gtk.Box{
|
||||
|
||||
var msg = "";
|
||||
string bullet = "• ";
|
||||
|
||||
|
||||
if (!show_notes){
|
||||
if (App.scheduled){
|
||||
msg += bullet + _("Scheduled snapshots are enabled. Snapshots will be created automatically for selected levels.") + "\n\n";
|
||||
@ -87,7 +87,7 @@ class FinishBox : Gtk.Box{
|
||||
else{
|
||||
msg += bullet + _("Restoring snapshots only replaces system files and settings. Non-hidden files and directories in user home directories will not be touched. This behaviour can be changed by adding a filter to include these files. Included files will be backed up when snapshot is created, and replaced when snapshot is restored.") + "\n\n";
|
||||
}
|
||||
|
||||
|
||||
if (App.btrfs_mode){
|
||||
msg += bullet + _("BTRFS snapshots are saved on the same disk from which it is created. If the system disk fails, snapshots will be lost along with the system. Save snapshots to an external non-system disk in RSYNC mode to guard against disk failures.") + "\n\n";
|
||||
}
|
||||
@ -96,7 +96,7 @@ class FinishBox : Gtk.Box{
|
||||
|
||||
msg += bullet + _("Saving snapshots to a non-system disk allows you to format and re-install the OS on the system disk without losing snapshots stored on it. You can even install another Linux distribution and later roll-back the previous distribution by restoring a snapshot.") + "\n\n";
|
||||
}
|
||||
|
||||
|
||||
msg += "\n";
|
||||
msg += "<b>" + _("Close window to exit") + "</b>\n\n";
|
||||
|
||||
|
@ -48,7 +48,7 @@ class MainWindow : Gtk.Window{
|
||||
private Gtk.Menu menu_extra;
|
||||
|
||||
private SnapshotListBox snapshot_list_box;
|
||||
|
||||
|
||||
//statusbar
|
||||
private Gtk.ScrolledWindow statusbar;
|
||||
private Gtk.Image img_shield;
|
||||
@ -60,7 +60,7 @@ class MainWindow : Gtk.Window{
|
||||
private Gtk.Label lbl_free_space_subnote;
|
||||
private Gtk.ScrolledWindow scrolled_snap_count;
|
||||
private Gtk.ScrolledWindow scrolled_free_space;
|
||||
|
||||
|
||||
//timers
|
||||
private uint tmr_init;
|
||||
private int def_width = 800;
|
||||
@ -71,7 +71,7 @@ class MainWindow : Gtk.Window{
|
||||
public MainWindow () {
|
||||
|
||||
log_debug("MainWindow: MainWindow()");
|
||||
|
||||
|
||||
this.title = AppName;
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -101,7 +101,7 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private bool init_delayed(){
|
||||
|
||||
|
||||
if (tmr_init > 0){
|
||||
Source.remove(tmr_init);
|
||||
tmr_init = 0;
|
||||
@ -123,12 +123,12 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
log_debug("MainWindow(): init_delayed(): exit");
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init_ui_toolbar(){
|
||||
|
||||
|
||||
//toolbar
|
||||
toolbar = new Gtk.Toolbar ();
|
||||
toolbar.toolbar_style = ToolbarStyle.BOTH;
|
||||
@ -163,7 +163,7 @@ class MainWindow : Gtk.Window{
|
||||
toolbar.add(btn_delete_snapshot);
|
||||
|
||||
btn_delete_snapshot.clicked.connect (delete_selected);
|
||||
|
||||
|
||||
//btn_browse_snapshot
|
||||
img = new Gtk.Image.from_icon_name("folder-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
|
||||
btn_browse_snapshot = new Gtk.ToolButton (img, null);
|
||||
@ -195,7 +195,7 @@ class MainWindow : Gtk.Window{
|
||||
btn_wizard.clicked.connect (btn_wizard_clicked);
|
||||
|
||||
// TODO: replace gtk icon names with desktop-neutral names
|
||||
|
||||
|
||||
//separator
|
||||
var separator = new Gtk.SeparatorToolItem();
|
||||
separator.set_draw (false);
|
||||
@ -216,13 +216,13 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private void init_ui_snapshot_list(){
|
||||
|
||||
|
||||
snapshot_list_box = new SnapshotListBox(this);
|
||||
snapshot_list_box.vexpand = true;
|
||||
vbox_main.add(snapshot_list_box);
|
||||
|
||||
snapshot_list_box.delete_selected.connect(delete_selected);
|
||||
|
||||
|
||||
snapshot_list_box.mark_selected.connect(mark_selected);
|
||||
|
||||
snapshot_list_box.browse_selected.connect(browse_selected);
|
||||
@ -237,7 +237,7 @@ class MainWindow : Gtk.Window{
|
||||
hbox_status.margin = 6;
|
||||
hbox_status.margin_top = 0;
|
||||
vbox_main.add(hbox_status);
|
||||
|
||||
|
||||
// scrolled
|
||||
var scrolled = new Gtk.ScrolledWindow(null, null);
|
||||
//scrolled.set_shadow_type (ShadowType.ETCHED_IN);
|
||||
@ -247,7 +247,7 @@ class MainWindow : Gtk.Window{
|
||||
scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
hbox_status.add(scrolled);
|
||||
statusbar = scrolled;
|
||||
|
||||
|
||||
// hbox_shield
|
||||
var box = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
box.margin = 6;
|
||||
@ -264,13 +264,13 @@ class MainWindow : Gtk.Window{
|
||||
var vbox = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
//vbox.margin_right = 6;
|
||||
box.add (vbox);
|
||||
|
||||
|
||||
//lbl_shield
|
||||
lbl_shield = add_label(vbox, "");
|
||||
//lbl_shield.margin_top = 6;
|
||||
lbl_shield.yalign = 0.5f;
|
||||
lbl_shield.hexpand = true;
|
||||
|
||||
|
||||
//lbl_shield_subnote
|
||||
lbl_shield_subnote = add_label(vbox, "");
|
||||
lbl_shield_subnote.yalign = 0.5f;
|
||||
@ -293,7 +293,7 @@ class MainWindow : Gtk.Window{
|
||||
scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scrolled.set_no_show_all(true);
|
||||
hbox_status.add (scrolled);
|
||||
|
||||
|
||||
vbox = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox.margin = 6;
|
||||
vbox.margin_left = 12;
|
||||
@ -306,7 +306,7 @@ class MainWindow : Gtk.Window{
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, true, true, 0);
|
||||
lbl_snap_count = label;
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Snapshots"));
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, false, false, 0);
|
||||
@ -316,7 +316,7 @@ class MainWindow : Gtk.Window{
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, false, false, 0);
|
||||
lbl_snap_count_subnote = label;
|
||||
|
||||
|
||||
// free space
|
||||
//vbox = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
//vbox.set_no_show_all(true);
|
||||
@ -329,7 +329,7 @@ class MainWindow : Gtk.Window{
|
||||
scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scrolled.set_no_show_all(true);
|
||||
hbox_status.add (scrolled);
|
||||
|
||||
|
||||
vbox = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox.margin = 6;
|
||||
vbox.margin_left = 12;
|
||||
@ -342,7 +342,7 @@ class MainWindow : Gtk.Window{
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, true, true, 0);
|
||||
lbl_free_space = label;
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Available"));
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, false, false, 0);
|
||||
@ -352,12 +352,12 @@ class MainWindow : Gtk.Window{
|
||||
label.justify = Gtk.Justification.CENTER;
|
||||
vbox.pack_start(label, false, false, 0);
|
||||
lbl_free_space_subnote = label;
|
||||
|
||||
|
||||
// TODO: medium: add a refresh button for device when device is offline
|
||||
|
||||
// TODO: low: refresh device list automatically when a device is plugged in
|
||||
}
|
||||
|
||||
|
||||
private bool menu_extra_popup(Gdk.EventButton? event){
|
||||
|
||||
menu_extra = new Gtk.Menu();
|
||||
@ -381,9 +381,9 @@ class MainWindow : Gtk.Window{
|
||||
menu_item = create_menu_item(_("About"), "", "", 16);
|
||||
menu_extra.append(menu_item);
|
||||
menu_item.activate.connect(btn_about_clicked);
|
||||
|
||||
|
||||
menu_extra.show_all();
|
||||
|
||||
|
||||
if (event != null) {
|
||||
menu_extra.popup (null, null, null, event.button, event.time);
|
||||
}
|
||||
@ -397,9 +397,9 @@ class MainWindow : Gtk.Window{
|
||||
private Gtk.MenuItem create_menu_item(
|
||||
string label_text, string icon_name_stock, string icon_name_custom,
|
||||
int icon_size, string tooltip_text = ""){
|
||||
|
||||
|
||||
var menu_item = new Gtk.MenuItem();
|
||||
|
||||
|
||||
var box = new Gtk.Box(Orientation.HORIZONTAL, 3);
|
||||
menu_item.add(box);
|
||||
|
||||
@ -411,17 +411,17 @@ class MainWindow : Gtk.Window{
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
|
||||
private Gtk.MenuItem create_menu_item_separator(){
|
||||
|
||||
|
||||
var menu_item = new Gtk.MenuItem();
|
||||
menu_item.sensitive = false;
|
||||
|
||||
|
||||
var box = new Gtk.Box(Orientation.HORIZONTAL, 3);
|
||||
menu_item.add(box);
|
||||
|
||||
box.add(new Gtk.Separator(Gtk.Orientation.HORIZONTAL));
|
||||
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
@ -433,7 +433,7 @@ class MainWindow : Gtk.Window{
|
||||
|
||||
snapshot_list_box.refresh();
|
||||
update_statusbar();
|
||||
|
||||
|
||||
ui_sensitive(true);
|
||||
|
||||
return false;
|
||||
@ -461,20 +461,20 @@ class MainWindow : Gtk.Window{
|
||||
// check backup device -------------------------------
|
||||
|
||||
if (!App.live_system()){
|
||||
|
||||
|
||||
if (!App.repo.available() || !App.repo.has_space()){
|
||||
|
||||
var title = App.repo.status_message;
|
||||
|
||||
|
||||
var msg = _("Select another device?");
|
||||
|
||||
|
||||
var type = Gtk.MessageType.ERROR;
|
||||
var buttons_type = Gtk.ButtonsType.YES_NO;
|
||||
|
||||
|
||||
var dlg = new CustomMessageDialog(title, msg, type, this, buttons_type);
|
||||
var response = dlg.run();
|
||||
dlg.destroy();
|
||||
|
||||
|
||||
if (response == Gtk.ResponseType.YES){
|
||||
this.delete_event.connect(on_delete_event); // reconnect this handler
|
||||
btn_wizard_clicked(); // open wizard
|
||||
@ -490,15 +490,15 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
// context menu
|
||||
|
||||
|
||||
public void create_snapshot(){
|
||||
|
||||
if (check_if_deletion_running()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ui_sensitive(false);
|
||||
|
||||
|
||||
// check root device --------------
|
||||
|
||||
if (App.btrfs_mode && (App.check_btrfs_layout_system(this) == false)){
|
||||
@ -526,7 +526,7 @@ class MainWindow : Gtk.Window{
|
||||
public void delete_selected(){
|
||||
|
||||
log_debug("main window: delete_selected()");
|
||||
|
||||
|
||||
// check snapshot device -----------
|
||||
|
||||
if (!App.repo.available()){
|
||||
@ -554,7 +554,7 @@ class MainWindow : Gtk.Window{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get selected snapshots
|
||||
|
||||
if (!App.thread_delete_running){
|
||||
@ -579,7 +579,7 @@ class MainWindow : Gtk.Window{
|
||||
// run wizard window ------------------
|
||||
|
||||
ui_sensitive(false);
|
||||
|
||||
|
||||
var win = new DeleteWindow();
|
||||
win.set_transient_for(this);
|
||||
win.destroy.connect(()=>{
|
||||
@ -589,21 +589,21 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
public void mark_selected(){
|
||||
|
||||
|
||||
TreeIter iter;
|
||||
bool is_success = true;
|
||||
|
||||
// check selected count ----------------
|
||||
|
||||
var sel = snapshot_list_box.treeview.get_selection();
|
||||
|
||||
|
||||
if (sel.count_selected_rows() == 0){
|
||||
|
||||
|
||||
gtk_messagebox(
|
||||
_("No Snapshots Selected"),
|
||||
_("Select the snapshots to mark for deletion"),
|
||||
this, false);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -612,11 +612,11 @@ class MainWindow : Gtk.Window{
|
||||
var store = (Gtk.ListStore) snapshot_list_box.treeview.model;
|
||||
bool iterExists = store.get_iter_first (out iter);
|
||||
bool marked = false;
|
||||
|
||||
|
||||
while (iterExists && is_success) {
|
||||
|
||||
|
||||
if (sel.iter_is_selected (iter)){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
store.get (iter, 0, out bak);
|
||||
// mark for deletion
|
||||
@ -640,13 +640,13 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
public void browse_selected(){
|
||||
|
||||
|
||||
var sel = snapshot_list_box.treeview.get_selection ();
|
||||
|
||||
|
||||
if (sel.count_selected_rows() == 0){
|
||||
|
||||
|
||||
var f = File.new_for_path(App.repo.snapshots_path);
|
||||
|
||||
|
||||
if (f.query_exists()){
|
||||
exo_open_folder(App.repo.snapshots_path);
|
||||
}
|
||||
@ -660,10 +660,10 @@ class MainWindow : Gtk.Window{
|
||||
var store = (Gtk.ListStore) snapshot_list_box.treeview.model;
|
||||
|
||||
bool iterExists = store.get_iter_first (out iter);
|
||||
|
||||
|
||||
while (iterExists) {
|
||||
if (sel.iter_is_selected (iter)){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
store.get (iter, 0, out bak);
|
||||
|
||||
@ -680,9 +680,9 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
public void view_snapshot_log(bool view_restore_log){
|
||||
|
||||
|
||||
var sel = snapshot_list_box.treeview.get_selection ();
|
||||
|
||||
|
||||
if (sel.count_selected_rows() == 0){
|
||||
gtk_messagebox(
|
||||
_("Select Snapshot"),
|
||||
@ -695,11 +695,11 @@ class MainWindow : Gtk.Window{
|
||||
var store = (Gtk.ListStore) snapshot_list_box.treeview.model;
|
||||
|
||||
bool iterExists = store.get_iter_first (out iter);
|
||||
|
||||
|
||||
while (iterExists) {
|
||||
|
||||
|
||||
if (sel.iter_is_selected (iter)){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
store.get (iter, 0, out bak);
|
||||
|
||||
@ -711,7 +711,7 @@ class MainWindow : Gtk.Window{
|
||||
if (file_exists(log_file_name) || file_exists(log_file_name + "-changes")){
|
||||
|
||||
this.hide();
|
||||
|
||||
|
||||
var win = new RsyncLogWindow(log_file_name);
|
||||
win.set_transient_for(this);
|
||||
win.destroy.connect(()=>{
|
||||
@ -730,17 +730,17 @@ class MainWindow : Gtk.Window{
|
||||
if (check_if_deletion_running()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
App.mirror_system = false;
|
||||
restore();
|
||||
}
|
||||
|
||||
private void btn_clone_clicked(){
|
||||
|
||||
|
||||
if (check_if_deletion_running()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
App.mirror_system = true;
|
||||
restore();
|
||||
}
|
||||
@ -750,20 +750,20 @@ class MainWindow : Gtk.Window{
|
||||
if (App.thread_delete_running){
|
||||
|
||||
ui_sensitive(true);
|
||||
|
||||
|
||||
gtk_messagebox(
|
||||
_("Snapshot deletion in progress..."),
|
||||
_("Please wait for snapshots to be deleted."), this, true);
|
||||
|
||||
|
||||
ui_sensitive(false);
|
||||
|
||||
|
||||
var win = new DeleteWindow();
|
||||
win.set_transient_for(this);
|
||||
win.destroy.connect(()=>{
|
||||
refresh_all();
|
||||
ui_sensitive(true);
|
||||
});
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -772,7 +772,7 @@ class MainWindow : Gtk.Window{
|
||||
|
||||
|
||||
private void restore(){
|
||||
|
||||
|
||||
TreeIter iter;
|
||||
TreeSelection sel;
|
||||
|
||||
@ -781,7 +781,7 @@ class MainWindow : Gtk.Window{
|
||||
//check if single snapshot is selected -------------
|
||||
|
||||
sel = snapshot_list_box.treeview.get_selection();
|
||||
|
||||
|
||||
if (sel.count_selected_rows() == 0){
|
||||
gtk_messagebox(
|
||||
_("No snapshots selected"),
|
||||
@ -796,14 +796,14 @@ class MainWindow : Gtk.Window{
|
||||
this, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//get selected snapshot ------------------
|
||||
|
||||
Snapshot snapshot_to_restore = null;
|
||||
|
||||
var store = (Gtk.ListStore) snapshot_list_box.treeview.model;
|
||||
bool iterExists = store.get_iter_first (out iter);
|
||||
|
||||
|
||||
while (iterExists) {
|
||||
if (sel.iter_is_selected (iter)){
|
||||
store.get (iter, 0, out snapshot_to_restore);
|
||||
@ -813,7 +813,7 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
if ((snapshot_to_restore != null) && (snapshot_to_restore.marked_for_deletion)){
|
||||
|
||||
|
||||
gtk_messagebox(
|
||||
_("Invalid snapshot"),
|
||||
_("Selected snapshot is marked for deletion and cannot be restored"),
|
||||
@ -828,7 +828,7 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
App.init_mount_list();
|
||||
|
||||
|
||||
//show restore window -----------------
|
||||
|
||||
var window = new RestoreWindow();
|
||||
@ -845,14 +845,14 @@ class MainWindow : Gtk.Window{
|
||||
private void btn_settings_clicked(){
|
||||
|
||||
log_debug("MainWindow: btn_settings_clicked()");
|
||||
|
||||
|
||||
btn_settings.sensitive = false;
|
||||
btn_wizard.sensitive = false;
|
||||
|
||||
this.hide();
|
||||
|
||||
bool btrfs_mode_prev = App.btrfs_mode;
|
||||
|
||||
|
||||
var win = new SettingsWindow();
|
||||
win.set_transient_for(this);
|
||||
win.destroy.connect(()=>{
|
||||
@ -865,14 +865,14 @@ class MainWindow : Gtk.Window{
|
||||
private void btn_wizard_clicked(){
|
||||
|
||||
log_debug("MainWindow: btn_wizard_clicked()");
|
||||
|
||||
|
||||
btn_settings.sensitive = false;
|
||||
btn_wizard.sensitive = false;
|
||||
|
||||
this.hide();
|
||||
|
||||
|
||||
bool btrfs_mode_prev = App.btrfs_mode;
|
||||
|
||||
|
||||
var win = new SetupWizardWindow();
|
||||
win.set_transient_for(this);
|
||||
win.destroy.connect(()=>{
|
||||
@ -905,18 +905,18 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private void btn_view_app_logs_clicked(){
|
||||
|
||||
|
||||
exo_open_folder(App.log_dir);
|
||||
}
|
||||
|
||||
public void btn_donate_clicked(){
|
||||
|
||||
|
||||
var dialog = new DonationWindow(this);
|
||||
dialog.show_all();
|
||||
}
|
||||
|
||||
private void btn_about_clicked (){
|
||||
|
||||
|
||||
var dialog = new AboutWindow(this);
|
||||
dialog.set_transient_for (this);
|
||||
|
||||
@ -947,25 +947,25 @@ class MainWindow : Gtk.Window{
|
||||
//dialog.license = "";
|
||||
dialog.website = "https://teejeetech.com/";
|
||||
dialog.website_label = "https://teejeetech.com/";
|
||||
|
||||
|
||||
dialog.initialize();
|
||||
dialog.show_all();
|
||||
}
|
||||
|
||||
private void ui_sensitive(bool enable){
|
||||
|
||||
|
||||
toolbar.sensitive = enable;
|
||||
snapshot_list_box.treeview.sensitive = enable;
|
||||
gtk_set_busy(!enable, this);
|
||||
}
|
||||
|
||||
private void update_statusbar(){
|
||||
|
||||
|
||||
App.repo.check_status();
|
||||
string message = App.repo.status_message;
|
||||
string details = App.repo.status_details;
|
||||
int status_code = App.repo.status_code;
|
||||
|
||||
|
||||
DateTime? last_snapshot_date = null;
|
||||
DateTime? oldest_snapshot_date = null;
|
||||
|
||||
@ -991,7 +991,7 @@ class MainWindow : Gtk.Window{
|
||||
case SnapshotLocationStatus.NO_BTRFS_SYSTEM:
|
||||
set_shield_subnote(details);
|
||||
break;
|
||||
|
||||
|
||||
case SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE:
|
||||
case SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE:
|
||||
set_shield_subnote(_("Snapshots available for restore"));
|
||||
@ -1059,13 +1059,13 @@ class MainWindow : Gtk.Window{
|
||||
set_shield_subnote(_("Create snapshots manually or enable scheduled snapshots to protect your system"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
scrolled_snap_count.hide();
|
||||
scrolled_free_space.hide();
|
||||
|
||||
|
||||
switch (status_code){
|
||||
case SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE:
|
||||
case SnapshotLocationStatus.NO_SNAPSHOTS_HAS_SPACE:
|
||||
@ -1073,14 +1073,14 @@ class MainWindow : Gtk.Window{
|
||||
case SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE:
|
||||
scrolled_snap_count.no_show_all = false;
|
||||
scrolled_snap_count.show_all();
|
||||
|
||||
|
||||
lbl_snap_count.label = format_text_large("%0d".printf(App.repo.snapshots.size));
|
||||
string mode = App.btrfs_mode ? "btrfs" : "rsync";
|
||||
lbl_snap_count_subnote.label = format_text(mode, false, true, false);
|
||||
|
||||
|
||||
scrolled_free_space.no_show_all = false;
|
||||
scrolled_free_space.show_all();
|
||||
|
||||
|
||||
lbl_free_space.label = format_text_large("%s".printf(format_file_size(App.repo.device.free_bytes)));
|
||||
|
||||
string devname = "(??)";
|
||||
@ -1094,33 +1094,33 @@ class MainWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
// ui helpers --------
|
||||
|
||||
|
||||
private string format_text_large(string text){
|
||||
|
||||
|
||||
return "<span size='xx-large'><b>" + text + "</b></span>";
|
||||
}
|
||||
|
||||
|
||||
private void set_shield_label(
|
||||
string text, bool is_bold = true, bool is_italic = false, bool is_large = true){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(is_bold ? " weight=\"bold\"" : ""),
|
||||
(is_italic ? " style=\"italic\"" : ""),
|
||||
(is_large ? " size=\"x-large\"" : ""),
|
||||
escape_html(text));
|
||||
|
||||
|
||||
lbl_shield.label = msg;
|
||||
}
|
||||
|
||||
private void set_shield_subnote(
|
||||
string text, bool is_bold = false, bool is_italic = true, bool is_large = false){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(is_bold ? " weight=\"bold\"" : ""),
|
||||
(is_italic ? " style=\"italic\"" : ""),
|
||||
(is_large ? " size=\"x-large\"" : ""),
|
||||
escape_html(text));
|
||||
|
||||
|
||||
lbl_shield_subnote.label = msg;
|
||||
}
|
||||
}
|
||||
|
@ -33,34 +33,34 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class MiscBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
private bool restore_mode = false;
|
||||
|
||||
|
||||
//private Gtk.CheckButton chk_include_btrfs_home;
|
||||
//private Gtk.CheckButton chk_enable_qgroups;
|
||||
|
||||
|
||||
|
||||
|
||||
public MiscBox (Gtk.Window _parent_window, bool _restore_mode) {
|
||||
|
||||
log_debug("MiscBox: MiscBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
restore_mode = _restore_mode;
|
||||
|
||||
|
||||
var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
|
||||
this.add(vbox);
|
||||
|
||||
// ------------------------
|
||||
|
||||
|
||||
init_date_format_option(vbox);
|
||||
|
||||
refresh();
|
||||
|
||||
|
||||
log_debug("MiscBox: MiscBox(): exit");
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ class MiscBox : Gtk.Box{
|
||||
var entry = new Gtk.Entry();
|
||||
entry.hexpand = true;
|
||||
hbox.add(entry);
|
||||
|
||||
|
||||
var cell_pix = new Gtk.CellRendererPixbuf();
|
||||
combo.pack_start (cell_pix, false);
|
||||
|
||||
@ -91,13 +91,13 @@ class MiscBox : Gtk.Box{
|
||||
var now = new DateTime.local(2019, 8, 11, 20, 25, 43);
|
||||
|
||||
combo.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{
|
||||
|
||||
|
||||
string txt;
|
||||
model.get (iter, 0, out txt, -1);
|
||||
|
||||
(cell as Gtk.CellRendererText).text = (txt.length == 0) ? _("Custom") : now.format(txt);
|
||||
});
|
||||
|
||||
|
||||
// populate combo
|
||||
var model = new Gtk.ListStore(1, typeof(string));
|
||||
combo.model = model;
|
||||
@ -113,7 +113,7 @@ class MiscBox : Gtk.Box{
|
||||
"%Y %b %d, %I:%M %p", // 2019 Aug 11, 08:00 PM
|
||||
"%c" // Sunday, 11 August 2019 08:00:00 PM IST
|
||||
}){
|
||||
|
||||
|
||||
index++;
|
||||
model.append(out iter);
|
||||
model.set(iter, 0, fmt);
|
||||
@ -122,11 +122,11 @@ class MiscBox : Gtk.Box{
|
||||
active = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (active < 0){
|
||||
active = 0;
|
||||
active = 0;
|
||||
}
|
||||
|
||||
|
||||
combo.active = active;
|
||||
|
||||
combo.changed.connect((path) => {
|
||||
@ -134,7 +134,7 @@ class MiscBox : Gtk.Box{
|
||||
TreeIter iter_active;
|
||||
bool selected = combo.get_active_iter(out iter_active);
|
||||
if (!selected){ return; }
|
||||
|
||||
|
||||
TreeIter iter_combo;
|
||||
var store = (Gtk.ListStore) combo.model;
|
||||
|
||||
@ -145,9 +145,9 @@ class MiscBox : Gtk.Box{
|
||||
if (txt.length > 0){
|
||||
fmt = txt;
|
||||
}
|
||||
|
||||
|
||||
entry.text = fmt;
|
||||
|
||||
|
||||
entry.sensitive = (txt.length == 0);
|
||||
|
||||
App.date_format = fmt;
|
||||
@ -162,7 +162,7 @@ class MiscBox : Gtk.Box{
|
||||
log_debug("saved date_format: %s".printf(App.date_format));
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
show_all();
|
||||
|
||||
log_debug("MiscBox: init_date_format_option(): exit");
|
||||
|
@ -39,7 +39,7 @@ using TeeJee.Misc;
|
||||
class RestoreBox : Gtk.Box{
|
||||
|
||||
public Gtk.Label lbl_header;
|
||||
|
||||
|
||||
private Gtk.Spinner spinner;
|
||||
public Gtk.Label lbl_msg;
|
||||
public Gtk.Label lbl_status;
|
||||
@ -63,7 +63,7 @@ class RestoreBox : Gtk.Box{
|
||||
public RestoreBox(Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("RestoreBox: RestoreBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -79,11 +79,11 @@ class RestoreBox : Gtk.Box{
|
||||
|
||||
var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
add (hbox_status);
|
||||
|
||||
|
||||
spinner = new Gtk.Spinner();
|
||||
spinner.active = true;
|
||||
hbox_status.add(spinner);
|
||||
|
||||
|
||||
//lbl_msg
|
||||
lbl_msg = add_label(hbox_status, _("Preparing..."));
|
||||
lbl_msg.hexpand = true;
|
||||
@ -110,15 +110,15 @@ class RestoreBox : Gtk.Box{
|
||||
|
||||
var label = add_label(this, "");
|
||||
label.vexpand = true;
|
||||
|
||||
|
||||
// add count labels ---------------------------------
|
||||
|
||||
|
||||
Gtk.SizeGroup sg_label = null;
|
||||
Gtk.SizeGroup sg_value = null;
|
||||
|
||||
label = add_label(this, _("Files and directory counts:"), true);
|
||||
label.margin_bottom = 6;
|
||||
|
||||
|
||||
lbl_unchanged = add_count_label(this, _("No Change"), ref sg_label, ref sg_value);
|
||||
lbl_created = add_count_label(this, _("Created"), ref sg_label, ref sg_value);
|
||||
lbl_deleted = add_count_label(this, _("Deleted"), ref sg_label, ref sg_value);
|
||||
@ -126,7 +126,7 @@ class RestoreBox : Gtk.Box{
|
||||
|
||||
label = add_label(this, _("Changed items:"), true);
|
||||
label.margin_bottom = 6;
|
||||
|
||||
|
||||
lbl_checksum = add_count_label(this, _("Checksum"), ref sg_label, ref sg_value);
|
||||
lbl_size = add_count_label(this, _("Size"), ref sg_label, ref sg_value);
|
||||
lbl_timestamp = add_count_label(this, _("Timestamp"), ref sg_label, ref sg_value);
|
||||
@ -140,7 +140,7 @@ class RestoreBox : Gtk.Box{
|
||||
private Gtk.Label add_count_label(Gtk.Box box, string text,
|
||||
ref Gtk.SizeGroup? sg_label, ref Gtk.SizeGroup? sg_value,
|
||||
int add_margin_bottom = 0){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
box.add (hbox);
|
||||
|
||||
@ -178,7 +178,7 @@ class RestoreBox : Gtk.Box{
|
||||
public bool restore(){
|
||||
|
||||
log_debug("RestoreBox: restore()");
|
||||
|
||||
|
||||
if (App.restore_current_system && !App.dry_run){
|
||||
parent_window.hide();
|
||||
}
|
||||
@ -189,7 +189,7 @@ class RestoreBox : Gtk.Box{
|
||||
else{
|
||||
lbl_header.label = format_text(_("Restoring Snapshot..."), true, false, true);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
thread_is_running = true;
|
||||
Thread.create<void> (restore_thread, true);
|
||||
@ -205,20 +205,20 @@ class RestoreBox : Gtk.Box{
|
||||
string status_line = "";
|
||||
string last_status_line = "";
|
||||
int remaining_counter = 10;
|
||||
|
||||
|
||||
while (thread_is_running){
|
||||
|
||||
status_line = escape_html(App.task.status_line);
|
||||
|
||||
|
||||
if (status_line != last_status_line){
|
||||
|
||||
|
||||
lbl_status.label = status_line;
|
||||
last_status_line = status_line;
|
||||
status_line_counter = status_line_counter_default;
|
||||
}
|
||||
else{
|
||||
status_line_counter--;
|
||||
|
||||
|
||||
if (status_line_counter < 0){
|
||||
status_line_counter = status_line_counter_default;
|
||||
lbl_status.label = "";
|
||||
@ -231,16 +231,16 @@ class RestoreBox : Gtk.Box{
|
||||
|
||||
// time remaining
|
||||
remaining_counter--;
|
||||
|
||||
|
||||
if (remaining_counter == 0){
|
||||
|
||||
|
||||
lbl_remaining.label = App.task.stat_time_remaining + " " + _("remaining");
|
||||
|
||||
remaining_counter = 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fraction < 0.99){
|
||||
|
||||
|
||||
progressbar.fraction = fraction;
|
||||
|
||||
#if XAPP
|
||||
@ -270,7 +270,7 @@ class RestoreBox : Gtk.Box{
|
||||
#if XAPP
|
||||
XApp.set_window_progress(parent_window, 0);
|
||||
#endif
|
||||
|
||||
|
||||
if (App.restore_current_system && !App.dry_run){
|
||||
parent_window.show();
|
||||
}
|
||||
@ -279,9 +279,9 @@ class RestoreBox : Gtk.Box{
|
||||
|
||||
return (App.task.exit_code == 0);
|
||||
}
|
||||
|
||||
|
||||
private void restore_thread(){
|
||||
|
||||
|
||||
log_debug("RestoreBox: restore_thread()");
|
||||
App.restore_snapshot(parent_window);
|
||||
thread_is_running = false;
|
||||
|
@ -39,7 +39,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
private Gtk.Box option_box;
|
||||
private Gtk.Label lbl_header_subvol;
|
||||
private bool show_volume_name = false;
|
||||
|
||||
|
||||
private Gtk.SizeGroup sg_mount_point = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
private Gtk.SizeGroup sg_device = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
private Gtk.SizeGroup sg_mount_options = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
@ -49,7 +49,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
public RestoreDeviceBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("RestoreDeviceBox: RestoreDeviceBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -63,9 +63,9 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
// buffer
|
||||
var label = add_label(hbox, "");
|
||||
label.hexpand = true;
|
||||
|
||||
|
||||
// refresh device button
|
||||
|
||||
|
||||
Gtk.SizeGroup size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
var btn_refresh = add_button(hbox, _("Refresh"), "", size_group, null);
|
||||
btn_refresh.clicked.connect(()=>{
|
||||
@ -85,7 +85,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
// headings
|
||||
|
||||
|
||||
hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
hbox.margin_top = 12;
|
||||
add(hbox);
|
||||
@ -93,7 +93,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
label = add_label(hbox, _("Path") + " ", true, true);
|
||||
label.xalign = (float) 0.0;
|
||||
sg_mount_point.add_widget(label);
|
||||
|
||||
|
||||
label = add_label(hbox, _("Device") + " ", true, true);
|
||||
label.xalign = (float) 0.0;
|
||||
sg_device.add_widget(label);
|
||||
@ -104,23 +104,23 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
lbl_header_subvol = label;
|
||||
|
||||
// options
|
||||
|
||||
|
||||
option_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
|
||||
add(option_box);
|
||||
|
||||
// bootloader
|
||||
|
||||
|
||||
add_boot_options();
|
||||
|
||||
// infobar
|
||||
|
||||
|
||||
create_infobar_location();
|
||||
|
||||
log_debug("RestoreDeviceBox: RestoreDeviceBox(): exit");
|
||||
}
|
||||
|
||||
public void refresh(bool reset_device_selections = true){
|
||||
|
||||
|
||||
log_debug("RestoreDeviceBox: refresh()");
|
||||
App.update_partitions();
|
||||
create_device_selection_options(reset_device_selections);
|
||||
@ -129,7 +129,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void create_device_selection_options(bool reset_device_selections){
|
||||
|
||||
|
||||
if (reset_device_selections){
|
||||
App.init_mount_list();
|
||||
}
|
||||
@ -166,7 +166,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
|
||||
var label = add_label(box, entry.mount_point, true);
|
||||
sg_mount_point.add_widget(label);
|
||||
|
||||
|
||||
var combo = add_device_combo(box, entry);
|
||||
sg_device.add_widget(combo);
|
||||
|
||||
@ -202,7 +202,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
if (dev.type == "disk"){
|
||||
(cell as Gtk.CellRendererPixbuf).icon_name = IconManager.ICON_HARDDRIVE;
|
||||
}
|
||||
|
||||
|
||||
(cell as Gtk.CellRendererPixbuf).sensitive = (dev.type != "disk");
|
||||
(cell as Gtk.CellRendererPixbuf).visible = (dev.type == "disk");
|
||||
}
|
||||
@ -219,16 +219,16 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
bool selected = combo.get_active_iter (out iter);
|
||||
if (!selected) { return true; }
|
||||
combo.model.get (iter, 0, out dev, -1);
|
||||
|
||||
|
||||
tooltip.set_icon_from_icon_name(IconManager.ICON_HARDDRIVE, tooltip_size);
|
||||
|
||||
|
||||
if (dev != null){
|
||||
tooltip.set_markup(dev.tooltip_text());
|
||||
}
|
||||
else{
|
||||
tooltip.set_markup(_("Keep this mount path on the root filesystem"));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -244,11 +244,11 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
(cell as Gtk.CellRendererText).markup = _("Keep on Root Device");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// populate combo
|
||||
var model = new Gtk.ListStore(2, typeof(Device), typeof(MountEntry));
|
||||
combo.model = model;
|
||||
|
||||
|
||||
var active = -1;
|
||||
var index = -1;
|
||||
TreeIter iter;
|
||||
@ -259,7 +259,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
model.set (iter, 0, null);
|
||||
model.set (iter, 1, entry);
|
||||
}
|
||||
|
||||
|
||||
foreach(var dev in App.partitions){
|
||||
// skip disk and loop devices
|
||||
//if ((dev.type == "disk")||(dev.type == "loop")){
|
||||
@ -283,12 +283,12 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
continue; // skip parent partitions of unlocked volumes (luks)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
index++;
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, dev);
|
||||
model.set (iter, 1, entry);
|
||||
|
||||
|
||||
if (entry.device != null){
|
||||
if (dev.uuid == entry.device.uuid){
|
||||
active = index;
|
||||
@ -308,12 +308,12 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
combo.active = active;
|
||||
|
||||
|
||||
combo.changed.connect((path) => {
|
||||
|
||||
Device current_dev;
|
||||
MountEntry current_entry;
|
||||
|
||||
|
||||
TreeIter iter_active;
|
||||
bool selected = combo.get_active_iter (out iter_active);
|
||||
if (!selected){
|
||||
@ -328,7 +328,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
if (current_dev.is_encrypted_partition()){
|
||||
|
||||
log_debug("add_device_combo().changed: unlocking encrypted device..");
|
||||
|
||||
|
||||
string msg_out, msg_err;
|
||||
var luks_unlocked = Device.luks_unlock(
|
||||
current_dev, "", "", parent_window, out msg_out, out msg_err);
|
||||
@ -336,13 +336,13 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
if (luks_unlocked == null){
|
||||
|
||||
log_debug("add_device_combo().changed: failed to unlock");
|
||||
|
||||
|
||||
// reset the selection
|
||||
|
||||
|
||||
if (current_entry.mount_point == "/"){
|
||||
|
||||
// reset to default device
|
||||
|
||||
|
||||
index = -1;
|
||||
for (bool next = store.get_iter_first (out iter_combo); next;
|
||||
next = store.iter_next (ref iter_combo)) {
|
||||
@ -350,7 +350,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
Device dev_iter;
|
||||
store.get(iter_combo, 0, out dev_iter, -1);
|
||||
index++;
|
||||
|
||||
|
||||
if ((dev_iter != null) && (dev_iter.device == current_entry.device.device)){
|
||||
combo.active = index;
|
||||
}
|
||||
@ -359,15 +359,15 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
else{
|
||||
combo.active = 0; // keep on root device
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
else{
|
||||
|
||||
log_debug("add_device_combo().changed: unlocked");
|
||||
|
||||
|
||||
// update current entry
|
||||
|
||||
|
||||
if (current_entry.mount_point == "/"){
|
||||
App.dst_root = luks_unlocked;
|
||||
App.init_boot_options();
|
||||
@ -383,7 +383,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
current_entry.device = current_dev;
|
||||
|
||||
|
||||
if (current_entry.mount_point == "/"){
|
||||
App.init_boot_options();
|
||||
}
|
||||
@ -398,38 +398,38 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
var label = new Gtk.Label("");
|
||||
label.vexpand = true;
|
||||
add(label);
|
||||
|
||||
|
||||
var hbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
hbox.margin_bottom = 24;
|
||||
add(hbox);
|
||||
|
||||
var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// close
|
||||
|
||||
|
||||
//var img = new Image.from_stock("gtk-dialog-warning", Gtk.IconSize.BUTTON);
|
||||
var button = add_button(hbox, _("Bootloader Options (Advanced)"), "", size_group, null);
|
||||
button.set_size_request(300, 40);
|
||||
button.set_tooltip_text(_("[Advanced Users Only] Change these settings only if the restored system fails to boot."));
|
||||
var btn_boot_options = button;
|
||||
//hbox.set_child_packing(btn_boot_options, false, true, 6, Gtk.PackType.END);
|
||||
|
||||
|
||||
btn_boot_options.clicked.connect(()=>{
|
||||
var win = new BootOptionsWindow();
|
||||
win.set_transient_for(parent_window);
|
||||
//win.destroy.connect(()=>{
|
||||
|
||||
|
||||
//});;
|
||||
});
|
||||
}
|
||||
|
||||
private void create_infobar_location(){
|
||||
|
||||
|
||||
var infobar = new Gtk.InfoBar();
|
||||
infobar.no_show_all = true;
|
||||
add(infobar);
|
||||
infobar_location = infobar;
|
||||
|
||||
|
||||
var content = (Gtk.Box) infobar.get_content_area ();
|
||||
var label = add_label(content, "");
|
||||
lbl_infobar_location = label;
|
||||
@ -438,27 +438,27 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
public bool check_and_mount_devices(){
|
||||
|
||||
// check if we are restoring the current system
|
||||
|
||||
|
||||
if (App.dst_root == App.sys_root){
|
||||
return true; // all required devices are already mounted
|
||||
}
|
||||
|
||||
|
||||
// check if target device is selected for /
|
||||
|
||||
|
||||
foreach(var entry in App.mount_list){
|
||||
if ((entry.mount_point == "/") && (entry.device == null)){
|
||||
|
||||
|
||||
gtk_messagebox(
|
||||
_("Root device not selected"),
|
||||
_("Select the device for root file system (/)"),
|
||||
parent_window, true);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// verify that target device for / is not same as system in clone mode
|
||||
|
||||
|
||||
if (App.mirror_system){
|
||||
|
||||
foreach(var entry in App.mount_list){
|
||||
@ -473,14 +473,14 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
same = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (same){
|
||||
|
||||
|
||||
gtk_messagebox(
|
||||
_("Target device is same as system device"),
|
||||
_("Select another device for root file system (/)"),
|
||||
parent_window, true);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -489,7 +489,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
}
|
||||
|
||||
// check if /boot device is selected for luks partitions
|
||||
|
||||
|
||||
foreach(var entry in App.mount_list){
|
||||
if ((entry.mount_point == "/boot") && (entry.device == null)){
|
||||
|
||||
@ -517,7 +517,7 @@ class RestoreDeviceBox : Gtk.Box{
|
||||
// check BTRFS subvolume layout --------------
|
||||
|
||||
bool supported = App.check_btrfs_layout(App.dst_root, App.dst_home, false);
|
||||
|
||||
|
||||
if (!supported){
|
||||
var title = _("Unsupported Subvolume Layout")
|
||||
+ " (%s)".printf(App.dst_root.device);
|
||||
|
@ -33,25 +33,25 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class RestoreExcludeBox : Gtk.Box{
|
||||
|
||||
|
||||
//private Gtk.CheckButton chk_web;
|
||||
private Gtk.CheckButton chk_other;
|
||||
private Gtk.CheckButton chk_web;
|
||||
private Gtk.CheckButton chk_torrent;
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public RestoreExcludeBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("RestoreExcludeBox: RestoreExcludeBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
// app settings header --------------------------------
|
||||
|
||||
|
||||
var label = add_label_header(this, _("Exclude Application Settings"), true);
|
||||
|
||||
add_label(this, _("Select applications to exclude from restore"));
|
||||
@ -63,7 +63,7 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
chk.margin_top = 12;
|
||||
chk.margin_bottom = 0;
|
||||
chk_web = chk;
|
||||
|
||||
|
||||
chk.toggled.connect(()=>{
|
||||
foreach(var name in new string[]{
|
||||
"chromium", "google-chrome", "mozilla", "midori", "epiphany",
|
||||
@ -73,7 +73,7 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
label = add_label(
|
||||
this, _("Firefox, Chromium, Chrome, Opera, Epiphany, Midori"), false, true);
|
||||
label.margin_top = 0;
|
||||
@ -87,12 +87,12 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
label.set_tooltip_text(tt);
|
||||
|
||||
// torrent clients ----------------------------
|
||||
|
||||
|
||||
chk = add_checkbox(this, _("Bittorrent Clients") + " (%s)".printf(_("Recommended")));
|
||||
chk.active = true;
|
||||
chk.margin_bottom = 0;
|
||||
chk_torrent = chk;
|
||||
|
||||
|
||||
chk.toggled.connect(()=>{
|
||||
foreach(var name in new string[]{
|
||||
"deluge", "transmission" }){
|
||||
@ -101,7 +101,7 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
label = add_label(this, _("Deluge, Transmission"), false, true);
|
||||
label.margin_top = 0;
|
||||
label.margin_bottom = 6;
|
||||
@ -114,7 +114,7 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
label.set_tooltip_text(tt);
|
||||
|
||||
// all apps ----------------------------
|
||||
|
||||
|
||||
chk = add_checkbox(this, _("Other applications (next page)"));
|
||||
chk_other = chk;
|
||||
|
||||
@ -127,13 +127,13 @@ class RestoreExcludeBox : Gtk.Box{
|
||||
}
|
||||
|
||||
public void refresh(){
|
||||
|
||||
|
||||
chk_web.toggled();
|
||||
chk_torrent.toggled();
|
||||
}
|
||||
|
||||
public bool show_all_apps(){
|
||||
|
||||
|
||||
return chk_other.active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ class RestoreFinishBox : Gtk.Box{
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public RestoreFinishBox (Gtk.Window _parent_window) {
|
||||
|
||||
|
||||
log_debug("RestoreFinishBox: RestoreFinishBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -56,7 +56,7 @@ class RestoreFinishBox : Gtk.Box{
|
||||
public void update_message(bool success, string message_header, string message_body){
|
||||
|
||||
// header -----------------------------------------
|
||||
|
||||
|
||||
var txt = "";
|
||||
|
||||
if (message_header.length > 0){
|
||||
@ -70,7 +70,7 @@ class RestoreFinishBox : Gtk.Box{
|
||||
else{
|
||||
txt = _("Restore");
|
||||
}
|
||||
|
||||
|
||||
if (success){
|
||||
txt += " " + _("Completed");
|
||||
}
|
||||
@ -84,12 +84,12 @@ class RestoreFinishBox : Gtk.Box{
|
||||
// body ------------------------------------------------------
|
||||
|
||||
var msg = "";
|
||||
|
||||
|
||||
if (message_body.length > 0){
|
||||
msg = message_body;
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
string bullet = "• ";
|
||||
|
||||
if (App.btrfs_mode && App.restore_current_system){
|
||||
@ -105,7 +105,7 @@ class RestoreFinishBox : Gtk.Box{
|
||||
msg += "\n";
|
||||
msg += "<b>" + _("Close window to exit") + "</b>\n\n";
|
||||
}
|
||||
|
||||
|
||||
lbl_message.label = msg;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class RestoreSummaryBox : Gtk.Box{
|
||||
|
||||
|
||||
public Gtk.Label lbl_devices;
|
||||
public Gtk.Label lbl_reboot;
|
||||
public Gtk.Label lbl_disclaimer;
|
||||
@ -42,14 +42,14 @@ class RestoreSummaryBox : Gtk.Box{
|
||||
public RestoreSummaryBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("RestoreSummaryBox: RestoreSummaryBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
// devices
|
||||
|
||||
|
||||
add_label_header(this, _("Warning"), true);
|
||||
|
||||
lbl_devices = add_label(this, "", false, false, false);
|
||||
@ -58,11 +58,11 @@ class RestoreSummaryBox : Gtk.Box{
|
||||
|
||||
lbl_reboot = add_label(this, "", true, false, false);
|
||||
lbl_reboot.margin_bottom = 6;
|
||||
|
||||
|
||||
// disclaimer
|
||||
|
||||
|
||||
add_label_header(this, _("Disclaimer"), true);
|
||||
|
||||
|
||||
lbl_disclaimer = add_label(this, "", false, false, false);
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ class RestoreSummaryBox : Gtk.Box{
|
||||
}
|
||||
|
||||
public void refresh(){
|
||||
|
||||
|
||||
string msg_devices = "";
|
||||
string msg_reboot = "";
|
||||
string msg_disclaimer = "";
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class RestoreWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Notebook notebook;
|
||||
private Gtk.ButtonBox bbox_action;
|
||||
@ -60,12 +60,12 @@ class RestoreWindow : Gtk.Window{
|
||||
private int def_height = 500;
|
||||
private bool success = false;
|
||||
|
||||
public bool check_before_restore = true;
|
||||
|
||||
public bool check_before_restore = true;
|
||||
|
||||
public RestoreWindow() {
|
||||
|
||||
log_debug("RestoreWindow: RestoreWindow()");
|
||||
|
||||
|
||||
this.title = App.mirror_system ? _("Clone System") : _("Restore Snapshot");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -85,7 +85,7 @@ class RestoreWindow : Gtk.Window{
|
||||
notebook = add_notebook(vbox_main, false, false);
|
||||
|
||||
Gtk.Label label;
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Restore Device"));
|
||||
restore_device_box = new RestoreDeviceBox(this);
|
||||
restore_device_box.margin = 12;
|
||||
@ -95,7 +95,7 @@ class RestoreWindow : Gtk.Window{
|
||||
restore_exclude_box = new RestoreExcludeBox(this);
|
||||
restore_exclude_box.margin = 12;
|
||||
notebook.append_page (restore_exclude_box, label);
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Exclude Apps"));
|
||||
exclude_apps_box = new ExcludeAppsBox(this);
|
||||
exclude_apps_box.margin = 12;
|
||||
@ -142,7 +142,7 @@ class RestoreWindow : Gtk.Window{
|
||||
|
||||
log_debug("RestoreWindow: RestoreWindow(): exit");
|
||||
}
|
||||
|
||||
|
||||
private bool init_delayed(){
|
||||
|
||||
if (tmr_init > 0){
|
||||
@ -160,44 +160,44 @@ class RestoreWindow : Gtk.Window{
|
||||
private bool on_delete_event(Gdk.EventAny event){
|
||||
|
||||
save_changes();
|
||||
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void save_changes(){
|
||||
|
||||
|
||||
App.cron_job_update();
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
vbox_main.add(hbox);
|
||||
|
||||
|
||||
var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
bbox.margin = 12;
|
||||
bbox.spacing = 6;
|
||||
bbox.hexpand = true;
|
||||
hbox.add(bbox);
|
||||
|
||||
|
||||
bbox_action = bbox;
|
||||
|
||||
#if GTK3_18
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
#endif
|
||||
|
||||
Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// previous
|
||||
|
||||
|
||||
btn_prev = add_button(bbox, _("Previous"), "", size_group, null);
|
||||
|
||||
|
||||
btn_prev.clicked.connect(()=>{
|
||||
go_prev();
|
||||
});
|
||||
|
||||
// next
|
||||
|
||||
|
||||
btn_next = add_button(bbox, _("Next"), "", size_group, null);
|
||||
|
||||
btn_next.clicked.connect(()=>{
|
||||
@ -205,7 +205,7 @@ class RestoreWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// close
|
||||
|
||||
|
||||
btn_close = add_button(bbox, _("Cancel"), "", size_group, null);
|
||||
|
||||
btn_close.clicked.connect(()=>{
|
||||
@ -214,33 +214,33 @@ class RestoreWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// cancel
|
||||
|
||||
|
||||
btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null);
|
||||
|
||||
btn_cancel.clicked.connect(()=>{
|
||||
|
||||
if (!App.dry_run){
|
||||
|
||||
|
||||
var title = _("Cancel restore?");
|
||||
|
||||
|
||||
var msg = _("Cancelling the restore process will leave the target system in an inconsistent state. The system may fail to boot or you may run into various issues. After cancelling, you need to restore another snapshot, to bring the system to a consistent state. Click Yes to confirm.");
|
||||
|
||||
|
||||
var type = Gtk.MessageType.ERROR;
|
||||
var buttons_type = Gtk.ButtonsType.YES_NO;
|
||||
|
||||
|
||||
var dlg = new CustomMessageDialog(title, msg, type, this, buttons_type);
|
||||
var response = dlg.run();
|
||||
dlg.destroy();
|
||||
|
||||
|
||||
if (response != Gtk.ResponseType.YES){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (App.task != null){
|
||||
App.task.stop(AppStatus.CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
this.destroy(); // TODO: low: Show error page
|
||||
});
|
||||
|
||||
@ -250,23 +250,23 @@ class RestoreWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private void action_buttons_set_no_show_all(bool val){
|
||||
|
||||
|
||||
btn_prev.no_show_all = val;
|
||||
btn_next.no_show_all = val;
|
||||
btn_close.no_show_all = val;
|
||||
btn_cancel.no_show_all = val;
|
||||
}
|
||||
|
||||
|
||||
// navigation ----------------------------------------------------
|
||||
|
||||
private void go_first(){
|
||||
|
||||
|
||||
// set initial tab
|
||||
|
||||
if (App.btrfs_mode){
|
||||
|
||||
|
||||
if (App.snapshot_to_restore.subvolumes.has_key("@home")){
|
||||
|
||||
|
||||
notebook.page = Tabs.USERS;
|
||||
}
|
||||
else {
|
||||
@ -276,42 +276,42 @@ class RestoreWindow : Gtk.Window{
|
||||
else{
|
||||
notebook.page = Tabs.TARGET_DEVICE;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_prev(){
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.RESTORE_EXCLUDE:
|
||||
notebook.page = Tabs.TARGET_DEVICE;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.EXCLUDE_APPS:
|
||||
notebook.page = Tabs.RESTORE_EXCLUDE;
|
||||
//notebook.page = Tabs.TARGET_DEVICE;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.SUMMARY:
|
||||
notebook.page = Tabs.RESTORE_EXCLUDE; // go to parent (RESTORE_EXCLUDE)
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.TARGET_DEVICE:
|
||||
case Tabs.RESTORE:
|
||||
case Tabs.FINISH:
|
||||
// btn_previous is disabled for this page
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_next(){
|
||||
|
||||
|
||||
if (!validate_current_tab()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.TARGET_DEVICE:
|
||||
if (!App.btrfs_mode && check_before_restore){
|
||||
@ -321,20 +321,20 @@ class RestoreWindow : Gtk.Window{
|
||||
notebook.page = Tabs.SUMMARY;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/*case Tabs.RESTORE_EXCLUDE:
|
||||
if (restore_exclude_box.show_all_apps()){
|
||||
notebook.page = Tabs.EXCLUDE_APPS;
|
||||
}
|
||||
else{
|
||||
notebook.page = Tabs.SUMMARY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.EXCLUDE_APPS:
|
||||
notebook.page = Tabs.SUMMARY;
|
||||
break;*/
|
||||
|
||||
|
||||
case Tabs.CHECK:
|
||||
notebook.page = Tabs.SHOW_LOG;
|
||||
break;
|
||||
@ -350,18 +350,18 @@ class RestoreWindow : Gtk.Window{
|
||||
case Tabs.SUMMARY:
|
||||
notebook.page = Tabs.RESTORE;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.RESTORE:
|
||||
notebook.page = Tabs.FINISH;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.FINISH:
|
||||
destroy();
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_do_events();
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
@ -374,29 +374,29 @@ class RestoreWindow : Gtk.Window{
|
||||
// show/hide actions -----------------------------------
|
||||
|
||||
action_buttons_set_no_show_all(false);
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.RESTORE:
|
||||
|
||||
|
||||
btn_prev.hide();
|
||||
btn_next.hide();
|
||||
btn_close.hide();
|
||||
|
||||
|
||||
btn_cancel.show();
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.CHECK:
|
||||
|
||||
|
||||
btn_prev.hide();
|
||||
btn_next.hide();
|
||||
btn_close.hide();
|
||||
|
||||
|
||||
btn_cancel.show();
|
||||
btn_cancel.sensitive = true;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.TARGET_DEVICE:
|
||||
case Tabs.RESTORE_EXCLUDE:
|
||||
case Tabs.EXCLUDE_APPS:
|
||||
@ -408,7 +408,7 @@ class RestoreWindow : Gtk.Window{
|
||||
btn_next.show();
|
||||
btn_close.show();
|
||||
btn_cancel.hide();
|
||||
|
||||
|
||||
btn_prev.sensitive = false;
|
||||
btn_next.sensitive = true;
|
||||
btn_close.sensitive = true;
|
||||
@ -416,25 +416,25 @@ class RestoreWindow : Gtk.Window{
|
||||
break;
|
||||
|
||||
case Tabs.SHOW_LOG:
|
||||
|
||||
|
||||
btn_prev.show();
|
||||
btn_next.show();
|
||||
btn_close.show();
|
||||
btn_cancel.hide();
|
||||
|
||||
|
||||
btn_prev.sensitive = false;
|
||||
btn_next.sensitive = true;
|
||||
btn_close.sensitive = true;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.FINISH:
|
||||
|
||||
|
||||
btn_prev.show();
|
||||
btn_next.show();
|
||||
btn_close.show();
|
||||
btn_cancel.hide();
|
||||
|
||||
|
||||
btn_prev.sensitive = false;
|
||||
btn_next.sensitive = false;
|
||||
btn_close.sensitive = true;
|
||||
@ -443,28 +443,28 @@ class RestoreWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
gtk_do_events();
|
||||
|
||||
|
||||
// actions ---------------------------------------------------
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.TARGET_DEVICE:
|
||||
restore_device_box.refresh(false); // false: App.init_mount_list() will be called before this window is shown
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.RESTORE_EXCLUDE:
|
||||
restore_exclude_box.refresh();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.EXCLUDE_APPS:
|
||||
exclude_apps_box.refresh();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.CHECK:
|
||||
App.dry_run = true;
|
||||
success = check_box.restore();
|
||||
go_next();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.SHOW_LOG:
|
||||
if (file_exists(App.snapshot_to_restore.rsync_restore_log_file)){
|
||||
log_box.open_log(App.snapshot_to_restore.rsync_restore_log_file);
|
||||
@ -483,13 +483,13 @@ class RestoreWindow : Gtk.Window{
|
||||
case Tabs.SUMMARY:
|
||||
summary_box.refresh();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.RESTORE:
|
||||
App.dry_run = false;
|
||||
success = restore_box.restore();
|
||||
go_next();
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.FINISH:
|
||||
restore_finish_box.update_message(success,"","");
|
||||
btn_close.label = _("Close");
|
||||
@ -501,7 +501,7 @@ class RestoreWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
private bool validate_current_tab(){
|
||||
|
||||
|
||||
if (notebook.page == Tabs.TARGET_DEVICE){
|
||||
|
||||
bool ok = restore_device_box.check_and_mount_devices();
|
||||
|
@ -46,7 +46,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
|
||||
private Gtk.TreeViewColumn col_name;
|
||||
private Gtk.TreeViewColumn col_status;
|
||||
|
||||
|
||||
private string name_filter = "";
|
||||
private string status_filter = "";
|
||||
|
||||
@ -57,7 +57,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
public Gtk.Label lbl_status;
|
||||
public Gtk.Label lbl_remaining;
|
||||
public Gtk.ProgressBar progressbar;
|
||||
|
||||
|
||||
//private uint tmr_task = 0;
|
||||
private uint tmr_init = 0;
|
||||
private bool thread_is_running = false;
|
||||
@ -68,11 +68,11 @@ public class RsyncLogBox : Gtk.Box {
|
||||
private Gtk.Window window;
|
||||
|
||||
public RsyncLogBox(Gtk.Window _window) {
|
||||
|
||||
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
|
||||
this.margin = 6;
|
||||
|
||||
|
||||
log_debug("RsyncLogBox: RsyncLogBox()");
|
||||
|
||||
window = _window;
|
||||
@ -91,11 +91,11 @@ public class RsyncLogBox : Gtk.Box {
|
||||
create_progressbar();
|
||||
|
||||
create_filters();
|
||||
|
||||
|
||||
create_treeview();
|
||||
|
||||
cmb_filter.changed.connect(() => {
|
||||
|
||||
|
||||
status_filter = gtk_combobox_get_value(cmb_filter, 0, "");
|
||||
log_debug("combo_changed(): filter=%s".printf(status_filter));
|
||||
|
||||
@ -103,7 +103,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
|
||||
hbox_filter.sensitive = false;
|
||||
treeview.sensitive = false;
|
||||
|
||||
|
||||
log_debug("refilter(): start");
|
||||
treefilter.refilter();
|
||||
log_debug("refilter(): end");
|
||||
@ -138,7 +138,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
public bool init_delayed(){
|
||||
|
||||
log_debug("init_delayed()");
|
||||
|
||||
|
||||
if (tmr_init > 0){
|
||||
Source.remove(tmr_init);
|
||||
tmr_init = 0;
|
||||
@ -156,7 +156,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
//gtk_set_busy(false, window);
|
||||
|
||||
log_debug("init_delayed(): finish");
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -171,20 +171,20 @@ public class RsyncLogBox : Gtk.Box {
|
||||
}
|
||||
|
||||
while (thread_is_running){
|
||||
|
||||
|
||||
double fraction = (App.task.prg_count * 1.0) / App.task.prg_count_total;
|
||||
|
||||
|
||||
if (fraction < 0.99){
|
||||
progressbar.fraction = fraction;
|
||||
}
|
||||
|
||||
|
||||
lbl_msg.label = _("Read %'d of %'d lines...").printf(
|
||||
App.task.prg_count, App.task.prg_count_total);
|
||||
|
||||
|
||||
sleep(500);
|
||||
gtk_do_events();
|
||||
}
|
||||
|
||||
|
||||
lbl_msg.label = _("Populating list...");
|
||||
gtk_do_events();
|
||||
treeview_refresh();
|
||||
@ -198,9 +198,9 @@ public class RsyncLogBox : Gtk.Box {
|
||||
hbox_filter.no_show_all = false;
|
||||
hbox_filter.show_all();
|
||||
}
|
||||
|
||||
|
||||
private void parse_log_file_thread(){
|
||||
|
||||
|
||||
App.task = new RsyncTask();
|
||||
loglist = App.task.parse_log(rsync_log_file);
|
||||
thread_is_running = false;
|
||||
@ -211,23 +211,23 @@ public class RsyncLogBox : Gtk.Box {
|
||||
return thread_is_running;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create ui -----------------------------------------
|
||||
|
||||
private void create_progressbar(){
|
||||
|
||||
|
||||
vbox_progress = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
this.add(vbox_progress);
|
||||
|
||||
|
||||
lbl_header_progress = add_label_header(vbox_progress, _("Parsing log file..."), true);
|
||||
|
||||
|
||||
var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
vbox_progress.add(hbox_status);
|
||||
|
||||
|
||||
spinner = new Gtk.Spinner();
|
||||
spinner.active = true;
|
||||
hbox_status.add(spinner);
|
||||
|
||||
|
||||
//lbl_msg
|
||||
lbl_msg = add_label(hbox_status, _("Preparing..."));
|
||||
lbl_msg.hexpand = true;
|
||||
@ -244,14 +244,14 @@ public class RsyncLogBox : Gtk.Box {
|
||||
// create filters -------------------------------------------
|
||||
|
||||
private void create_filters(){
|
||||
|
||||
|
||||
log_debug("create_filters()");
|
||||
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
hbox.no_show_all = true;
|
||||
this.add(hbox);
|
||||
hbox_filter = hbox;
|
||||
|
||||
|
||||
//add_label(hbox, _("Filter:"));
|
||||
|
||||
add_search_entry(hbox);
|
||||
@ -262,10 +262,10 @@ public class RsyncLogBox : Gtk.Box {
|
||||
|
||||
var label = add_label(hbox, "");
|
||||
label.hexpand = true;
|
||||
|
||||
|
||||
var button = new Gtk.Button.with_label(_("Close"));
|
||||
hbox.add(button);
|
||||
|
||||
|
||||
button.clicked.connect(()=>{
|
||||
window.destroy();
|
||||
});
|
||||
@ -275,7 +275,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
_("Exclude Selected"),
|
||||
_("Exclude selected items from future snapshots (careful!)"),
|
||||
ref size_group, null);
|
||||
|
||||
|
||||
btn_exclude.clicked.connect(()=>{
|
||||
if (flat_view){
|
||||
gtk_messagebox(_("Cannot exclude files in flat view"),
|
||||
@ -286,7 +286,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
else{
|
||||
exclude_selected_items();
|
||||
}
|
||||
|
||||
|
||||
treeview_refresh();
|
||||
});*/
|
||||
}
|
||||
@ -298,7 +298,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
txt.hexpand = true;
|
||||
txt.margin = 0;
|
||||
hbox.add(txt);
|
||||
|
||||
|
||||
txt.placeholder_text = _("Filter by name or path");
|
||||
|
||||
txt_pattern = txt;
|
||||
@ -332,17 +332,17 @@ public class RsyncLogBox : Gtk.Box {
|
||||
add_action_delayed();
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
//txt.set_no_show_all(true);
|
||||
}
|
||||
|
||||
private void add_combo(Gtk.Box hbox){
|
||||
|
||||
|
||||
// combo
|
||||
var combo = new Gtk.ComboBox ();
|
||||
hbox.add(combo);
|
||||
cmb_filter = combo;
|
||||
|
||||
|
||||
var cell_text = new CellRendererText ();
|
||||
cell_text.text = "";
|
||||
combo.pack_start (cell_text, false);
|
||||
@ -358,10 +358,10 @@ public class RsyncLogBox : Gtk.Box {
|
||||
cmb_filter.model = model;
|
||||
|
||||
TreeIter iter;
|
||||
|
||||
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, "", 1, _("All Files"));
|
||||
|
||||
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, "created", 1, "%s".printf(App.dry_run ? _("Create") : _("Created")));
|
||||
|
||||
@ -369,7 +369,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, "deleted", 1, "%s".printf(App.dry_run ? _("Delete") : _("Deleted")));
|
||||
}
|
||||
|
||||
|
||||
model.append(out iter);
|
||||
|
||||
string txt = "";
|
||||
@ -382,7 +382,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
else{
|
||||
txt = _("Changed");
|
||||
}
|
||||
|
||||
|
||||
model.set (iter, 0, "changed", 1, "%s".printf(txt));
|
||||
|
||||
if (!App.dry_run){
|
||||
@ -399,20 +399,20 @@ public class RsyncLogBox : Gtk.Box {
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, "group", 1, " └ %s".printf(_("Group")));
|
||||
}
|
||||
|
||||
|
||||
cmb_filter.active = 0;
|
||||
}
|
||||
|
||||
private uint tmr_action = 0;
|
||||
|
||||
|
||||
private void add_action_delayed(){
|
||||
|
||||
|
||||
clear_action_delayed();
|
||||
tmr_action = Timeout.add(200, execute_action);
|
||||
}
|
||||
|
||||
private void clear_action_delayed(){
|
||||
|
||||
|
||||
if (tmr_action > 0){
|
||||
Source.remove(tmr_action);
|
||||
tmr_action = 0;
|
||||
@ -424,9 +424,9 @@ public class RsyncLogBox : Gtk.Box {
|
||||
clear_action_delayed();
|
||||
|
||||
name_filter = txt_pattern.text;
|
||||
|
||||
|
||||
treefilter.refilter();
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -478,7 +478,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
cell_pix.stock_size = Gtk.IconSize.MENU;
|
||||
col.pack_start(cell_pix, false);
|
||||
col.set_attributes(cell_pix, "pixbuf", 3);
|
||||
|
||||
|
||||
// cell text
|
||||
var cell_text = new Gtk.CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
@ -495,13 +495,13 @@ public class RsyncLogBox : Gtk.Box {
|
||||
col.expand = true;
|
||||
treeview.append_column(col);
|
||||
col_name = col;
|
||||
|
||||
|
||||
// cell icon
|
||||
var cell_pix = new Gtk.CellRendererPixbuf();
|
||||
cell_pix.stock_size = Gtk.IconSize.MENU;
|
||||
col.pack_start(cell_pix, false);
|
||||
col.set_attributes(cell_pix, "pixbuf", 1);
|
||||
|
||||
|
||||
// cell text
|
||||
var cell_text = new Gtk.CellRendererText ();
|
||||
cell_text.ellipsize = Pango.EllipsizeMode.END;
|
||||
@ -518,20 +518,20 @@ public class RsyncLogBox : Gtk.Box {
|
||||
col.min_width = 20;
|
||||
treeview.append_column(col);
|
||||
//var col_spacer = col;
|
||||
|
||||
|
||||
// cell text
|
||||
var cell_text = new Gtk.CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
}
|
||||
|
||||
|
||||
private void treeview_refresh() {
|
||||
|
||||
|
||||
log_debug("treeview_refresh(): 0");
|
||||
|
||||
var tmr = timer_start();
|
||||
|
||||
hbox_filter.sensitive = false;
|
||||
|
||||
|
||||
gtk_set_busy(true, window);
|
||||
|
||||
var model = new Gtk.ListStore(5,
|
||||
@ -545,7 +545,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
TreeIter iter0;
|
||||
|
||||
var spath = "%s/localhost".printf(file_parent(rsync_log_file));
|
||||
|
||||
|
||||
foreach(var item in loglist) {
|
||||
|
||||
if (App.dry_run){
|
||||
@ -554,7 +554,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
|
||||
string status = "";
|
||||
Gdk.Pixbuf status_icon = null;
|
||||
|
||||
|
||||
if (is_restore_log){
|
||||
|
||||
switch(item.file_status){
|
||||
@ -604,7 +604,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
if (!is_restore_log){
|
||||
relpath = relpath[1:relpath.length]; // show relative path; remove / prefix
|
||||
}
|
||||
|
||||
|
||||
// add row
|
||||
model.append(out iter0);
|
||||
model.set(iter0, 0, item);
|
||||
@ -613,11 +613,11 @@ public class RsyncLogBox : Gtk.Box {
|
||||
model.set(iter0, 3, status_icon);
|
||||
model.set(iter0, 4, status);
|
||||
}
|
||||
|
||||
|
||||
treefilter = new Gtk.TreeModelFilter(model, null);
|
||||
treefilter.set_visible_func(filter_packages_func);
|
||||
treeview.set_model(treefilter);
|
||||
|
||||
|
||||
//treeview.set_model(model);
|
||||
//treeview.columns_autosize();
|
||||
|
||||
@ -628,7 +628,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
}
|
||||
|
||||
private bool filter_packages_func (Gtk.TreeModel model, Gtk.TreeIter iter) {
|
||||
|
||||
|
||||
FileItem item;
|
||||
model.get (iter, 0, out item, -1);
|
||||
|
||||
@ -641,9 +641,9 @@ public class RsyncLogBox : Gtk.Box {
|
||||
|
||||
var spath = "%s/localhost".printf(file_parent(rsync_log_file));
|
||||
var relpath = item.file_path[spath.length:item.file_path.length];
|
||||
|
||||
|
||||
if (!relpath.down().contains(name_filter)){
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -677,7 +677,7 @@ public class RsyncLogBox : Gtk.Box {
|
||||
App.exclude_list_user.clear();
|
||||
|
||||
// TODO: medium: exclude selected items: not working
|
||||
|
||||
|
||||
// add include list
|
||||
TreeIter iter;
|
||||
var store = (Gtk.ListStore) treeview.model;
|
||||
@ -694,14 +694,14 @@ public class RsyncLogBox : Gtk.Box {
|
||||
else{
|
||||
//pattern = "%s/***".printf(pattern);
|
||||
}
|
||||
|
||||
|
||||
if (!App.exclude_list_user.contains(pattern)
|
||||
&& !App.exclude_list_default.contains(pattern)
|
||||
&& !App.exclude_list_home.contains(pattern)){
|
||||
|
||||
|
||||
list.add(pattern);
|
||||
}
|
||||
|
||||
|
||||
iterExists = store.iter_next (ref iter);
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class RsyncLogWindow : Window {
|
||||
public RsyncLogWindow(string _rsync_log_file) {
|
||||
|
||||
log_debug("RsyncLogWindow: RsyncLogWindow()");
|
||||
|
||||
|
||||
this.title = _("Rsync Log Viewer");
|
||||
this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
|
||||
this.set_default_size(def_width, def_height);
|
||||
@ -56,10 +56,10 @@ public class RsyncLogWindow : Window {
|
||||
this.delete_event.connect(on_delete_event);
|
||||
|
||||
rsync_log_file = _rsync_log_file;
|
||||
|
||||
|
||||
logbox = new RsyncLogBox(this);
|
||||
this.add(logbox);
|
||||
|
||||
|
||||
show_all();
|
||||
|
||||
logbox.open_log(rsync_log_file);
|
||||
@ -68,7 +68,7 @@ public class RsyncLogWindow : Window {
|
||||
}
|
||||
|
||||
private bool on_delete_event(Gdk.EventAny event){
|
||||
|
||||
|
||||
if (logbox.is_running){
|
||||
return true; // keep window open
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class ScheduleBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.Image img_shield;
|
||||
private Gtk.Label lbl_shield;
|
||||
private Gtk.Label lbl_shield_subnote;
|
||||
@ -42,25 +42,25 @@ class ScheduleBox : Gtk.Box{
|
||||
private Gtk.SizeGroup sg_count;
|
||||
|
||||
private Gtk.CheckButton chk_cron;
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
|
||||
public ScheduleBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("ScheduleBox: ScheduleBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 12;
|
||||
|
||||
|
||||
add_label_header(this, _("Select Snapshot Levels"), true);
|
||||
|
||||
Gtk.CheckButton chk_m, chk_w, chk_d, chk_h, chk_b = null;
|
||||
Gtk.SpinButton spin_m, spin_w, spin_d, spin_h, spin_b;
|
||||
|
||||
// monthly
|
||||
|
||||
|
||||
add_schedule_option(this, _("Monthly"), _("Create one per month"), out chk_m, out spin_m);
|
||||
|
||||
chk_m.active = App.schedule_monthly;
|
||||
@ -76,9 +76,9 @@ class ScheduleBox : Gtk.Box{
|
||||
spin_m.value_changed.connect(()=>{
|
||||
App.count_monthly = (int) spin_m.get_value();
|
||||
});
|
||||
|
||||
|
||||
// weekly
|
||||
|
||||
|
||||
add_schedule_option(this, _("Weekly"), _("Create one per week"), out chk_w, out spin_w);
|
||||
|
||||
chk_w.active = App.schedule_weekly;
|
||||
@ -96,7 +96,7 @@ class ScheduleBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// daily
|
||||
|
||||
|
||||
add_schedule_option(this, _("Daily"), _("Create one per day"), out chk_d, out spin_d);
|
||||
|
||||
chk_d.active = App.schedule_daily;
|
||||
@ -114,7 +114,7 @@ class ScheduleBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// hourly
|
||||
|
||||
|
||||
add_schedule_option(this, _("Hourly"), _("Create one per hour"), out chk_h, out spin_h);
|
||||
|
||||
chk_h.active = App.schedule_hourly;
|
||||
@ -132,7 +132,7 @@ class ScheduleBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// boot
|
||||
|
||||
|
||||
add_schedule_option(this, _("Boot"), _("Create one per boot"), out chk_b, out spin_b);
|
||||
|
||||
chk_b.active = App.schedule_boot;
|
||||
@ -150,14 +150,14 @@ class ScheduleBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// cron emails --------------------------------------------------------------------
|
||||
|
||||
|
||||
chk_cron = add_checkbox(this, _("Stop cron emails for scheduled tasks"));
|
||||
//chk_cron.hexpand = true;
|
||||
chk_cron.set_tooltip_text(_("The cron service sends the output of scheduled tasks as an email to the current user. Select this option to suppress the emails for cron tasks created by Timeshift."));
|
||||
|
||||
chk_cron.margin = 6;
|
||||
chk_cron.margin_top = 12;
|
||||
|
||||
chk_cron.margin_top = 12;
|
||||
|
||||
chk_cron.active = App.stop_cron_emails;
|
||||
chk_cron.toggled.connect(()=>{
|
||||
App.stop_cron_emails = chk_cron.active;
|
||||
@ -172,9 +172,9 @@ class ScheduleBox : Gtk.Box{
|
||||
var label = new Gtk.Label("");
|
||||
label.vexpand = true;
|
||||
add(label);
|
||||
|
||||
|
||||
// message area -------------------------------------------------------------------
|
||||
|
||||
|
||||
var scrolled = new Gtk.ScrolledWindow(null, null);
|
||||
scrolled.set_shadow_type (ShadowType.ETCHED_IN);
|
||||
scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
@ -193,14 +193,14 @@ class ScheduleBox : Gtk.Box{
|
||||
scrolled.add(label);
|
||||
|
||||
// status area --------------------------------------------------------------------
|
||||
|
||||
|
||||
scrolled = new Gtk.ScrolledWindow(null, null);
|
||||
scrolled.set_shadow_type (ShadowType.ETCHED_IN);
|
||||
scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scrolled.set_size_request(-1, 100);
|
||||
add(scrolled);
|
||||
|
||||
|
||||
// hbox
|
||||
var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
|
||||
hbox.margin = 6;
|
||||
@ -216,7 +216,7 @@ class ScheduleBox : Gtk.Box{
|
||||
var vbox = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox.margin_top = 6;
|
||||
hbox.add (vbox);
|
||||
|
||||
|
||||
// lbl_shield
|
||||
lbl_shield = add_label(vbox, "");
|
||||
lbl_shield.yalign = 0.5f;
|
||||
@ -237,25 +237,25 @@ class ScheduleBox : Gtk.Box{
|
||||
|
||||
private void set_shield_label(
|
||||
string text, bool is_bold = true, bool is_italic = false, bool is_large = true){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(is_bold ? " weight=\"bold\"" : ""),
|
||||
(is_italic ? " style=\"italic\"" : ""),
|
||||
(is_large ? " size=\"x-large\"" : ""),
|
||||
escape_html(text));
|
||||
|
||||
|
||||
lbl_shield.label = msg;
|
||||
}
|
||||
|
||||
private void set_shield_subnote(
|
||||
string text, bool is_bold = false, bool is_italic = true, bool is_large = false){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(is_bold ? " weight=\"bold\"" : ""),
|
||||
(is_italic ? " style=\"italic\"" : ""),
|
||||
(is_large ? " size=\"x-large\"" : ""),
|
||||
escape_html(text));
|
||||
|
||||
|
||||
lbl_shield_subnote.label = msg;
|
||||
}
|
||||
|
||||
@ -274,11 +274,11 @@ class ScheduleBox : Gtk.Box{
|
||||
sg_subtitle = new Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL);
|
||||
sg_count = new Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL);
|
||||
}
|
||||
|
||||
|
||||
var txt = "<b>%s</b>".printf(period);
|
||||
chk = add_checkbox(hbox, txt);
|
||||
sg_title.add_widget(chk);
|
||||
|
||||
|
||||
var tt = _("Number of snapshots to keep.\nOlder snapshots will be removed once this limit is exceeded.");
|
||||
var label = add_label(hbox, " " + _("Keep"));
|
||||
label.set_tooltip_text(tt);
|
||||
@ -286,7 +286,7 @@ class ScheduleBox : Gtk.Box{
|
||||
var spin2 = add_spin(hbox, 1, 999, 10);
|
||||
spin2.set_tooltip_text(tt);
|
||||
sg_count.add_widget(spin2);
|
||||
|
||||
|
||||
spin2.notify["sensitive"].connect(()=>{
|
||||
label.sensitive = spin2.sensitive;
|
||||
});
|
||||
@ -295,20 +295,20 @@ class ScheduleBox : Gtk.Box{
|
||||
}
|
||||
|
||||
public void update_statusbar(){
|
||||
|
||||
|
||||
if (App.schedule_monthly || App.schedule_weekly || App.schedule_daily
|
||||
|| App.schedule_hourly || App.schedule_boot){
|
||||
|
||||
img_shield.surface = IconManager.lookup_surface(IconManager.SHIELD_HIGH,
|
||||
IconManager.SHIELD_ICON_SIZE, img_shield.scale_factor);
|
||||
|
||||
|
||||
set_shield_label(_("Scheduled snapshots are enabled"));
|
||||
set_shield_subnote(_("Snapshots will be created at selected intervals if snapshot disk has enough space (> 1 GB)"));
|
||||
}
|
||||
else{
|
||||
img_shield.surface = IconManager.lookup_surface(IconManager.SHIELD_LOW,
|
||||
IconManager.SHIELD_ICON_SIZE, img_shield.scale_factor);
|
||||
|
||||
|
||||
set_shield_label(_("Scheduled snapshots are disabled"));
|
||||
set_shield_subnote(_("Select the intervals for creating snapshots"));
|
||||
}
|
||||
|
@ -33,22 +33,22 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class SettingsWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.StackSwitcher switcher;
|
||||
private Gtk.Stack stack;
|
||||
|
||||
|
||||
private SnapshotBackendBox backend_box;
|
||||
private BackupDeviceBox backup_dev_box;
|
||||
private ScheduleBox schedule_box;
|
||||
private ExcludeBox exclude_box;
|
||||
private UsersBox users_box;
|
||||
private MiscBox misc_box;
|
||||
|
||||
|
||||
private uint tmr_init;
|
||||
private int def_width = 500;
|
||||
private int def_height = 500;
|
||||
|
||||
|
||||
public SettingsWindow() {
|
||||
|
||||
log_debug("SettingsWindow: SettingsWindow()");
|
||||
@ -71,7 +71,7 @@ class SettingsWindow : Gtk.Window{
|
||||
hbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
hbox.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
|
||||
vbox_main.add(hbox);
|
||||
|
||||
|
||||
switcher = new Gtk.StackSwitcher();
|
||||
switcher.margin = 6;
|
||||
hbox.add (switcher);
|
||||
@ -82,10 +82,10 @@ class SettingsWindow : Gtk.Window{
|
||||
vbox_main.add(stack);
|
||||
|
||||
switcher.set_stack(stack);
|
||||
|
||||
|
||||
backend_box = new SnapshotBackendBox(this);
|
||||
stack.add_titled (backend_box, "type", _("Type"));
|
||||
|
||||
|
||||
backup_dev_box = new BackupDeviceBox(this);
|
||||
stack.add_titled (backup_dev_box, "location", _("Location"));
|
||||
|
||||
@ -97,7 +97,7 @@ class SettingsWindow : Gtk.Window{
|
||||
exclude_box.set_users_box(users_box);
|
||||
|
||||
misc_box = new MiscBox(this, false);
|
||||
|
||||
|
||||
stack.add_titled (users_box, "users", _("Users"));
|
||||
|
||||
stack.add_titled (exclude_box, "filters", _("Filters"));
|
||||
@ -115,16 +115,16 @@ class SettingsWindow : Gtk.Window{
|
||||
//var hbox = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL);
|
||||
var bbox = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL);
|
||||
vbox_main.add(bbox);
|
||||
|
||||
|
||||
#if GTK3_18
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
#endif
|
||||
|
||||
|
||||
var btn_ok = new Button.with_label(_("OK"));
|
||||
btn_ok.margin = 12;
|
||||
btn_ok.set_size_request(100, -1);
|
||||
bbox.add(btn_ok);
|
||||
|
||||
|
||||
btn_ok.clicked.connect(()=>{
|
||||
save_changes();
|
||||
this.destroy();
|
||||
@ -146,25 +146,25 @@ class SettingsWindow : Gtk.Window{
|
||||
|
||||
backend_box.refresh();
|
||||
stack.set_visible_child_name("type");
|
||||
|
||||
|
||||
this.resize(def_width, def_height);
|
||||
|
||||
|
||||
//backup_dev_box.refresh(); //will be triggerred indirectly
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private bool on_delete_event(Gdk.EventAny event){
|
||||
|
||||
|
||||
save_changes();
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void save_changes(){
|
||||
|
||||
|
||||
exclude_box.save_changes();
|
||||
|
||||
|
||||
App.cron_job_update();
|
||||
|
||||
//App.check_encrypted_home(this);
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class SetupWizardWindow : Gtk.Window{
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Notebook notebook;
|
||||
|
||||
@ -56,11 +56,11 @@ class SetupWizardWindow : Gtk.Window{
|
||||
private uint tmr_init;
|
||||
private int def_width = 600;
|
||||
private int def_height = 500;
|
||||
|
||||
|
||||
public SetupWizardWindow() {
|
||||
|
||||
log_debug("SetupWizardWindow: SetupWizardWindow()");
|
||||
|
||||
|
||||
this.title = _("Setup Wizard");
|
||||
this.window_position = WindowPosition.CENTER;
|
||||
this.modal = true;
|
||||
@ -68,7 +68,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
this.icon = IconManager.lookup("timeshift",16);
|
||||
|
||||
this.delete_event.connect(on_delete_event);
|
||||
|
||||
|
||||
// vbox_main
|
||||
vbox_main = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox_main.margin = 0;
|
||||
@ -95,7 +95,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
backend_box = new SnapshotBackendBox(this);
|
||||
backend_box.margin = 12;
|
||||
notebook.append_page (backend_box, label);
|
||||
|
||||
|
||||
label = new Gtk.Label(_("Estimate"));
|
||||
estimate_box = new EstimateBox(this);
|
||||
estimate_box.margin = 12;
|
||||
@ -123,7 +123,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
notebook.append_page (finish_box, label);
|
||||
|
||||
// TODO: Add a tab for excluding browser cache and other items
|
||||
|
||||
|
||||
create_actions();
|
||||
|
||||
show_all();
|
||||
@ -132,7 +132,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
|
||||
log_debug("SetupWizardWindow: SetupWizardWindow(): exit");
|
||||
}
|
||||
|
||||
|
||||
private bool init_delayed(){
|
||||
|
||||
if (tmr_init > 0){
|
||||
@ -158,40 +158,40 @@ class SetupWizardWindow : Gtk.Window{
|
||||
}
|
||||
|
||||
save_changes();
|
||||
|
||||
|
||||
return false; // close window
|
||||
}
|
||||
|
||||
|
||||
private void save_changes(){
|
||||
|
||||
|
||||
App.cron_job_update();
|
||||
|
||||
App.first_run = false;
|
||||
|
||||
|
||||
//App.check_encrypted_home(this);
|
||||
|
||||
//App.check_encrypted_private_dirs(this);
|
||||
}
|
||||
|
||||
|
||||
private void create_actions(){
|
||||
|
||||
var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
|
||||
vbox_main.add(hbox);
|
||||
|
||||
|
||||
var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
|
||||
bbox.margin = 12;
|
||||
bbox.spacing = 6;
|
||||
bbox.hexpand = true;
|
||||
hbox.add(bbox);
|
||||
|
||||
|
||||
#if GTK3_18
|
||||
bbox.set_layout (Gtk.ButtonBoxStyle.CENTER);
|
||||
#endif
|
||||
|
||||
|
||||
Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
|
||||
|
||||
|
||||
// previous
|
||||
|
||||
|
||||
btn_prev = add_button(bbox, _("Previous"), "", size_group, null);
|
||||
|
||||
btn_prev.clicked.connect(()=>{
|
||||
@ -199,7 +199,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// next
|
||||
|
||||
|
||||
btn_next = add_button(bbox, _("Next"), "", size_group, null);
|
||||
|
||||
btn_next.clicked.connect(()=>{
|
||||
@ -207,7 +207,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// close
|
||||
|
||||
|
||||
btn_close = add_button(bbox, _("Finish"), "", size_group, null);
|
||||
|
||||
btn_close.clicked.connect(()=>{
|
||||
@ -216,40 +216,40 @@ class SetupWizardWindow : Gtk.Window{
|
||||
});
|
||||
|
||||
// cancel
|
||||
|
||||
|
||||
btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null);
|
||||
|
||||
btn_cancel.clicked.connect(()=>{
|
||||
if (App.task != null){
|
||||
App.task.stop(AppStatus.CANCELLED);
|
||||
}
|
||||
|
||||
|
||||
this.destroy(); // TODO: Show error page
|
||||
});
|
||||
|
||||
btn_prev.hexpand = btn_next.hexpand = btn_close.hexpand = true;
|
||||
btn_cancel.hexpand = true;
|
||||
|
||||
|
||||
action_buttons_set_no_show_all(true);
|
||||
}
|
||||
|
||||
private void action_buttons_set_no_show_all(bool val){
|
||||
|
||||
|
||||
btn_prev.no_show_all = val;
|
||||
btn_next.no_show_all = val;
|
||||
btn_close.no_show_all = val;
|
||||
btn_cancel.no_show_all = val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// navigation
|
||||
|
||||
private void go_first(){
|
||||
|
||||
|
||||
// set initial tab
|
||||
|
||||
notebook.page = Tabs.SNAPSHOT_BACKEND;
|
||||
|
||||
|
||||
/*if (App.live_system()){
|
||||
// skip estimate_box and go to backup_dev_box
|
||||
notebook.page = Tabs.SNAPSHOT_BACKEND;
|
||||
@ -265,9 +265,9 @@ class SetupWizardWindow : Gtk.Window{
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_prev(){
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.SNAPSHOT_BACKEND:
|
||||
case Tabs.ESTIMATE:
|
||||
@ -286,12 +286,12 @@ class SetupWizardWindow : Gtk.Window{
|
||||
notebook.page = Tabs.USERS;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
|
||||
private void go_next(){
|
||||
|
||||
|
||||
if (!validate_current_tab()){
|
||||
return;
|
||||
}
|
||||
@ -305,11 +305,11 @@ class SetupWizardWindow : Gtk.Window{
|
||||
notebook.page = Tabs.ESTIMATE; // rsync mode only
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.ESTIMATE:
|
||||
notebook.page = Tabs.BACKUP_DEVICE;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.BACKUP_DEVICE:
|
||||
if (App.live_system()){
|
||||
destroy();
|
||||
@ -318,7 +318,7 @@ class SetupWizardWindow : Gtk.Window{
|
||||
notebook.page = Tabs.SCHEDULE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.SCHEDULE:
|
||||
notebook.page = Tabs.USERS;
|
||||
schedule_accepted = true;
|
||||
@ -327,12 +327,12 @@ class SetupWizardWindow : Gtk.Window{
|
||||
case Tabs.USERS:
|
||||
notebook.page = Tabs.FINISH;
|
||||
break;
|
||||
|
||||
|
||||
case Tabs.FINISH:
|
||||
// btn_next is disabled for this page
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
initialize_tab();
|
||||
}
|
||||
|
||||
@ -348,13 +348,13 @@ class SetupWizardWindow : Gtk.Window{
|
||||
// show/hide actions -----------------------------------
|
||||
|
||||
action_buttons_set_no_show_all(false);
|
||||
|
||||
|
||||
btn_cancel.hide(); // TODO: remove this
|
||||
|
||||
btn_prev.show();
|
||||
btn_next.show();
|
||||
btn_close.show();
|
||||
|
||||
|
||||
switch(notebook.page){
|
||||
case Tabs.SNAPSHOT_BACKEND:
|
||||
btn_prev.sensitive = false;
|
||||
@ -421,10 +421,10 @@ class SetupWizardWindow : Gtk.Window{
|
||||
}
|
||||
else if (notebook.page == Tabs.BACKUP_DEVICE){
|
||||
if (!App.repo.available() || !App.repo.has_space()){
|
||||
|
||||
|
||||
gtk_messagebox(App.repo.status_message,
|
||||
App.repo.status_details, this, true);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -33,18 +33,18 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class SnapshotBackendBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.RadioButton opt_rsync;
|
||||
private Gtk.RadioButton opt_btrfs;
|
||||
private Gtk.Label lbl_description;
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
|
||||
public signal void type_changed();
|
||||
|
||||
public SnapshotBackendBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("SnapshotBackendBox: SnapshotBackendBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -64,7 +64,7 @@ class SnapshotBackendBox : Gtk.Box{
|
||||
var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
|
||||
//hbox.homogeneous = true;
|
||||
add(vbox);
|
||||
|
||||
|
||||
add_opt_rsync(vbox);
|
||||
|
||||
add_opt_btrfs(vbox);
|
||||
@ -113,28 +113,28 @@ class SnapshotBackendBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private bool check_for_btrfs_tools(){
|
||||
|
||||
|
||||
if (!cmd_exists("btrfs")){
|
||||
|
||||
|
||||
string msg = _("The 'btrfs' command is not available on your system. Install the 'btrfs-tools' package and try again.");
|
||||
string title = _("BTRFS Tools Not Found");
|
||||
gtk_set_busy(false, parent_window);
|
||||
gtk_messagebox(title, msg, parent_window, true);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void add_description(){
|
||||
|
||||
Gtk.Expander expander = new Gtk.Expander(_("Help"));
|
||||
expander.use_markup = true;
|
||||
expander.margin_top = 12;
|
||||
this.add(expander);
|
||||
|
||||
|
||||
// scrolled
|
||||
var scrolled = new ScrolledWindow(null, null);
|
||||
scrolled.set_shadow_type (ShadowType.ETCHED_IN);
|
||||
@ -161,16 +161,16 @@ class SnapshotBackendBox : Gtk.Box{
|
||||
private void update_description(){
|
||||
|
||||
string bullet = "• ";
|
||||
|
||||
|
||||
if (opt_btrfs.active){
|
||||
string txt = "<b>" + _("BTRFS Snapshots") + "</b>\n\n";
|
||||
|
||||
txt += bullet + _("Snapshots are created using the built-in features of the BTRFS file system.") + "\n\n";
|
||||
|
||||
|
||||
txt += bullet + _("Snapshots are created and restored instantly. Snapshot creation is an atomic transaction at the file system level.") + "\n\n";
|
||||
|
||||
txt += bullet + _("Snapshots are restored by replacing system subvolumes. Since files are never copied, deleted or overwritten, there is no risk of data loss. The existing system is preserved as a new snapshot after restore.") + "\n\n";
|
||||
|
||||
|
||||
txt += bullet + _("Snapshots are perfect, byte-for-byte copies of the system. Nothing is excluded.") + "\n\n";
|
||||
|
||||
txt += bullet + _("Snapshots are saved on the same disk from which they are created (system disk). Storage on other disks is not supported. If system disk fails then snapshots stored on it will be lost along with the system.") + "\n\n";
|
||||
@ -178,14 +178,14 @@ class SnapshotBackendBox : Gtk.Box{
|
||||
txt += bullet + _("Size of BTRFS snapshots are initially zero. As system files gradually change with time, data gets written to new data blocks which take up disk space (copy-on-write). Files in the snapshot continue to point to original data blocks.") + "\n\n";
|
||||
|
||||
txt += bullet + _("OS must be installed on a BTRFS partition with Ubuntu-type subvolume layout (@ and @home subvolumes). Other layouts are not supported.") + "\n\n";
|
||||
|
||||
|
||||
lbl_description.label = txt;
|
||||
}
|
||||
else{
|
||||
string txt = "<b>" + _("RSYNC Snapshots") + "</b>\n\n";
|
||||
|
||||
txt += bullet + _("Snapshots are created by creating copies of system files using rsync, and hard-linking unchanged files from previous snapshot.") + "\n\n";
|
||||
|
||||
|
||||
txt += bullet + _("All files are copied when first snapshot is created. Subsequent snapshots are incremental. Unchanged files will be hard-linked from the previous snapshot if available.") + "\n\n";
|
||||
|
||||
txt += bullet + _("Snapshots can be saved to any disk formatted with a Linux file system. Saving snapshots to non-system or external disk allows the system to be restored even if system disk is damaged or re-formatted.") + "\n\n";
|
||||
@ -195,14 +195,14 @@ class SnapshotBackendBox : Gtk.Box{
|
||||
lbl_description.label = txt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void init_backend(){
|
||||
|
||||
|
||||
App.try_select_default_device_for_backup(parent_window);
|
||||
}
|
||||
|
||||
public void refresh(){
|
||||
|
||||
|
||||
opt_btrfs.active = App.btrfs_mode;
|
||||
type_changed();
|
||||
update_description();
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class SnapshotListBox : Gtk.Box{
|
||||
|
||||
|
||||
public Gtk.TreeView treeview;
|
||||
private Gtk.TreeViewColumn col_date;
|
||||
private Gtk.TreeViewColumn col_tags;
|
||||
@ -50,7 +50,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
private Gtk.ImageMenuItem mi_mark;
|
||||
private Gtk.ImageMenuItem mi_view_log_create;
|
||||
private Gtk.ImageMenuItem mi_view_log_restore;
|
||||
|
||||
|
||||
private Gtk.Window parent_window;
|
||||
|
||||
public signal void delete_selected();
|
||||
@ -61,21 +61,21 @@ class SnapshotListBox : Gtk.Box{
|
||||
public SnapshotListBox (Gtk.Window _parent_window) {
|
||||
|
||||
log_debug("SnapshotListBox: SnapshotListBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
margin = 6;
|
||||
|
||||
init_treeview();
|
||||
|
||||
|
||||
init_list_view_context_menu();
|
||||
|
||||
log_debug("SnapshotListBox: SnapshotListBox(): exit");
|
||||
}
|
||||
|
||||
private void init_treeview(){
|
||||
|
||||
|
||||
//treeview
|
||||
treeview = new TreeView();
|
||||
treeview.get_selection().mode = SelectionMode.MULTIPLE;
|
||||
@ -182,7 +182,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
col.set_cell_data_func (cell_size, cell_size_render);
|
||||
col_size = col;
|
||||
treeview.append_column(col_size);
|
||||
|
||||
|
||||
col_size.clicked.connect(() => {
|
||||
if(treeview_sort_column_index == 2){
|
||||
treeview_sort_column_desc = !treeview_sort_column_desc;
|
||||
@ -207,7 +207,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
col.set_cell_data_func (cell_unshared, cell_unshared_render);
|
||||
col_unshared = col;
|
||||
treeview.append_column(col_unshared);
|
||||
|
||||
|
||||
col_unshared.clicked.connect(() => {
|
||||
if(treeview_sort_column_index == 2){
|
||||
treeview_sort_column_desc = !treeview_sort_column_desc;
|
||||
@ -230,7 +230,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
col_desc.pack_start (cell_desc, false);
|
||||
col_desc.set_cell_data_func (cell_desc, cell_desc_render);
|
||||
treeview.append_column(col_desc);
|
||||
|
||||
|
||||
cell_desc.editable = true;
|
||||
cell_desc.edited.connect ((path, new_text)=>{
|
||||
Snapshot bak;
|
||||
@ -247,22 +247,22 @@ class SnapshotListBox : Gtk.Box{
|
||||
cell_text.width = 20;
|
||||
col_buffer.pack_start (cell_text, false);
|
||||
treeview.append_column(col_buffer);
|
||||
|
||||
|
||||
//tooltips
|
||||
treeview.query_tooltip.connect ((x, y, keyboard_tooltip, tooltip) => {
|
||||
|
||||
|
||||
TreeModel model;
|
||||
TreePath path;
|
||||
TreeIter iter;
|
||||
TreeViewColumn column;
|
||||
|
||||
|
||||
if (treeview.get_tooltip_context (ref x, ref y, keyboard_tooltip, out model, out path, out iter)){
|
||||
|
||||
|
||||
int bx, by;
|
||||
treeview.convert_widget_to_bin_window_coords(x, y, out bx, out by);
|
||||
|
||||
|
||||
if (treeview.get_path_at_pos (bx, by, null, out column, null, null)){
|
||||
|
||||
|
||||
if ((column == col_date) || (column == col_system)){
|
||||
|
||||
Snapshot bak;
|
||||
@ -273,7 +273,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
if (App.btrfs_mode){
|
||||
|
||||
txt += "<b>%s: %d</b>\n".printf(_("Subvolumes"), bak.subvolumes.values.size);
|
||||
|
||||
|
||||
foreach(var subvol in bak.subvolumes_sorted){
|
||||
if (txt.length > 0) { txt += "\n"; }
|
||||
txt += "%s".printf(subvol.path);
|
||||
@ -282,7 +282,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
else{
|
||||
txt = bak.path;
|
||||
}
|
||||
|
||||
|
||||
tooltip.set_markup(txt);
|
||||
return true;
|
||||
}
|
||||
@ -311,7 +311,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private void init_list_view_context_menu(){
|
||||
|
||||
|
||||
Gdk.RGBA gray = Gdk.RGBA();
|
||||
gray.parse ("rgba(200,200,200,1)");
|
||||
|
||||
@ -324,68 +324,68 @@ class SnapshotListBox : Gtk.Box{
|
||||
item.activate.connect(()=> { delete_selected(); });
|
||||
menu_snapshots.append(item);
|
||||
mi_remove = item;
|
||||
|
||||
|
||||
// mi_mark
|
||||
item = new ImageMenuItem.with_label(_("Mark/Unmark for Deletion"));
|
||||
item.image = IconManager.lookup_image("edit-delete", 16);
|
||||
item.activate.connect(()=> { mark_selected(); });
|
||||
menu_snapshots.append(item);
|
||||
mi_mark = item;
|
||||
|
||||
|
||||
// mi_browse
|
||||
item = new ImageMenuItem.with_label(_("Browse Files"));
|
||||
item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_DIRECTORY, 16);
|
||||
item.activate.connect(()=> { browse_selected(); });
|
||||
menu_snapshots.append(item);
|
||||
mi_browse = item;
|
||||
|
||||
|
||||
// mi_view_log_create
|
||||
item = new ImageMenuItem.with_label(_("View Rsync Log for Create"));
|
||||
item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_FILE, 16);
|
||||
item.activate.connect(()=> { view_snapshot_log(false); });
|
||||
menu_snapshots.append(item);
|
||||
mi_view_log_create = item;
|
||||
|
||||
|
||||
// mi_view_log_restore
|
||||
item = new ImageMenuItem.with_label(_("View Rsync Log for Restore"));
|
||||
item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_FILE, 16);
|
||||
item.activate.connect(()=> { view_snapshot_log(true); });
|
||||
menu_snapshots.append(item);
|
||||
mi_view_log_restore = item;
|
||||
|
||||
|
||||
menu_snapshots.show_all();
|
||||
|
||||
// connect signal for shift+F10
|
||||
treeview.popup_menu.connect(treeview_popup_menu);
|
||||
|
||||
|
||||
// connect signal for right-click
|
||||
treeview.button_press_event.connect(treeview_button_press_event);
|
||||
}
|
||||
|
||||
// signals
|
||||
|
||||
|
||||
private bool treeview_popup_menu(){
|
||||
|
||||
|
||||
return menu_snapshots_popup (menu_snapshots, null);
|
||||
}
|
||||
|
||||
private bool treeview_button_press_event(Gdk.EventButton event){
|
||||
|
||||
|
||||
if (event.button == 3) {
|
||||
return menu_snapshots_popup (menu_snapshots, event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// renderers
|
||||
|
||||
|
||||
private void cell_date_render(
|
||||
CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
model.get (iter, 0, out bak, -1);
|
||||
|
||||
|
||||
var ctxt = (cell as Gtk.CellRendererText);
|
||||
ctxt.text = bak.date_formatted;
|
||||
ctxt.sensitive = !bak.marked_for_deletion;
|
||||
@ -396,16 +396,16 @@ class SnapshotListBox : Gtk.Box{
|
||||
else{
|
||||
ctxt.markup = ctxt.text;
|
||||
}
|
||||
|
||||
|
||||
// Note: Avoid AM/PM as it may be hidden due to locale settings
|
||||
}
|
||||
|
||||
private void cell_tags_render(
|
||||
CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
model.get (iter, 0, out bak, -1);
|
||||
|
||||
|
||||
var ctxt = (cell as Gtk.CellRendererText);
|
||||
ctxt.text = bak.taglist_short;
|
||||
ctxt.sensitive = !bak.marked_for_deletion;
|
||||
@ -420,30 +420,30 @@ class SnapshotListBox : Gtk.Box{
|
||||
|
||||
private void cell_size_render(
|
||||
CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
model.get (iter, 0, out bak, -1);
|
||||
|
||||
|
||||
var ctxt = (cell as Gtk.CellRendererText);
|
||||
|
||||
if (bak.btrfs_mode){
|
||||
|
||||
|
||||
int64 size = 0;
|
||||
|
||||
|
||||
if (bak.subvolumes.has_key("@")){
|
||||
size += bak.subvolumes["@"].total_bytes;
|
||||
}
|
||||
|
||||
|
||||
if (bak.subvolumes.has_key("@home")){
|
||||
size += bak.subvolumes["@home"].total_bytes;
|
||||
}
|
||||
|
||||
|
||||
ctxt.text = format_file_size(size);
|
||||
}
|
||||
else{
|
||||
ctxt.text = "";
|
||||
}
|
||||
|
||||
|
||||
ctxt.sensitive = !bak.marked_for_deletion;
|
||||
|
||||
if (bak.live){
|
||||
@ -456,29 +456,29 @@ class SnapshotListBox : Gtk.Box{
|
||||
|
||||
private void cell_unshared_render(
|
||||
CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
model.get (iter, 0, out bak, -1);
|
||||
|
||||
|
||||
var ctxt = (cell as Gtk.CellRendererText);
|
||||
|
||||
if (bak.btrfs_mode){
|
||||
|
||||
|
||||
int64 size = 0;
|
||||
|
||||
|
||||
if (bak.subvolumes.has_key("@")){
|
||||
size += bak.subvolumes["@"].unshared_bytes;
|
||||
}
|
||||
if (bak.subvolumes.has_key("@home")){
|
||||
size += bak.subvolumes["@home"].unshared_bytes;
|
||||
}
|
||||
|
||||
|
||||
ctxt.text = format_file_size(size);
|
||||
}
|
||||
else{
|
||||
ctxt.text = "";
|
||||
}
|
||||
|
||||
|
||||
ctxt.sensitive = !bak.marked_for_deletion;
|
||||
|
||||
if (bak.live){
|
||||
@ -491,10 +491,10 @@ class SnapshotListBox : Gtk.Box{
|
||||
|
||||
private void cell_system_render(
|
||||
CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){
|
||||
|
||||
|
||||
Snapshot bak;
|
||||
model.get (iter, 0, out bak, -1);
|
||||
|
||||
|
||||
var ctxt = (cell as Gtk.CellRendererText);
|
||||
ctxt.text = bak.sys_distro;
|
||||
ctxt.sensitive = !bak.marked_for_deletion;
|
||||
@ -528,9 +528,9 @@ class SnapshotListBox : Gtk.Box{
|
||||
}
|
||||
|
||||
private bool menu_snapshots_popup (Gtk.Menu popup, Gdk.EventButton? event) {
|
||||
|
||||
|
||||
var selected = selected_snapshots();
|
||||
|
||||
|
||||
mi_remove.sensitive = (selected.size > 0);
|
||||
mi_mark.sensitive = (selected.size > 0);
|
||||
mi_view_log_create.sensitive = !App.btrfs_mode;
|
||||
@ -539,7 +539,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
if (!App.btrfs_mode){
|
||||
|
||||
if (selected.size > 0){
|
||||
|
||||
|
||||
mi_view_log_restore.sensitive = file_exists(selected[0].rsync_restore_log_file)
|
||||
|| file_exists(selected[0].rsync_restore_changes_log_file);
|
||||
}
|
||||
@ -550,12 +550,12 @@ class SnapshotListBox : Gtk.Box{
|
||||
} else {
|
||||
menu_snapshots.popup (null, null, null, 0, Gtk.get_current_event_time());
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// actions
|
||||
|
||||
|
||||
public void refresh(){
|
||||
|
||||
var model = new Gtk.ListStore(1, typeof(Snapshot));
|
||||
@ -566,7 +566,7 @@ class SnapshotListBox : Gtk.Box{
|
||||
}
|
||||
|
||||
App.repo.load_snapshots();
|
||||
|
||||
|
||||
var list = App.repo.snapshots;
|
||||
|
||||
if (treeview_sort_column_index == 0){
|
||||
@ -616,23 +616,23 @@ class SnapshotListBox : Gtk.Box{
|
||||
}
|
||||
|
||||
col_size.visible = App.btrfs_mode;
|
||||
col_unshared.visible = App.btrfs_mode;
|
||||
col_unshared.visible = App.btrfs_mode;
|
||||
|
||||
treeview.set_model (model);
|
||||
treeview.columns_autosize ();
|
||||
}
|
||||
|
||||
public void hide_context_menu(){
|
||||
|
||||
|
||||
// disconnect signal for shift+F10
|
||||
treeview.popup_menu.disconnect(treeview_popup_menu);
|
||||
|
||||
|
||||
// disconnect signal for right-click
|
||||
treeview.button_press_event.disconnect(treeview_button_press_event);
|
||||
}
|
||||
|
||||
public Gee.ArrayList<Snapshot> selected_snapshots(){
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<Snapshot>();
|
||||
|
||||
TreeIter iter;
|
||||
|
@ -33,7 +33,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
class UsersBox : Gtk.Box{
|
||||
|
||||
|
||||
private Gtk.TreeView treeview;
|
||||
private Gtk.ScrolledWindow scrolled_treeview;
|
||||
private Gtk.Window parent_window;
|
||||
@ -43,11 +43,11 @@ class UsersBox : Gtk.Box{
|
||||
private Gtk.CheckButton chk_include_btrfs_home;
|
||||
private Gtk.CheckButton chk_enable_qgroups;
|
||||
private bool restore_mode = false;
|
||||
|
||||
|
||||
public UsersBox (Gtk.Window _parent_window, ExcludeBox _exclude_box, bool _restore_mode) {
|
||||
|
||||
log_debug("UsersBox: UsersBox()");
|
||||
|
||||
|
||||
//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
|
||||
GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
|
||||
parent_window = _parent_window;
|
||||
@ -59,11 +59,11 @@ class UsersBox : Gtk.Box{
|
||||
|
||||
var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
|
||||
add(box);
|
||||
|
||||
|
||||
add_label_header(this, _("User Home Directories"), true);
|
||||
|
||||
// ------------------------
|
||||
|
||||
|
||||
var label = add_label(this, _("User home directories are excluded by default unless you enable them here"), false, true);
|
||||
lbl_message = label;
|
||||
|
||||
@ -75,14 +75,14 @@ class UsersBox : Gtk.Box{
|
||||
init_btrfs_home_option(box_btrfs);
|
||||
|
||||
init_btrfs_qgroup_option(box_btrfs);
|
||||
|
||||
|
||||
refresh();
|
||||
|
||||
log_debug("UsersBox: UsersBox(): exit");
|
||||
}
|
||||
|
||||
private void init_treeview(){
|
||||
|
||||
|
||||
// treeview
|
||||
treeview = new TreeView();
|
||||
treeview.get_selection().mode = SelectionMode.MULTIPLE;
|
||||
@ -99,7 +99,7 @@ class UsersBox : Gtk.Box{
|
||||
scrolled.expand = true;
|
||||
add(scrolled);
|
||||
scrolled_treeview = scrolled;
|
||||
|
||||
|
||||
// column
|
||||
var col = new TreeViewColumn();
|
||||
col.title = _("User");
|
||||
@ -108,7 +108,7 @@ class UsersBox : Gtk.Box{
|
||||
// name
|
||||
var cell_text = new CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
|
||||
|
||||
col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{
|
||||
SystemUser user;
|
||||
model.get(iter, 0, out user);
|
||||
@ -123,7 +123,7 @@ class UsersBox : Gtk.Box{
|
||||
// name
|
||||
cell_text = new CellRendererText ();
|
||||
col.pack_start (cell_text, false);
|
||||
|
||||
|
||||
col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{
|
||||
SystemUser user;
|
||||
model.get(iter, 0, out user);
|
||||
@ -131,11 +131,11 @@ class UsersBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// column -------------------------------------------------
|
||||
|
||||
|
||||
col = new TreeViewColumn();
|
||||
col.title = _("Exclude All Files");
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
// radio_exclude
|
||||
var cell_radio = new Gtk.CellRendererToggle();
|
||||
cell_radio.radio = true;
|
||||
@ -144,19 +144,19 @@ class UsersBox : Gtk.Box{
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
col.set_attributes(cell_radio, "active", 3);
|
||||
|
||||
|
||||
cell_radio.toggled.connect((cell, path)=>{
|
||||
|
||||
log_debug("cell_exclude.toggled()");
|
||||
|
||||
|
||||
var model = (Gtk.ListStore) treeview.model;
|
||||
TreeIter iter;
|
||||
|
||||
|
||||
model.get_iter_from_string (out iter, path);
|
||||
|
||||
bool enabled;
|
||||
model.get(iter, 3, out enabled);
|
||||
|
||||
|
||||
SystemUser user;
|
||||
model.get(iter, 0, out user);
|
||||
|
||||
@ -168,9 +168,9 @@ class UsersBox : Gtk.Box{
|
||||
inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name);
|
||||
exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name);
|
||||
}
|
||||
|
||||
|
||||
enabled = !enabled;
|
||||
|
||||
|
||||
if (enabled){
|
||||
if (!App.exclude_list_user.contains(exc_pattern)){
|
||||
App.exclude_list_user.add(exc_pattern);
|
||||
@ -184,16 +184,16 @@ class UsersBox : Gtk.Box{
|
||||
}
|
||||
|
||||
this.refresh_treeview();
|
||||
|
||||
|
||||
//exclude_box.refresh_treeview();
|
||||
});
|
||||
|
||||
// column -------------------------------------------------
|
||||
|
||||
|
||||
col = new TreeViewColumn();
|
||||
col.title = _("Include Only Hidden Files");
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
// radio_include
|
||||
cell_radio = new Gtk.CellRendererToggle();
|
||||
cell_radio.radio = true;
|
||||
@ -202,41 +202,41 @@ class UsersBox : Gtk.Box{
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
col.set_attributes(cell_radio, "active", 1);
|
||||
|
||||
|
||||
cell_radio.toggled.connect((cell, path)=>{
|
||||
|
||||
log_debug("cell_include.toggled()");
|
||||
|
||||
|
||||
var model = (Gtk.ListStore) treeview.model;
|
||||
TreeIter iter;
|
||||
|
||||
|
||||
model.get_iter_from_string (out iter, path);
|
||||
|
||||
bool enabled;
|
||||
model.get(iter, 1, out enabled);
|
||||
|
||||
|
||||
SystemUser user;
|
||||
model.get(iter, 0, out user);
|
||||
|
||||
string exc_pattern = "%s/**".printf(user.home_path);
|
||||
string inc_pattern = "+ %s/**".printf(user.home_path);
|
||||
string inc_hidden_pattern = "+ %s/.**".printf(user.home_path);
|
||||
|
||||
|
||||
if (user.has_encrypted_home){
|
||||
inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name);
|
||||
exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name);
|
||||
}
|
||||
|
||||
|
||||
enabled = !enabled;
|
||||
|
||||
|
||||
if (enabled){
|
||||
|
||||
|
||||
if (user.has_encrypted_home){
|
||||
|
||||
|
||||
string txt = _("Encrypted Home Directory");
|
||||
|
||||
string msg = _("Selected user has an encrypted home directory. It's not possible to include only hidden files.");
|
||||
|
||||
|
||||
gtk_messagebox(txt, msg, parent_window, true);
|
||||
|
||||
return;
|
||||
@ -261,7 +261,7 @@ class UsersBox : Gtk.Box{
|
||||
});
|
||||
|
||||
// column --------------------------------------------
|
||||
|
||||
|
||||
col = new TreeViewColumn();
|
||||
col.title = _("Include All Files");
|
||||
treeview.append_column(col);
|
||||
@ -272,7 +272,7 @@ class UsersBox : Gtk.Box{
|
||||
cell_radio.xpad = 2;
|
||||
cell_radio.activatable = true;
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
|
||||
col.set_attributes(cell_radio, "active", 2);
|
||||
|
||||
cell_radio.toggled.connect((cell, path)=>{
|
||||
@ -297,7 +297,7 @@ class UsersBox : Gtk.Box{
|
||||
inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name);
|
||||
exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name);
|
||||
}
|
||||
|
||||
|
||||
if (enabled){
|
||||
if (!App.exclude_list_user.contains(inc_pattern)){
|
||||
App.exclude_list_user.add(inc_pattern);
|
||||
@ -325,24 +325,24 @@ class UsersBox : Gtk.Box{
|
||||
private void init_btrfs_home_option(Gtk.Box box){
|
||||
|
||||
if (restore_mode){
|
||||
|
||||
|
||||
chk_include_btrfs_home = new Gtk.CheckButton.with_label(_("Restore @home subvolume"));
|
||||
|
||||
box.add(chk_include_btrfs_home);
|
||||
|
||||
chk_include_btrfs_home.toggled.connect(()=>{
|
||||
App.include_btrfs_home_for_restore = chk_include_btrfs_home.active;
|
||||
App.include_btrfs_home_for_restore = chk_include_btrfs_home.active;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
chk_include_btrfs_home = new Gtk.CheckButton.with_label(_("Include @home subvolume in backups"));
|
||||
|
||||
|
||||
box.add(chk_include_btrfs_home);
|
||||
|
||||
chk_include_btrfs_home.toggled.connect(()=>{
|
||||
App.include_btrfs_home_for_backup = chk_include_btrfs_home.active;
|
||||
App.include_btrfs_home_for_backup = chk_include_btrfs_home.active;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -353,7 +353,7 @@ class UsersBox : Gtk.Box{
|
||||
|
||||
var label = add_label_header(box, _("Miscellaneous"), true);
|
||||
label.margin_top = 12;
|
||||
|
||||
|
||||
chk_enable_qgroups = new Gtk.CheckButton.with_label(_("Enable BTRFS qgroups (recommended)"));
|
||||
box.add(chk_enable_qgroups);
|
||||
|
||||
@ -362,11 +362,11 @@ class UsersBox : Gtk.Box{
|
||||
chk_enable_qgroups.active = App.btrfs_use_qgroup;
|
||||
|
||||
chk_enable_qgroups.toggled.connect(()=>{
|
||||
App.btrfs_use_qgroup = chk_enable_qgroups.active;
|
||||
App.btrfs_use_qgroup = chk_enable_qgroups.active;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
public void refresh(){
|
||||
@ -381,7 +381,7 @@ class UsersBox : Gtk.Box{
|
||||
|
||||
box_btrfs.set_no_show_all(false);
|
||||
box_btrfs.show_all();
|
||||
|
||||
|
||||
if (restore_mode){
|
||||
chk_include_btrfs_home.active = App.include_btrfs_home_for_restore;
|
||||
}
|
||||
@ -397,21 +397,21 @@ class UsersBox : Gtk.Box{
|
||||
scrolled_treeview.set_no_show_all(false);
|
||||
|
||||
refresh_treeview();
|
||||
|
||||
|
||||
box_btrfs.hide();
|
||||
box_btrfs.set_no_show_all(true);
|
||||
}
|
||||
|
||||
show_all();
|
||||
}
|
||||
|
||||
|
||||
private void refresh_treeview(){
|
||||
|
||||
|
||||
var model = new Gtk.ListStore(4, typeof(SystemUser), typeof(bool), typeof(bool), typeof(bool));
|
||||
treeview.model = model;
|
||||
|
||||
TreeIter iter;
|
||||
|
||||
|
||||
foreach(var user in App.current_system_users.values){
|
||||
|
||||
if (user.is_system){ continue; }
|
||||
@ -424,13 +424,13 @@ class UsersBox : Gtk.Box{
|
||||
inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name);
|
||||
exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name);
|
||||
}
|
||||
|
||||
|
||||
bool include_hidden = App.exclude_list_user.contains(inc_hidden_pattern);
|
||||
bool include_all = App.exclude_list_user.contains(inc_pattern);
|
||||
bool exclude_all = !include_hidden && !include_all; //App.exclude_list_user.contains(exc_pattern);
|
||||
|
||||
if (exclude_all){
|
||||
|
||||
|
||||
if (!App.exclude_list_user.contains(exc_pattern)){
|
||||
App.exclude_list_user.add(exc_pattern);
|
||||
}
|
||||
@ -441,7 +441,7 @@ class UsersBox : Gtk.Box{
|
||||
App.exclude_list_user.remove(inc_hidden_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
model.append(out iter);
|
||||
model.set (iter, 0, user);
|
||||
model.set (iter, 1, include_hidden);
|
||||
@ -467,10 +467,10 @@ class UsersBox : Gtk.Box{
|
||||
if (!App.exclude_list_user.contains(pattern)
|
||||
&& !App.exclude_list_default.contains(pattern)
|
||||
&& !App.exclude_list_home.contains(pattern)){
|
||||
|
||||
|
||||
App.exclude_list_user.add(pattern);
|
||||
}
|
||||
|
||||
|
||||
iterExists = store.iter_next(ref iter);
|
||||
}*/
|
||||
|
||||
|
@ -20,22 +20,22 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using TeeJee.Logging;
|
||||
using TeeJee.FileSystem;
|
||||
using TeeJee.ProcessHelper;
|
||||
using TeeJee.Misc;
|
||||
|
||||
|
||||
public class AppLock : GLib.Object {
|
||||
public string lock_file = "";
|
||||
public string lock_message = "";
|
||||
|
||||
|
||||
public bool create(string app_name, string message){
|
||||
|
||||
var lock_dir = "/var/run/lock/%s".printf(app_name);
|
||||
dir_create(lock_dir);
|
||||
lock_file = path_combine(lock_dir, "lock");
|
||||
|
||||
|
||||
try{
|
||||
var file = File.new_for_path(lock_file);
|
||||
if (file.query_exists()) {
|
||||
@ -72,7 +72,7 @@ public class AppLock : GLib.Object {
|
||||
string current_pid = ((long) Posix.getpid()).to_string();
|
||||
file_write(lock_file, "%s;%s".printf(current_pid, message));
|
||||
}
|
||||
|
||||
|
||||
public void remove(){
|
||||
try{
|
||||
var file = File.new_for_path (lock_file);
|
||||
|
@ -29,7 +29,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public abstract class AsyncTask : GLib.Object{
|
||||
|
||||
|
||||
private string err_line = "";
|
||||
private string out_line = "";
|
||||
private DataOutputStream dos_in;
|
||||
@ -40,7 +40,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
|
||||
private bool stdout_is_open = false;
|
||||
private bool stderr_is_open = false;
|
||||
|
||||
|
||||
protected Pid child_pid;
|
||||
private int input_fd;
|
||||
private int output_fd;
|
||||
@ -52,7 +52,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
protected string log_file = "";
|
||||
|
||||
public bool background_mode = false;
|
||||
|
||||
|
||||
// public
|
||||
public AppStatus status;
|
||||
public string status_line = "";
|
||||
@ -67,40 +67,40 @@ public abstract class AsyncTask : GLib.Object{
|
||||
public int64 prg_bytes_total = 0;
|
||||
public string eta = "";
|
||||
//public bool is_running = false;
|
||||
|
||||
|
||||
// signals
|
||||
public signal void stdout_line_read(string line);
|
||||
public signal void stderr_line_read(string line);
|
||||
public signal void task_complete();
|
||||
|
||||
protected AsyncTask(){
|
||||
|
||||
|
||||
working_dir = TEMP_DIR + "/" + timestamp_for_path();
|
||||
script_file = path_combine(working_dir, "script.sh");
|
||||
log_file = path_combine(working_dir, "task.log");
|
||||
|
||||
//regex = new Gee.HashMap<string,Regex>(); // needs to be initialized again in instance constructor
|
||||
|
||||
|
||||
dir_create(working_dir);
|
||||
}
|
||||
|
||||
|
||||
public bool begin(){
|
||||
|
||||
status = AppStatus.RUNNING;
|
||||
|
||||
|
||||
bool has_started = true;
|
||||
is_terminated = false;
|
||||
finish_called = false;
|
||||
|
||||
|
||||
prg_count = 0;
|
||||
prg_bytes = 0;
|
||||
error_msg = "";
|
||||
|
||||
|
||||
string[] spawn_args = new string[1];
|
||||
spawn_args[0] = script_file;
|
||||
|
||||
|
||||
string[] spawn_env = Environ.get();
|
||||
|
||||
|
||||
try {
|
||||
// start timer
|
||||
timer = new GLib.Timer();
|
||||
@ -121,7 +121,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
set_priority();
|
||||
|
||||
log_debug("AsyncTask: child_pid: %d".printf(child_pid));
|
||||
|
||||
|
||||
// create stream readers
|
||||
UnixOutputStream uos_in = new UnixOutputStream(input_fd, false);
|
||||
UnixInputStream uis_out = new UnixInputStream(output_fd, false);
|
||||
@ -171,7 +171,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
private void read_stdout() {
|
||||
try {
|
||||
stdout_is_open = true;
|
||||
|
||||
|
||||
out_line = dis_out.read_line (null);
|
||||
while (out_line != null) {
|
||||
//log_msg("O: " + out_line);
|
||||
@ -202,16 +202,16 @@ public abstract class AsyncTask : GLib.Object{
|
||||
log_error (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void read_stderr() {
|
||||
try {
|
||||
stderr_is_open = true;
|
||||
|
||||
|
||||
err_line = dis_err.read_line (null);
|
||||
while (err_line != null) {
|
||||
if (!is_terminated && (err_line.length > 0)){
|
||||
error_msg += "%s\n".printf(err_line);
|
||||
|
||||
|
||||
parse_stderr_line(err_line);
|
||||
stderr_line_read(err_line); //signal
|
||||
}
|
||||
@ -222,7 +222,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
|
||||
// dispose stderr
|
||||
if ((dis_err != null) && !dis_err.is_closed()){
|
||||
dis_err.close();
|
||||
dis_err.close();
|
||||
}
|
||||
//dis_err.close();
|
||||
dis_err = null;
|
||||
@ -253,19 +253,19 @@ public abstract class AsyncTask : GLib.Object{
|
||||
log_error (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected abstract void parse_stdout_line(string out_line);
|
||||
|
||||
|
||||
protected abstract void parse_stderr_line(string err_line);
|
||||
|
||||
|
||||
private void finish(){
|
||||
|
||||
|
||||
// finish() gets called by 2 threads but should be executed only once
|
||||
if (finish_called) { return; }
|
||||
finish_called = true;
|
||||
|
||||
|
||||
log_debug("AsyncTask: finish(): enter");
|
||||
|
||||
|
||||
// dispose stdin
|
||||
try{
|
||||
if ((dos_in != null) && !dos_in.is_closed() && !dos_in.is_closing()){
|
||||
@ -277,7 +277,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
//log_error ("AsyncTask.finish(): dos_in.close()");
|
||||
//log_error (e.message);
|
||||
}
|
||||
|
||||
|
||||
dos_in = null;
|
||||
GLib.FileUtils.close(input_fd);
|
||||
|
||||
@ -298,13 +298,13 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
read_exit_code();
|
||||
|
||||
|
||||
status_line = "";
|
||||
err_line = "";
|
||||
out_line = "";
|
||||
|
||||
timer.stop();
|
||||
|
||||
|
||||
finish_task();
|
||||
|
||||
if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) {
|
||||
@ -312,14 +312,14 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
//dir_delete(working_dir);
|
||||
|
||||
|
||||
task_complete(); //signal
|
||||
}
|
||||
|
||||
protected abstract void finish_task();
|
||||
|
||||
protected int read_exit_code(){
|
||||
|
||||
|
||||
exit_code = -1;
|
||||
var path = file_parent(script_file) + "/status";
|
||||
if (file_exists(path)){
|
||||
@ -331,14 +331,14 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
public bool is_running(){
|
||||
|
||||
|
||||
return (status == AppStatus.RUNNING);
|
||||
}
|
||||
|
||||
|
||||
// public actions --------------
|
||||
|
||||
public void pause() {
|
||||
|
||||
|
||||
Pid sub_child_pid;
|
||||
foreach (long pid in get_process_children(child_pid)) {
|
||||
sub_child_pid = (Pid) pid;
|
||||
@ -349,7 +349,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
|
||||
|
||||
Pid sub_child_pid;
|
||||
foreach (long pid in get_process_children(child_pid)) {
|
||||
sub_child_pid = (Pid) pid;
|
||||
@ -360,21 +360,21 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
public void stop(AppStatus status_to_update = AppStatus.CANCELLED) {
|
||||
|
||||
|
||||
// we need to un-freeze the processes before we kill them
|
||||
if (status == AppStatus.PAUSED) {
|
||||
resume();
|
||||
}
|
||||
|
||||
status = status_to_update;
|
||||
|
||||
|
||||
process_quit(child_pid);
|
||||
|
||||
|
||||
log_debug("process_quit: %d".printf(child_pid));
|
||||
}
|
||||
|
||||
public void set_priority() {
|
||||
|
||||
|
||||
if (background_mode){
|
||||
set_priority_value(5);
|
||||
}
|
||||
@ -384,7 +384,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
public void set_priority_value(int prio) {
|
||||
|
||||
|
||||
Pid app_pid = Posix.getpid();
|
||||
process_set_priority (app_pid, prio);
|
||||
|
||||
@ -423,7 +423,7 @@ public abstract class AsyncTask : GLib.Object{
|
||||
}
|
||||
|
||||
public void print_app_status(){
|
||||
|
||||
|
||||
switch(status){
|
||||
case AppStatus.NOT_STARTED:
|
||||
log_debug("status=%s".printf("NOT_STARTED"));
|
||||
@ -465,13 +465,13 @@ public class RsyncTask : AsyncTask{
|
||||
public string source_path = "";
|
||||
public string dest_path = "";
|
||||
public bool verbose = true;
|
||||
|
||||
|
||||
public RsyncTask(string _script_file, string _working_dir, string _log_file){
|
||||
working_dir = _working_dir;
|
||||
script_file = _script_file;
|
||||
log_file = _log_file;
|
||||
}
|
||||
|
||||
|
||||
public void prepare() {
|
||||
string script_text = build_script();
|
||||
save_bash_script_temp(script_text, script_file);
|
||||
@ -504,18 +504,18 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
|
||||
source_path = remove_trailing_slash(source_path);
|
||||
|
||||
|
||||
dest_path = remove_trailing_slash(dest_path);
|
||||
|
||||
|
||||
cmd += " '%s/'".printf(escape_single_quote(source_path));
|
||||
|
||||
cmd += " '%s/'".printf(escape_single_quote(dest_path));
|
||||
|
||||
|
||||
//cmd += " /. \"%s\"".printf(sync_path + "/localhost/");
|
||||
|
||||
return script.str;
|
||||
}
|
||||
|
||||
|
||||
// execution ----------------------------
|
||||
|
||||
public void execute() {
|
||||
@ -525,8 +525,8 @@ public class RsyncTask : AsyncTask{
|
||||
begin();
|
||||
|
||||
if (status == AppStatus.RUNNING){
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -534,15 +534,15 @@ public class RsyncTask : AsyncTask{
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(out_line);
|
||||
}
|
||||
|
||||
|
||||
public override void parse_stderr_line(string err_line){
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(err_line);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using TeeJee.Logging;
|
||||
using TeeJee.FileSystem;
|
||||
using TeeJee.ProcessHelper;
|
||||
@ -33,7 +33,7 @@ public class CronTab : GLib.Object {
|
||||
public static void clear_cached_text(){
|
||||
crontab_text = null;
|
||||
}
|
||||
|
||||
|
||||
public static string crontab_read_all(string user_name = ""){
|
||||
string std_out, std_err;
|
||||
|
||||
@ -43,9 +43,9 @@ public class CronTab : GLib.Object {
|
||||
}
|
||||
|
||||
log_debug(cmd);
|
||||
|
||||
|
||||
int ret_val = exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
if (ret_val != 0){
|
||||
log_debug(_("Failed to read cron tab"));
|
||||
return "";
|
||||
@ -56,7 +56,7 @@ public class CronTab : GLib.Object {
|
||||
}
|
||||
|
||||
public static bool has_job(string entry, bool partial_match, bool use_cached_text){
|
||||
|
||||
|
||||
// read crontab file
|
||||
string tab = "";
|
||||
if (use_cached_text && (crontab_text != null)){
|
||||
@ -84,9 +84,9 @@ public class CronTab : GLib.Object {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static bool add_job(string entry, bool use_cached_text){
|
||||
|
||||
|
||||
// read crontab file
|
||||
string tab = "";
|
||||
if (use_cached_text && (crontab_text != null)){
|
||||
@ -96,7 +96,7 @@ public class CronTab : GLib.Object {
|
||||
crontab_text = crontab_read_all();
|
||||
tab = crontab_text;
|
||||
}
|
||||
|
||||
|
||||
var lines = new Gee.ArrayList<string>();
|
||||
foreach(string line in tab.split("\n")){
|
||||
lines.add(line);
|
||||
@ -139,7 +139,7 @@ public class CronTab : GLib.Object {
|
||||
}
|
||||
|
||||
public static bool remove_job(string entry, bool use_regex, bool use_cached_text){
|
||||
|
||||
|
||||
// read crontab file
|
||||
string tab = "";
|
||||
if (use_cached_text && (crontab_text != null)){
|
||||
@ -149,12 +149,12 @@ public class CronTab : GLib.Object {
|
||||
crontab_text = crontab_read_all();
|
||||
tab = crontab_text;
|
||||
}
|
||||
|
||||
|
||||
var lines = new Gee.ArrayList<string>();
|
||||
foreach(string line in tab.split("\n")){
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
|
||||
Regex regex = null;
|
||||
|
||||
if (use_regex){
|
||||
@ -175,7 +175,7 @@ public class CronTab : GLib.Object {
|
||||
}
|
||||
|
||||
if (use_regex && (regex != null)){
|
||||
|
||||
|
||||
MatchInfo match;
|
||||
if (regex.match(line, 0, out match)) {
|
||||
lines.remove(line);
|
||||
@ -225,7 +225,7 @@ public class CronTab : GLib.Object {
|
||||
log_error(_("File not found") + ": %s".printf(file_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var cmd = "crontab";
|
||||
if (user_name.length > 0){
|
||||
cmd += " -u %s".printf(user_name);
|
||||
@ -245,12 +245,12 @@ public class CronTab : GLib.Object {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool export(string file_path, string user_name = ""){
|
||||
if (file_exists(file_path)){
|
||||
file_delete(file_path);
|
||||
}
|
||||
|
||||
|
||||
bool ok = file_write(file_path, crontab_read_all(user_name));
|
||||
|
||||
if (!ok){
|
||||
@ -268,11 +268,11 @@ public class CronTab : GLib.Object {
|
||||
}
|
||||
|
||||
public static bool add_script_file(string file_name, string cron_dir_type, string text, bool stop_cron_emails){
|
||||
|
||||
|
||||
/* Note:
|
||||
* cron.d and cron.hourly are managed by cron so it expects entries in crontab format
|
||||
* minute hour day_of_month month day_of_week user command
|
||||
*
|
||||
*
|
||||
* cron.{daily|weekly|monthly} are read by anacron. scripts placed here should have commands only.
|
||||
* */
|
||||
|
||||
@ -310,7 +310,7 @@ public class CronTab : GLib.Object {
|
||||
chmod(file_path, "644");
|
||||
|
||||
log_msg(_("Added cron task") + ": %s".printf(file_path));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -334,11 +334,11 @@ public class CronTab : GLib.Object {
|
||||
if (!file_exists(file_path)){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
file_delete(file_path);
|
||||
|
||||
log_msg(_("Removed cron task") + ": %s".printf(file_path));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class CryptTabEntry : GLib.Object{
|
||||
|
||||
|
||||
public bool is_comment = false;
|
||||
public bool is_empty_line = false;
|
||||
|
||||
@ -57,7 +57,7 @@ public class CryptTabEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public static Gee.ArrayList<CryptTabEntry> read_file(string file_path){
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<CryptTabEntry>();
|
||||
|
||||
if (!file_exists(file_path)){ return list; }
|
||||
@ -106,7 +106,7 @@ public class CryptTabEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public static string write_file(Gee.ArrayList<CryptTabEntry> entries, string file_path, bool keep_comments_and_empty_lines = true){
|
||||
|
||||
|
||||
string text = "";
|
||||
foreach(var entry in entries){
|
||||
if (entry.is_comment || entry.is_empty_line){
|
||||
@ -124,29 +124,29 @@ public class CryptTabEntry : GLib.Object{
|
||||
if (file_exists(file_path)){
|
||||
file_delete(file_path);
|
||||
}
|
||||
|
||||
|
||||
file_write(file_path, text);
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public void append_option(string option){
|
||||
|
||||
|
||||
if (!options.contains(option)){
|
||||
options += ",%s".printf(option);
|
||||
}
|
||||
|
||||
|
||||
if(options.has_prefix(",")){
|
||||
options = options[1:options.length];
|
||||
}
|
||||
|
||||
|
||||
options = options.strip();
|
||||
}
|
||||
|
||||
public void remove_option(string option){
|
||||
|
||||
|
||||
options = options.replace(option,"").strip();
|
||||
|
||||
|
||||
if(options.has_prefix(",")){
|
||||
options = options[1:options.length];
|
||||
}
|
||||
@ -160,13 +160,13 @@ public class CryptTabEntry : GLib.Object{
|
||||
|
||||
public static CryptTabEntry? find_entry_by_uuid(
|
||||
Gee.ArrayList<CryptTabEntry> entries, string uuid){
|
||||
|
||||
|
||||
foreach(var entry in entries){
|
||||
if (entry.device_uuid == uuid){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -37,17 +37,17 @@ public class DeleteFileTask : AsyncTask{
|
||||
public bool use_rsync = false;
|
||||
|
||||
//private
|
||||
private string source_path = "";
|
||||
|
||||
private string source_path = "";
|
||||
|
||||
// regex
|
||||
private Gee.HashMap<string, Regex> regex_list;
|
||||
|
||||
|
||||
// status
|
||||
public int64 status_line_count = 0;
|
||||
public int64 total_size = 0;
|
||||
public string status_message = "";
|
||||
public string time_remaining = "";
|
||||
|
||||
|
||||
public DeleteFileTask(){
|
||||
init_regular_expressions();
|
||||
}
|
||||
@ -56,9 +56,9 @@ public class DeleteFileTask : AsyncTask{
|
||||
if (regex_list != null){
|
||||
return; // already initialized
|
||||
}
|
||||
|
||||
|
||||
regex_list = new Gee.HashMap<string,Regex>();
|
||||
|
||||
|
||||
try {
|
||||
|
||||
regex_list["rsync-deleted"] = new Regex(
|
||||
@ -69,7 +69,7 @@ public class DeleteFileTask : AsyncTask{
|
||||
log_error (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void prepare() {
|
||||
string script_text = build_script();
|
||||
log_debug(script_text);
|
||||
@ -108,7 +108,7 @@ public class DeleteFileTask : AsyncTask{
|
||||
|
||||
source_path = remove_trailing_slash(source_path);
|
||||
dest_path = remove_trailing_slash(dest_path);
|
||||
|
||||
|
||||
cmd += " '%s/'".printf(escape_single_quote(source_path));
|
||||
cmd += " '%s/'".printf(escape_single_quote(dest_path));
|
||||
}
|
||||
@ -133,16 +133,16 @@ public class DeleteFileTask : AsyncTask{
|
||||
public void execute() {
|
||||
|
||||
status = AppStatus.RUNNING;
|
||||
|
||||
|
||||
log_debug("RsyncTask:execute()");
|
||||
|
||||
|
||||
prepare();
|
||||
|
||||
begin();
|
||||
|
||||
if (status == AppStatus.RUNNING){
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,15 +150,15 @@ public class DeleteFileTask : AsyncTask{
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(out_line);
|
||||
}
|
||||
|
||||
|
||||
public override void parse_stderr_line(string err_line){
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(err_line);
|
||||
}
|
||||
|
||||
@ -173,16 +173,16 @@ public class DeleteFileTask : AsyncTask{
|
||||
prg_count = status_line_count;
|
||||
progress = (prg_count * 1.0) / prg_count_total;
|
||||
}
|
||||
|
||||
|
||||
MatchInfo match;
|
||||
if (regex_list["rsync-deleted"].match(line, 0, out match)) {
|
||||
|
||||
|
||||
//log_debug("matched: rsync-deleted:%s".printf(line));
|
||||
|
||||
status_line = match.fetch(1).split(" -> ")[0].strip();
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
//log_debug("matched: else:%s".printf(line));
|
||||
|
||||
status_line = line.strip();
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Functions and classes for handling disk partitions */
|
||||
|
||||
using TeeJee.Logging;
|
||||
@ -40,7 +40,7 @@ public class Device : GLib.Object{
|
||||
public static double KiB = 1024;
|
||||
public static double MiB = 1024 * KiB;
|
||||
public static double GiB = 1024 * MiB;
|
||||
|
||||
|
||||
public string device = "";
|
||||
public string name = "";
|
||||
public string kname = "";
|
||||
@ -51,7 +51,7 @@ public class Device : GLib.Object{
|
||||
public string label = "";
|
||||
public string partuuid = "";
|
||||
public string partlabel = "";
|
||||
|
||||
|
||||
public int major = -1;
|
||||
public int minor = -1;
|
||||
|
||||
@ -73,11 +73,11 @@ public class Device : GLib.Object{
|
||||
|
||||
public bool removable = false;
|
||||
public bool read_only = false;
|
||||
|
||||
|
||||
public uint64 size_bytes = 0;
|
||||
public uint64 used_bytes = 0;
|
||||
public uint64 available_bytes = 0;
|
||||
|
||||
|
||||
public string used_percent = "";
|
||||
public string dist_info = "";
|
||||
public Gee.ArrayList<MountEntry> mount_points;
|
||||
@ -88,7 +88,7 @@ public class Device : GLib.Object{
|
||||
|
||||
private static string lsblk_version = "";
|
||||
private static bool lsblk_is_ancient = false;
|
||||
|
||||
|
||||
private static Gee.ArrayList<Device> device_list;
|
||||
|
||||
public Device(){
|
||||
@ -116,7 +116,7 @@ public class Device : GLib.Object{
|
||||
lsblk_is_ancient = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public uint64 free_bytes{
|
||||
get{
|
||||
return (used_bytes == 0) ? 0 : (size_bytes - used_bytes);
|
||||
@ -130,7 +130,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
else if (size_bytes > 0){
|
||||
return "%.1f GB".printf(size_bytes / GB);
|
||||
}
|
||||
}
|
||||
else{
|
||||
return "";
|
||||
}
|
||||
@ -156,7 +156,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
public bool is_mounted_at_path(string subvolname, string mount_path){
|
||||
|
||||
|
||||
foreach (var mnt in mount_points){
|
||||
if (mnt.mount_point == mount_path){
|
||||
if (subvolname.length == 0){
|
||||
@ -169,7 +169,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -215,13 +215,13 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
public Device? first_linux_child(){
|
||||
|
||||
|
||||
foreach(var child in children){
|
||||
if (child.has_linux_filesystem()){
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
// static --------------------------------
|
||||
|
||||
|
||||
public static Gee.ArrayList<Device> get_filesystems(bool get_space = true, bool get_mounts = true){
|
||||
|
||||
/* Returns list of block devices
|
||||
@ -268,7 +268,7 @@ public class Device : GLib.Object{
|
||||
//print_device_mounts(list);
|
||||
|
||||
log_debug("Device: get_filesystems(): %d".printf(list.size));
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -298,7 +298,7 @@ public class Device : GLib.Object{
|
||||
if (dev.pkname.length == 0){ return; }
|
||||
|
||||
var top_kname = dev.pkname;
|
||||
|
||||
|
||||
foreach (var part in list){
|
||||
if (part.kname == top_kname){
|
||||
if (part.pkname.length > 0){
|
||||
@ -374,7 +374,7 @@ public class Device : GLib.Object{
|
||||
public static Gee.ArrayList<Device> get_block_devices_using_lsblk(string dev_name = ""){
|
||||
|
||||
//log_debug("Device: get_block_devices_using_lsblk()");
|
||||
|
||||
|
||||
/* Returns list of mounted partitions using 'lsblk' command
|
||||
Populates device, type, uuid, label */
|
||||
|
||||
@ -439,10 +439,10 @@ public class Device : GLib.Object{
|
||||
Device pi = new Device();
|
||||
|
||||
int pos = 0;
|
||||
|
||||
|
||||
pi.name = match.fetch(++pos).strip();
|
||||
pi.kname = match.fetch(++pos).strip();
|
||||
|
||||
|
||||
pi.label = match.fetch(++pos); // don't strip; labels can have leading or trailing spaces
|
||||
pi.uuid = match.fetch(++pos).strip();
|
||||
|
||||
@ -470,12 +470,12 @@ public class Device : GLib.Object{
|
||||
pi.major = int.parse(txt.split(":")[0]);
|
||||
pi.minor = int.parse(txt.split(":")[1]);
|
||||
}
|
||||
|
||||
|
||||
if (!lsblk_is_ancient){
|
||||
|
||||
|
||||
pi.partlabel = match.fetch(++pos); // don't strip; labels can have leading or trailing spaces
|
||||
pi.partuuid = match.fetch(++pos).strip();
|
||||
|
||||
|
||||
pi.pkname = match.fetch(++pos).strip();
|
||||
pi.vendor = match.fetch(++pos).strip();
|
||||
pi.serial = match.fetch(++pos).strip();
|
||||
@ -718,7 +718,7 @@ public class Device : GLib.Object{
|
||||
if (LOG_DEBUG){
|
||||
log_debug(cmd);
|
||||
}
|
||||
|
||||
|
||||
ret_val = exec_script_sync(cmd, out std_out, out std_err);
|
||||
if (ret_val != 0){
|
||||
var msg = "blkid: " + _("Failed to get partition list");
|
||||
@ -793,7 +793,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
log_debug("Device: get_block_devices_using_blkid(): %d".printf(list.size));
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -891,7 +891,7 @@ public class Device : GLib.Object{
|
||||
// resolve device name --------------------
|
||||
|
||||
pi.device = resolve_device_name(pi.device);
|
||||
|
||||
|
||||
// get uuid ---------------------------
|
||||
|
||||
pi.uuid = get_device_uuid(pi.device);
|
||||
@ -902,7 +902,7 @@ public class Device : GLib.Object{
|
||||
list.add(pi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log_debug("Device: get_disk_space_using_df(): %d".printf(list.size));
|
||||
|
||||
return list;
|
||||
@ -1050,7 +1050,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
log_debug("Device: get_mounted_filesystems_using_mtab(): %d".printf(list.size));
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -1067,18 +1067,18 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
public static Device? get_device_by_path(string path_to_check){
|
||||
|
||||
|
||||
var list = Device.get_disk_space_using_df(path_to_check);
|
||||
|
||||
|
||||
if (list.size > 0){
|
||||
return list[0];
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static string get_device_uuid(string device){
|
||||
|
||||
|
||||
if (device_list == null){
|
||||
device_list = get_block_devices_using_lsblk();
|
||||
}
|
||||
@ -1087,7 +1087,7 @@ public class Device : GLib.Object{
|
||||
return dev.uuid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -1106,7 +1106,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
var list_mtab = get_mounted_filesystems_using_mtab();
|
||||
|
||||
|
||||
var dev = find_device_in_list(list_mtab, uuid);
|
||||
|
||||
if (dev != null){
|
||||
@ -1155,20 +1155,20 @@ public class Device : GLib.Object{
|
||||
public static Device? find_device_in_list(Gee.ArrayList<Device> list, string _dev_alias){
|
||||
|
||||
string dev_alias = _dev_alias;
|
||||
|
||||
|
||||
if (dev_alias.down().has_prefix("uuid=")){
|
||||
|
||||
|
||||
dev_alias = dev_alias.split("=",2)[1].strip().down();
|
||||
}
|
||||
else if (file_exists(dev_alias) && file_is_symlink(dev_alias)){
|
||||
|
||||
var link_path = file_get_symlink_target(dev_alias);
|
||||
|
||||
|
||||
dev_alias = link_path.replace("../../../","/dev/").replace("../../","/dev/").replace("../","/dev/");
|
||||
}
|
||||
|
||||
foreach(var dev in list){
|
||||
|
||||
|
||||
if (dev.device == dev_alias){
|
||||
return dev;
|
||||
}
|
||||
@ -1206,9 +1206,9 @@ public class Device : GLib.Object{
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void copy_fields_from(Device dev2){
|
||||
|
||||
|
||||
this.device = dev2.device;
|
||||
this.name = dev2.name;
|
||||
this.kname = dev2.kname;
|
||||
@ -1216,14 +1216,14 @@ public class Device : GLib.Object{
|
||||
this.label = dev2.label;
|
||||
this.uuid = dev2.uuid;
|
||||
this.mapped_name = dev2.mapped_name;
|
||||
|
||||
|
||||
this.type = dev2.type;
|
||||
this.fstype = dev2.fstype;
|
||||
|
||||
this.size_bytes = dev2.size_bytes;
|
||||
this.used_bytes = dev2.used_bytes;
|
||||
this.available_bytes = dev2.available_bytes;
|
||||
|
||||
|
||||
this.mount_points = dev2.mount_points;
|
||||
this.symlinks = dev2.symlinks;
|
||||
this.parent = dev2.parent;
|
||||
@ -1239,9 +1239,9 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
public Device? query_changes(){
|
||||
|
||||
|
||||
Device dev_new = null;
|
||||
|
||||
|
||||
foreach (var dev in get_block_devices_using_lsblk()){
|
||||
if (uuid.length > 0){
|
||||
if (dev.uuid == uuid){
|
||||
@ -1256,18 +1256,18 @@ public class Device : GLib.Object{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return dev_new;
|
||||
}
|
||||
|
||||
|
||||
public void query_disk_space(){
|
||||
|
||||
/* Updates disk space info and returns the given Device object */
|
||||
|
||||
var list_df = get_disk_space_using_df(device);
|
||||
|
||||
|
||||
var dev_df = find_device_in_list(list_df, uuid);
|
||||
|
||||
|
||||
if (dev_df != null){
|
||||
// update dev fields
|
||||
size_bytes = dev_df.size_bytes;
|
||||
@ -1278,14 +1278,14 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
// mounting ---------------------------------
|
||||
|
||||
|
||||
public static bool automount_udisks(string dev_name_or_uuid, Gtk.Window? parent_window){
|
||||
|
||||
|
||||
if (dev_name_or_uuid.length == 0){
|
||||
log_error(_("Device name is empty!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var cmd = "udisksctl mount -b '%s'".printf(dev_name_or_uuid);
|
||||
log_debug(cmd);
|
||||
int status = Posix.system(cmd);
|
||||
@ -1312,11 +1312,11 @@ public class Device : GLib.Object{
|
||||
|
||||
var cmd = "udisksctl loop-setup -r -f '%s'".printf(
|
||||
escape_single_quote(iso_file_path));
|
||||
|
||||
|
||||
log_debug(cmd);
|
||||
string std_out, std_err;
|
||||
int exit_code = exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
if (exit_code == 0){
|
||||
log_msg("%s".printf(std_out));
|
||||
//log_msg("%s".printf(std_err));
|
||||
@ -1328,7 +1328,7 @@ public class Device : GLib.Object{
|
||||
|
||||
loop_device = std_out.split(" as ")[1].replace(".","").strip();
|
||||
log_msg("loop_device: %s".printf(loop_device));
|
||||
|
||||
|
||||
var list = get_block_devices_using_lsblk();
|
||||
foreach(var dev in list){
|
||||
if ((dev.pkname == loop_device.replace("/dev/","")) && (dev.fstype == "iso9660")){
|
||||
@ -1337,7 +1337,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1347,7 +1347,7 @@ public class Device : GLib.Object{
|
||||
log_error(_("Device name is empty!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var cmd = "udisksctl unmount -b '%s'".printf(dev_name_or_uuid);
|
||||
log_debug(cmd);
|
||||
int status = Posix.system(cmd);
|
||||
@ -1358,12 +1358,12 @@ public class Device : GLib.Object{
|
||||
gtk_messagebox("Error", msg, parent_window, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
public static Device? luks_unlock(
|
||||
Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window,
|
||||
Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window,
|
||||
out string message, out string details){
|
||||
|
||||
/* Unlocks a LUKS device using provided passphrase.
|
||||
@ -1371,10 +1371,10 @@ public class Device : GLib.Object{
|
||||
* Displays a GTK prompt if parent_window is not null
|
||||
* Otherwise prompts user on terminal with a timeout of 20 secsonds
|
||||
* */
|
||||
|
||||
|
||||
Device unlocked_device = null;
|
||||
string std_out = "", std_err = "";
|
||||
|
||||
|
||||
// check if not encrypted
|
||||
if (!luks_device.fstype.contains("luks") && !luks_device.fstype.contains("crypt")){
|
||||
message = _("This device is not encrypted");
|
||||
@ -1389,7 +1389,7 @@ public class Device : GLib.Object{
|
||||
unlocked_device = part;
|
||||
message = _("Device is unlocked");
|
||||
details = _("Unlocked device is mapped to '%s'").printf(part.mapped_name);
|
||||
return part;
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1403,11 +1403,11 @@ public class Device : GLib.Object{
|
||||
if (parent_window == null){
|
||||
|
||||
// console mode
|
||||
|
||||
|
||||
if ((luks_pass == null) || (luks_pass.length == 0)){
|
||||
|
||||
// prompt user on terminal and unlock, else timeout after 20 secs
|
||||
|
||||
|
||||
var counter = new TimeoutCounter();
|
||||
counter.kill_process_on_timeout("cryptsetup", 20, true);
|
||||
string cmd = "cryptsetup luksOpen '%s' '%s'".printf(luks_device.device, luks_name);
|
||||
@ -1416,7 +1416,7 @@ public class Device : GLib.Object{
|
||||
Posix.system(cmd);
|
||||
counter.stop();
|
||||
log_msg("");
|
||||
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
@ -1426,7 +1426,7 @@ public class Device : GLib.Object{
|
||||
escape_single_quote(luks_pass), luks_device.device, luks_name);
|
||||
|
||||
log_debug(cmd.replace(escape_single_quote(luks_pass), "**PASSWORD**"));
|
||||
|
||||
|
||||
int status = exec_script_sync(cmd, out std_out, out std_err, false, true);
|
||||
|
||||
switch (status){
|
||||
@ -1449,7 +1449,7 @@ public class Device : GLib.Object{
|
||||
// show input prompt
|
||||
|
||||
log_debug("Prompting user for passphrase..");
|
||||
|
||||
|
||||
luks_pass = gtk_inputbox(
|
||||
_("Encrypted Device"),
|
||||
_("Enter passphrase to unlock '%s'").printf(luks_device.name),
|
||||
@ -1472,7 +1472,7 @@ public class Device : GLib.Object{
|
||||
escape_single_quote(luks_pass), luks_device.device, luks_name);
|
||||
|
||||
log_debug(cmd.replace(escape_single_quote(luks_pass), "**PASSWORD**"));
|
||||
|
||||
|
||||
int status = exec_script_sync(cmd, out std_out, out std_err, false, true);
|
||||
|
||||
switch (status){
|
||||
@ -1484,7 +1484,7 @@ public class Device : GLib.Object{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// find unlocked device
|
||||
@ -1492,7 +1492,7 @@ public class Device : GLib.Object{
|
||||
foreach(var part in list){
|
||||
if (part.pkname == luks_device.kname){
|
||||
unlocked_device = part;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1515,7 +1515,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
public static bool luks_lock(string kname, Gtk.Window? parent_window){
|
||||
|
||||
|
||||
var cmd = "cryptsetup luksClose %s".printf(kname);
|
||||
|
||||
log_debug(cmd);
|
||||
@ -1524,18 +1524,18 @@ public class Device : GLib.Object{
|
||||
int status = exec_script_sync(cmd, out std_out, out std_err, false, true);
|
||||
log_msg(std_out);
|
||||
log_msg(std_err);
|
||||
|
||||
|
||||
if (status != 0){
|
||||
if (parent_window != null){
|
||||
string msg = "Failed to lock device: %s".printf(kname);
|
||||
gtk_messagebox("Error", msg, parent_window, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (status == 0);
|
||||
|
||||
|
||||
/*log_debug(cmd);
|
||||
|
||||
|
||||
if (bash_admin_shell != null){
|
||||
int status = bash_admin_shell.execute(cmd);
|
||||
return (status == 0);
|
||||
@ -1551,7 +1551,7 @@ public class Device : GLib.Object{
|
||||
|
||||
/*
|
||||
* Mounts specified device at specified mount point.
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
string cmd = "";
|
||||
@ -1563,7 +1563,7 @@ public class Device : GLib.Object{
|
||||
string uuid = "";
|
||||
|
||||
// resolve uuid and device name ----------
|
||||
|
||||
|
||||
if (dev_name_or_uuid.has_prefix("/dev")){
|
||||
device = dev_name_or_uuid;
|
||||
uuid = get_device_uuid(dev_name_or_uuid);
|
||||
@ -1575,7 +1575,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
// check if already mounted --------------
|
||||
|
||||
|
||||
var mps = Device.get_device_mount_points(dev_name_or_uuid);
|
||||
|
||||
log_debug("------------------");
|
||||
@ -1584,7 +1584,7 @@ public class Device : GLib.Object{
|
||||
log_debug(mp.mount_point);
|
||||
}
|
||||
log_debug("------------------");
|
||||
|
||||
|
||||
foreach(var mp in mps){
|
||||
if ((mp.mount_point == mount_point) && mp.mount_options.contains(mount_options)){
|
||||
if (!silent){
|
||||
@ -1605,7 +1605,7 @@ public class Device : GLib.Object{
|
||||
unmount(mount_point);
|
||||
|
||||
// mount the device -------------------
|
||||
|
||||
|
||||
if (mount_options.length > 0){
|
||||
cmd = "mount -o %s \"%s\" \"%s\"".printf(mount_options, device, mount_point);
|
||||
}
|
||||
@ -1630,7 +1630,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// check if mounted successfully ------------------
|
||||
|
||||
/*mps = Device.get_device_mount_points(dev_name_or_uuid);
|
||||
@ -1783,7 +1783,7 @@ public class Device : GLib.Object{
|
||||
if (has_parent() && (parent.type == "part")){
|
||||
text += " (%s)".printf(pkname);
|
||||
}
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@ -1795,7 +1795,7 @@ public class Device : GLib.Object{
|
||||
if (has_parent() && (parent.type == "part")){
|
||||
text += " (%s)".printf(parent.kname);
|
||||
}
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@ -1830,13 +1830,13 @@ public class Device : GLib.Object{
|
||||
|
||||
return s.strip();
|
||||
}
|
||||
|
||||
|
||||
public string description_simple(){
|
||||
return description_simple_formatted().replace("<b>","").replace("</b>","");
|
||||
}
|
||||
|
||||
|
||||
public string description_simple_formatted(){
|
||||
|
||||
|
||||
string s = "";
|
||||
|
||||
if (type == "disk"){
|
||||
@ -1902,7 +1902,7 @@ public class Device : GLib.Object{
|
||||
s += (uuid.length > 0) ? " ~ " + uuid : "";
|
||||
s += (fstype.length > 0) ? " ~ " + fstype : "";
|
||||
s += (used.length > 0) ? " ~ " + used + " / " + size + " GB used (" + used_percent + ")" : "";
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1941,7 +1941,7 @@ public class Device : GLib.Object{
|
||||
else{
|
||||
tt += "%-15s: %s\n".printf(_("Device"),
|
||||
(mapped_name.length > 0) ? "%s → %s".printf(device, mapped_name) : device);
|
||||
|
||||
|
||||
if (has_parent()){
|
||||
tt += "%-15s: %s\n".printf(_("Parent Device"), parent.device);
|
||||
}
|
||||
@ -1949,10 +1949,10 @@ public class Device : GLib.Object{
|
||||
tt += "%-15s: %s\n".printf(_("Type"),type);
|
||||
tt += "%-15s: %s\n".printf(_("Filesystem"),fstype);
|
||||
tt += "%-15s: %s\n".printf(_("Label"),label);
|
||||
|
||||
|
||||
tt += "%-15s: %s\n".printf(_("Size"),
|
||||
(size_bytes > 0) ? format_file_size(size_bytes) : "N/A");
|
||||
|
||||
|
||||
tt += "%-15s: %s\n".printf(_("Used"),
|
||||
(used_bytes > 0) ? format_file_size(used_bytes) : "N/A");
|
||||
|
||||
@ -1965,13 +1965,13 @@ public class Device : GLib.Object{
|
||||
// testing -----------------------------------
|
||||
|
||||
public static void test_all(){
|
||||
|
||||
|
||||
var list = get_block_devices_using_lsblk();
|
||||
log_msg("\n> get_block_devices_using_lsblk()");
|
||||
print_device_list(list);
|
||||
|
||||
log_msg("");
|
||||
|
||||
|
||||
//list = get_block_devices_using_blkid();
|
||||
//log_msg("\nget_block_devices_using_blkid()\n");
|
||||
//print_device_list(list);
|
||||
@ -1993,14 +1993,14 @@ public class Device : GLib.Object{
|
||||
print_device_list(list);
|
||||
print_device_mounts(list);
|
||||
print_device_disk_space(list);
|
||||
|
||||
|
||||
log_msg("");
|
||||
}
|
||||
|
||||
public static void print_device_list(Gee.ArrayList<Device> list){
|
||||
|
||||
log_debug("");
|
||||
|
||||
|
||||
log_debug("%-12s ,%-5s ,%-5s ,%-36s ,%s".printf(
|
||||
"device",
|
||||
"pkname",
|
||||
@ -2021,7 +2021,7 @@ public class Device : GLib.Object{
|
||||
}
|
||||
|
||||
log_debug("");
|
||||
|
||||
|
||||
/*
|
||||
log_debug("%-20s %-20s %s %s %s %s".printf(
|
||||
"device",
|
||||
@ -2046,7 +2046,7 @@ public class Device : GLib.Object{
|
||||
|
||||
log_debug("");
|
||||
*/
|
||||
|
||||
|
||||
/*log_debug("%-20s %-10s %-15s %-3s %-3s %15s %15s".printf(
|
||||
"device",
|
||||
"type",
|
||||
@ -2076,7 +2076,7 @@ public class Device : GLib.Object{
|
||||
public static void print_device_mounts(Gee.ArrayList<Device> list){
|
||||
|
||||
log_debug("");
|
||||
|
||||
|
||||
log_debug("%-15s %s".printf(
|
||||
"device",
|
||||
//"fstype",
|
||||
@ -2100,7 +2100,7 @@ public class Device : GLib.Object{
|
||||
//dev.fstype,
|
||||
mps
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
log_debug("");
|
||||
@ -2108,7 +2108,7 @@ public class Device : GLib.Object{
|
||||
|
||||
public static void print_device_disk_space(Gee.ArrayList<Device> list){
|
||||
log_debug("");
|
||||
|
||||
|
||||
log_debug("%-15s %-12s %15s %15s %15s %10s".printf(
|
||||
"device",
|
||||
"fstype",
|
||||
|
@ -35,7 +35,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
|
||||
|
||||
public string file_name = "";
|
||||
public string file_location = "";
|
||||
public string file_path = "";
|
||||
@ -46,7 +46,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
public string owner_user = "";
|
||||
public string owner_group = "";
|
||||
public string content_type = "";
|
||||
public string file_status = "";
|
||||
public string file_status = "";
|
||||
|
||||
public bool is_selected = false;
|
||||
public bool is_symlink = false;
|
||||
@ -59,7 +59,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
public GLib.Icon icon;
|
||||
|
||||
// contructors -------------------------------
|
||||
|
||||
|
||||
public FileItem(string name) {
|
||||
file_name = name;
|
||||
}
|
||||
@ -79,7 +79,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
}
|
||||
|
||||
// properties -------------------------------------------------
|
||||
|
||||
|
||||
public int64 size {
|
||||
get{
|
||||
return _size;
|
||||
@ -106,11 +106,11 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// instance methods -------------------------------------------
|
||||
|
||||
|
||||
public void query_file_info() {
|
||||
|
||||
|
||||
try {
|
||||
FileInfo info;
|
||||
File file = File.parse_name (file_path);
|
||||
@ -118,7 +118,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
if (file.query_exists()) {
|
||||
|
||||
// get type without following symlinks
|
||||
|
||||
|
||||
info = file.query_info("%s,%s,%s".printf(
|
||||
FileAttribute.STANDARD_TYPE,
|
||||
FileAttribute.STANDARD_ICON,
|
||||
@ -128,14 +128,14 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
var item_file_type = info.get_file_type();
|
||||
|
||||
this.icon = info.get_icon();
|
||||
|
||||
|
||||
if (item_file_type == FileType.SYMBOLIC_LINK) {
|
||||
//this.icon = GLib.Icon.new_for_string("emblem-symbolic-link");
|
||||
this.is_symlink = true;
|
||||
this.symlink_target = info.get_symlink_target();
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
this.is_symlink = false;
|
||||
this.symlink_target = "";
|
||||
|
||||
@ -143,7 +143,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
//log_msg(file_basename(file_path) + " (gicon): " + icon.to_string());
|
||||
|
||||
/*var themed_icon = (GLib.ThemedIcon) icon;
|
||||
|
||||
|
||||
string txt = "-> ";
|
||||
foreach(var name in themed_icon.names){
|
||||
txt += ", " + name;
|
||||
@ -153,7 +153,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
}
|
||||
|
||||
// get file info - follow symlinks
|
||||
|
||||
|
||||
info = file.query_info("%s,%s,%s,%s,%s,%s,%s,%s".printf(
|
||||
FileAttribute.STANDARD_TYPE,
|
||||
FileAttribute.STANDARD_SIZE,
|
||||
@ -175,7 +175,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
|
||||
// content type
|
||||
this.content_type = info.get_content_type();
|
||||
|
||||
|
||||
// size
|
||||
if (!this.is_symlink && (this.file_type == FileType.REGULAR)) {
|
||||
this._size = info.get_size();
|
||||
@ -189,7 +189,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
|
||||
// owner_group
|
||||
this.owner_group = info.get_attribute_string(FileAttribute.OWNER_GROUP);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Error e) {
|
||||
@ -198,7 +198,7 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
}
|
||||
|
||||
public void query_file_info_basic() {
|
||||
|
||||
|
||||
try {
|
||||
FileInfo info;
|
||||
File file = File.parse_name(file_path);
|
||||
@ -206,12 +206,12 @@ public class FileItem : GLib.Object,Gee.Comparable<FileItem> {
|
||||
if (file.query_exists()) {
|
||||
|
||||
// get type and icon -- follow symlinks
|
||||
|
||||
|
||||
info = file.query_info("%s,%s".printf(
|
||||
FileAttribute.STANDARD_TYPE,
|
||||
FileAttribute.STANDARD_ICON
|
||||
), 0);
|
||||
|
||||
|
||||
this.icon = info.get_icon();
|
||||
|
||||
this.file_type = info.get_file_type();
|
||||
|
@ -30,10 +30,10 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class FsTabEntry : GLib.Object{
|
||||
|
||||
|
||||
public bool is_comment = false;
|
||||
public bool is_empty_line = false;
|
||||
|
||||
|
||||
public string device_string = "";
|
||||
public string mount_point = "";
|
||||
public string type = "";
|
||||
@ -57,17 +57,17 @@ public class FsTabEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public static Gee.ArrayList<FsTabEntry> read_file(string file_path){
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<FsTabEntry>();
|
||||
|
||||
if (!file_exists(file_path)){ return list; }
|
||||
|
||||
string text = file_read(file_path);
|
||||
|
||||
|
||||
string[] lines = text.split("\n");
|
||||
|
||||
|
||||
foreach(string line in lines){
|
||||
|
||||
|
||||
var entry = new FsTabEntry();
|
||||
list.add(entry);
|
||||
|
||||
@ -75,24 +75,24 @@ public class FsTabEntry : GLib.Object{
|
||||
entry.is_empty_line = (line.strip().length == 0);
|
||||
|
||||
if (entry.is_comment){
|
||||
|
||||
|
||||
entry.line = line;
|
||||
}
|
||||
else if (entry.is_empty_line){
|
||||
|
||||
|
||||
entry.line = "";
|
||||
}
|
||||
else{
|
||||
entry.line = line;
|
||||
|
||||
string[] parts = line.replace("\t"," ").split(" ");
|
||||
|
||||
|
||||
int part_num = -1;
|
||||
|
||||
|
||||
foreach(string part in parts){
|
||||
|
||||
|
||||
if (part.strip().length == 0) { continue; }
|
||||
|
||||
|
||||
switch (++part_num){
|
||||
case 0:
|
||||
entry.device_string = part.strip();
|
||||
@ -123,13 +123,13 @@ public class FsTabEntry : GLib.Object{
|
||||
public static string write_file(
|
||||
Gee.ArrayList<FsTabEntry> entries, string file_path,
|
||||
bool keep_comments_and_empty_lines = false){
|
||||
|
||||
|
||||
string text = "";
|
||||
|
||||
if (!keep_comments_and_empty_lines){
|
||||
text += "# <file system> <mount point> <type> <options> <dump> <pass>\n\n";
|
||||
}
|
||||
|
||||
|
||||
foreach(var entry in entries){
|
||||
if (entry.is_comment || entry.is_empty_line){
|
||||
if (keep_comments_and_empty_lines){
|
||||
@ -149,18 +149,18 @@ public class FsTabEntry : GLib.Object{
|
||||
entries.sort((a, b)=>{
|
||||
return strcmp(a.mount_point, b.mount_point);
|
||||
});
|
||||
|
||||
|
||||
if (file_exists(file_path)){
|
||||
file_delete(file_path);
|
||||
}
|
||||
|
||||
|
||||
file_write(file_path, text);
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public string subvolume_name(){
|
||||
|
||||
|
||||
if (options.down().contains("subvol=")){
|
||||
string txt = options.split("subvol=")[1].split(",")[0].strip();
|
||||
if (txt.has_prefix("/") && (txt.split("/").length == 2)){
|
||||
@ -183,7 +183,7 @@ public class FsTabEntry : GLib.Object{
|
||||
|| (mount_point == "none")
|
||||
|| !mount_point.has_prefix("/")
|
||||
|| (!device_string.has_prefix("/dev/") && !device_string.down().has_prefix("uuid="))){
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
@ -192,7 +192,7 @@ public class FsTabEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public static FsTabEntry? find_entry_by_mount_point(Gee.ArrayList<FsTabEntry> entries, string mount_path){
|
||||
|
||||
|
||||
foreach(var entry in entries){
|
||||
if (entry.mount_point == mount_path){
|
||||
return entry;
|
||||
@ -202,7 +202,7 @@ public class FsTabEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public Device? resolve_device(Gee.ArrayList<CryptTabEntry> crypttab, Gtk.Window? parent_window){
|
||||
|
||||
|
||||
Device dev_fstab = null;
|
||||
if (device_uuid.length > 0){
|
||||
dev_fstab = Device.get_device_by_uuid(device_uuid);
|
||||
@ -217,30 +217,30 @@ public class FsTabEntry : GLib.Object{
|
||||
Check if the device mentioned in fstab entry is a mapped device.
|
||||
If it is, then try finding the parent device which may be available on the current system.
|
||||
Prompt user to unlock it if found.
|
||||
|
||||
|
||||
Note:
|
||||
Mapped name may be different on running system, or it may be same.
|
||||
Since it is not reliable, we will try to identify the parent intead of the mapped device.
|
||||
*/
|
||||
|
||||
|
||||
if (device_string.has_prefix("/dev/mapper/")){
|
||||
|
||||
|
||||
string mapped_name = device_string.replace("/dev/mapper/","");
|
||||
|
||||
|
||||
foreach(var item in crypttab){
|
||||
|
||||
|
||||
if (item.mapped_name == mapped_name){
|
||||
|
||||
// we found the entry for the mapped device
|
||||
device_string = item.device_string;
|
||||
|
||||
if (device_uuid.length > 0){
|
||||
|
||||
|
||||
// we have the parent's uuid. get the luks device and prompt user to unlock it.
|
||||
var dev_luks = Device.get_device_by_uuid(device_uuid);
|
||||
|
||||
|
||||
if (dev_luks != null){
|
||||
|
||||
|
||||
string msg_out, msg_err;
|
||||
var dev_unlocked = Device.luks_unlock(
|
||||
dev_luks, "", "", parent_window, out msg_out, out msg_err);
|
||||
@ -268,22 +268,22 @@ public class FsTabEntry : GLib.Object{
|
||||
|
||||
|
||||
public void append_option(string option){
|
||||
|
||||
|
||||
if (!options.contains(option)){
|
||||
options += ",%s".printf(option);
|
||||
}
|
||||
|
||||
|
||||
if(options.has_prefix(",")){
|
||||
options = options[1:options.length];
|
||||
}
|
||||
|
||||
|
||||
options = options.strip();
|
||||
}
|
||||
|
||||
public void remove_option(string option){
|
||||
|
||||
|
||||
options = options.replace(option,"").strip();
|
||||
|
||||
|
||||
if(options.has_prefix(",")){
|
||||
options = options[1:options.length];
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class AboutWindow : Gtk.Window {
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Box vbox_logo;
|
||||
private Gtk.Box vbox_credits;
|
||||
@ -81,7 +81,7 @@ public class AboutWindow : Gtk.Window {
|
||||
_contributors = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string _comments = "";
|
||||
public string comments{
|
||||
get{
|
||||
@ -161,7 +161,7 @@ public class AboutWindow : Gtk.Window {
|
||||
_translators = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string[] _third_party;
|
||||
public string[] third_party{
|
||||
get{
|
||||
@ -203,11 +203,11 @@ public class AboutWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
private string username = "";
|
||||
|
||||
|
||||
public AboutWindow(Gtk.Window _window) {
|
||||
|
||||
window = _window;
|
||||
|
||||
|
||||
window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
set_destroy_with_parent (true);
|
||||
set_modal (true);
|
||||
@ -218,17 +218,17 @@ public class AboutWindow : Gtk.Window {
|
||||
username = get_username();
|
||||
log_debug("username: %s".printf(username));
|
||||
}
|
||||
|
||||
|
||||
vbox_main = new Gtk.Box(Orientation.VERTICAL,0);
|
||||
vbox_main.margin = 12;
|
||||
vbox_main.spacing = 6;
|
||||
this.add(vbox_main);
|
||||
|
||||
|
||||
vbox_logo = new Gtk.Box(Orientation.VERTICAL,0);
|
||||
vbox_main.add(vbox_logo);
|
||||
|
||||
// license -------------------------------------
|
||||
|
||||
|
||||
vbox_license = new Gtk.Box(Orientation.VERTICAL,0);
|
||||
vbox_license.no_show_all = true;
|
||||
vbox_main.add(vbox_license);
|
||||
@ -237,7 +237,7 @@ public class AboutWindow : Gtk.Window {
|
||||
sw_license.set_shadow_type(ShadowType.ETCHED_IN);
|
||||
sw_license.expand = true;
|
||||
vbox_license.add(sw_license);
|
||||
|
||||
|
||||
var label = new Gtk.Label("");
|
||||
label.set_use_markup(true);
|
||||
label.margin_top = 5;
|
||||
@ -250,9 +250,9 @@ public class AboutWindow : Gtk.Window {
|
||||
label.margin = 6;
|
||||
sw_license.add(label);
|
||||
lbl_license = label;
|
||||
|
||||
|
||||
// credits --------------------------------
|
||||
|
||||
|
||||
vbox_credits = new Gtk.Box(Orientation.VERTICAL,0);
|
||||
vbox_credits.no_show_all = true;
|
||||
vbox_main.add(vbox_credits);
|
||||
@ -261,11 +261,11 @@ public class AboutWindow : Gtk.Window {
|
||||
sw_credits.set_shadow_type(ShadowType.ETCHED_IN);
|
||||
sw_credits.expand = true;
|
||||
vbox_credits.add(sw_credits);
|
||||
|
||||
|
||||
vbox_lines = new Gtk.Box(Orientation.VERTICAL,0);
|
||||
vbox_lines.margin_top = 10;
|
||||
sw_credits.add(vbox_lines);
|
||||
|
||||
|
||||
//logo
|
||||
img_logo = new Gtk.Image();
|
||||
img_logo.margin_top = 6;
|
||||
@ -295,7 +295,7 @@ public class AboutWindow : Gtk.Window {
|
||||
vbox_logo.add(lbtn_website);
|
||||
|
||||
lbtn_website.activate_link.connect(()=>{
|
||||
return xdg_open(lbtn_website.uri, username);
|
||||
return xdg_open(lbtn_website.uri, username);
|
||||
});
|
||||
|
||||
//copyright
|
||||
@ -332,13 +332,13 @@ public class AboutWindow : Gtk.Window {
|
||||
hbox_action.add(btn_close);
|
||||
|
||||
// handlers
|
||||
|
||||
|
||||
btn_license.clicked.connect(()=>{
|
||||
|
||||
|
||||
vbox_logo.visible = !vbox_logo.visible;
|
||||
|
||||
vbox_license.visible = !vbox_license.visible;
|
||||
|
||||
|
||||
if (vbox_license.visible){
|
||||
vbox_license.set_no_show_all(false);
|
||||
vbox_license.show_all();
|
||||
@ -366,7 +366,7 @@ public class AboutWindow : Gtk.Window {
|
||||
});
|
||||
|
||||
btn_credits.clicked.connect(()=>{
|
||||
|
||||
|
||||
vbox_logo.visible = !vbox_logo.visible;
|
||||
|
||||
vbox_credits.visible = !vbox_credits.visible;
|
||||
@ -400,7 +400,7 @@ public class AboutWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
|
||||
|
||||
title = program_name;
|
||||
img_logo.pixbuf = logo.scale_simple(128,128,Gdk.InterpType.HYPER);
|
||||
lbl_program_name.label = "<span size='larger'>%s</span>".printf(program_name);
|
||||
@ -479,7 +479,7 @@ public class AboutWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
private void add_line(string text, bool escape_html_chars = true){
|
||||
|
||||
|
||||
if (text.split(":").length >= 2){
|
||||
var link = new LinkButton(escape_html(text.split(":")[0]));
|
||||
vbox_lines.add(link);
|
||||
@ -496,7 +496,7 @@ public class AboutWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
link.activate_link.connect(()=>{
|
||||
return xdg_open(link.uri, username);
|
||||
return xdg_open(link.uri, username);
|
||||
});
|
||||
}
|
||||
else{
|
||||
|
@ -34,7 +34,7 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class CustomMessageDialog : Gtk.Dialog {
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Gtk.Label lbl_msg;
|
||||
private Gtk.ScrolledWindow sw_msg;
|
||||
@ -47,9 +47,9 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
private string msg_body;
|
||||
private Gtk.MessageType msg_type;
|
||||
private Gtk.ButtonsType buttons_type;
|
||||
|
||||
|
||||
public CustomMessageDialog(string _msg_title, string _msg_body, Gtk.MessageType _msg_type, Window? parent, Gtk.ButtonsType _buttons_type) {
|
||||
|
||||
|
||||
set_transient_for(parent);
|
||||
set_modal(true);
|
||||
|
||||
@ -57,7 +57,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
msg_body = _msg_body;
|
||||
msg_type = _msg_type;
|
||||
buttons_type = _buttons_type;
|
||||
|
||||
|
||||
init_window();
|
||||
|
||||
lbl_msg.expand = true;
|
||||
@ -75,7 +75,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
}
|
||||
|
||||
public void init_window () {
|
||||
|
||||
|
||||
this.title = "";
|
||||
this.window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
this.icon = IconManager.lookup("timeshift", 16);
|
||||
@ -83,7 +83,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
this.deletable = false;
|
||||
this.skip_taskbar_hint = true;
|
||||
this.skip_pager_hint = true;
|
||||
|
||||
|
||||
//vbox_main
|
||||
vbox_main = get_content_area () as Gtk.Box;
|
||||
vbox_main.margin = 6;
|
||||
@ -94,7 +94,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
vbox_main.add (hbox_contents);
|
||||
|
||||
string icon_name = "dialog-info";
|
||||
|
||||
|
||||
switch(msg_type){
|
||||
case Gtk.MessageType.INFO:
|
||||
icon_name = "dialog-info";
|
||||
@ -111,10 +111,10 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
}
|
||||
|
||||
// image ----------------
|
||||
|
||||
|
||||
var img = new Image.from_icon_name(icon_name, Gtk.IconSize.DIALOG);
|
||||
hbox_contents.add(img);
|
||||
|
||||
|
||||
// label -------------------
|
||||
|
||||
var text = "<span weight=\"bold\" size=\"x-large\">%s</span>\n\n%s".printf(
|
||||
@ -138,7 +138,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
hbox_contents.add(sw_msg);
|
||||
|
||||
// actions -------------------------
|
||||
|
||||
|
||||
switch(buttons_type){
|
||||
case Gtk.ButtonsType.OK:
|
||||
btn_ok = (Gtk.Button) add_button (_("OK"), Gtk.ResponseType.OK);
|
||||
@ -154,7 +154,7 @@ public class CustomMessageDialog : Gtk.Dialog {
|
||||
btn_no = (Gtk.Button) add_button (_("No"), Gtk.ResponseType.NO);
|
||||
btn_yes.grab_focus();
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,10 +41,10 @@ public class DonationWindow : Gtk.Window {
|
||||
public DonationWindow(Gtk.Window window) {
|
||||
|
||||
set_title(_("Donate"));
|
||||
|
||||
|
||||
set_transient_for(window);
|
||||
set_destroy_with_parent(true);
|
||||
|
||||
|
||||
window_position = WindowPosition.CENTER_ON_PARENT;
|
||||
|
||||
set_modal(true);
|
||||
@ -56,7 +56,7 @@ public class DonationWindow : Gtk.Window {
|
||||
vbox_main.margin = 12;
|
||||
|
||||
this.add(vbox_main);
|
||||
|
||||
|
||||
if (get_user_id_effective() == 0){
|
||||
username = get_username();
|
||||
}
|
||||
@ -70,16 +70,16 @@ public class DonationWindow : Gtk.Window {
|
||||
msg = _("This software is updated once a year due to lack of time, developers, and funds. You can support this project by making a donation with PayPal.");
|
||||
|
||||
add_label(msg);
|
||||
|
||||
|
||||
var hbox = add_hbox();
|
||||
|
||||
|
||||
add_button(hbox, _("Donate"),
|
||||
"https://www.paypal.com/cgi-bin/webscr?business=teejeetech@gmail.com&cmd=_xclick¤cy_code=USD&item_name=%s+Donation".printf(appname));
|
||||
|
||||
// -----------------------------
|
||||
|
||||
|
||||
msg = _("Use the GitHub issue tracker for reporting issues, or post your questions on the Linux Mint forums. Please avoid reporting issues by email.");
|
||||
|
||||
|
||||
add_label(msg);
|
||||
|
||||
hbox = add_vbox();
|
||||
@ -89,21 +89,21 @@ public class DonationWindow : Gtk.Window {
|
||||
if (has_wiki){
|
||||
add_button(hbox, _("Wiki"), "https://github.com/teejee2008/%s/wiki".printf(appname.down()));
|
||||
}
|
||||
|
||||
|
||||
// close window ---------------------------------------------------------
|
||||
|
||||
var lbl_dummy = add_label("");
|
||||
lbl_dummy.margin = 20;
|
||||
|
||||
|
||||
hbox = add_hbox();
|
||||
|
||||
add_button(hbox, _("Visit Website"), "https://teejeetech.com/");
|
||||
|
||||
add_button(hbox, _("More Apps"), "https://teejeetech.com/shop/");
|
||||
|
||||
|
||||
var button = new Gtk.Button.with_label(_("Close"));
|
||||
hbox.add(button);
|
||||
|
||||
|
||||
button.clicked.connect(() => {
|
||||
this.destroy();
|
||||
});
|
||||
@ -112,20 +112,20 @@ public class DonationWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
private void add_heading(string msg){
|
||||
|
||||
|
||||
var label = new Gtk.Label("<span weight=\"bold\" size=\"large\" style=\"italic\">%s</span>".printf(msg));
|
||||
|
||||
label.set_use_markup(true);
|
||||
|
||||
|
||||
label.wrap = true;
|
||||
label.wrap_mode = Pango.WrapMode.WORD;
|
||||
label.max_width_chars = 80;
|
||||
|
||||
|
||||
label.xalign = 0.0f;
|
||||
label.margin_top = 12;
|
||||
vbox_main.add(label);
|
||||
}
|
||||
|
||||
|
||||
private string format_heading(string msg){
|
||||
|
||||
return "<span size=\"large\" style=\"italic\">%s</span>".printf(msg);
|
||||
@ -134,17 +134,17 @@ public class DonationWindow : Gtk.Window {
|
||||
private Gtk.Label add_label(string msg){
|
||||
|
||||
var label = new Gtk.Label(msg);
|
||||
|
||||
|
||||
label.set_use_markup(true);
|
||||
|
||||
|
||||
label.wrap = true;
|
||||
label.wrap_mode = Pango.WrapMode.WORD;
|
||||
label.max_width_chars = 50;
|
||||
|
||||
|
||||
label.xalign = 0.0f;
|
||||
|
||||
vbox_main.add(label);
|
||||
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ public class DonationWindow : Gtk.Window {
|
||||
vbox_main.add(hbox);
|
||||
return hbox;
|
||||
}
|
||||
|
||||
|
||||
private Gtk.ButtonBox add_vbox(){
|
||||
|
||||
var vbox = new Gtk.ButtonBox(Orientation.VERTICAL);
|
||||
@ -173,7 +173,7 @@ public class DonationWindow : Gtk.Window {
|
||||
box.add(button);
|
||||
|
||||
//button.set_size_request(200,-1);
|
||||
|
||||
|
||||
button.clicked.connect(() => {
|
||||
xdg_open(url, username);
|
||||
});
|
||||
@ -184,7 +184,7 @@ public class DonationWindow : Gtk.Window {
|
||||
var button = new Gtk.LinkButton.with_label("", text);
|
||||
button.set_tooltip_text(url);
|
||||
box.add(button);
|
||||
|
||||
|
||||
button.clicked.connect(() => {
|
||||
xdg_open(url, username);
|
||||
});
|
||||
|
@ -34,52 +34,52 @@ using TeeJee.System;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public class TerminalWindow : Gtk.Window {
|
||||
|
||||
|
||||
private Gtk.Box vbox_main;
|
||||
private Vte.Terminal term;
|
||||
|
||||
|
||||
private int def_width = 800;
|
||||
private int def_height = 600;
|
||||
|
||||
private Pid child_pid;
|
||||
private Gtk.Window parent_win = null;
|
||||
public bool is_running = false;
|
||||
|
||||
|
||||
// init
|
||||
|
||||
|
||||
public TerminalWindow.with_parent(Gtk.Window? parent) {
|
||||
|
||||
|
||||
if (parent != null){
|
||||
set_transient_for(parent);
|
||||
parent_win = parent;
|
||||
}
|
||||
|
||||
|
||||
set_modal(true);
|
||||
fullscreen();
|
||||
|
||||
this.delete_event.connect(()=>{
|
||||
// do not allow window to close
|
||||
// do not allow window to close
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
init_window();
|
||||
}
|
||||
|
||||
public void init_window () {
|
||||
|
||||
|
||||
this.title = "";
|
||||
this.icon = IconManager.lookup("timeshift",16);
|
||||
this.resizable = true;
|
||||
this.deletable = false;
|
||||
|
||||
|
||||
// vbox_main ---------------
|
||||
|
||||
|
||||
vbox_main = new Gtk.Box(Orientation.VERTICAL, 6);
|
||||
vbox_main.set_size_request (def_width, def_height);
|
||||
add (vbox_main);
|
||||
|
||||
// terminal ----------------------
|
||||
|
||||
|
||||
term = new Vte.Terminal();
|
||||
term.expand = true;
|
||||
vbox_main.add(term);
|
||||
@ -89,33 +89,33 @@ public class TerminalWindow : Gtk.Window {
|
||||
term.cursor_blink_mode = Vte.CursorBlinkMode.SYSTEM;
|
||||
term.cursor_shape = Vte.CursorShape.UNDERLINE;
|
||||
term.rewrap_on_resize = true;
|
||||
|
||||
|
||||
term.scroll_on_keystroke = true;
|
||||
term.scroll_on_output = true;
|
||||
|
||||
// colors -----------------------------
|
||||
|
||||
|
||||
var color = Gdk.RGBA();
|
||||
color.parse("#FFFFFF");
|
||||
term.set_color_foreground(color);
|
||||
|
||||
color.parse("#404040");
|
||||
term.set_color_background(color);
|
||||
|
||||
|
||||
// grab focus ----------------
|
||||
|
||||
|
||||
term.grab_focus();
|
||||
|
||||
|
||||
show_all();
|
||||
}
|
||||
|
||||
public void start_shell(){
|
||||
|
||||
|
||||
string[] argv = new string[1];
|
||||
argv[0] = "/bin/sh";
|
||||
|
||||
string[] env = Environ.get();
|
||||
|
||||
|
||||
try{
|
||||
|
||||
is_running = true;
|
||||
@ -137,16 +137,16 @@ public class TerminalWindow : Gtk.Window {
|
||||
}
|
||||
|
||||
public void execute_script(string script_path, bool wait = false){
|
||||
|
||||
|
||||
string[] argv = new string[1];
|
||||
argv[0] = script_path;
|
||||
|
||||
|
||||
string[] env = Environ.get();
|
||||
|
||||
try{
|
||||
|
||||
is_running = true;
|
||||
|
||||
|
||||
term.spawn_sync(
|
||||
Vte.PtyFlags.DEFAULT, //pty_flags
|
||||
TEMP_DIR, //working_directory
|
||||
@ -159,7 +159,7 @@ public class TerminalWindow : Gtk.Window {
|
||||
);
|
||||
|
||||
term.watch_child(child_pid);
|
||||
|
||||
|
||||
term.child_exited.connect(script_exit);
|
||||
|
||||
if (wait){
|
||||
@ -177,11 +177,11 @@ public class TerminalWindow : Gtk.Window {
|
||||
public void script_exit(int status){
|
||||
|
||||
is_running = false;
|
||||
|
||||
|
||||
this.hide();
|
||||
|
||||
//no need to check status again
|
||||
|
||||
|
||||
//destroying parent will display main window
|
||||
if (parent != null){
|
||||
parent_win.destroy();
|
||||
|
@ -12,7 +12,7 @@ namespace TeeJee.GtkHelper{
|
||||
using Gtk;
|
||||
|
||||
// messages -----------
|
||||
|
||||
|
||||
public void show_err_log(Gtk.Window parent, bool disable_log = true){
|
||||
if ((err_log != null) && (err_log.length > 0)){
|
||||
gtk_messagebox(_("Error"), err_log, parent, true);
|
||||
@ -22,7 +22,7 @@ namespace TeeJee.GtkHelper{
|
||||
err_log_disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void gtk_do_events (){
|
||||
|
||||
/* Do pending events */
|
||||
@ -113,11 +113,11 @@ namespace TeeJee.GtkHelper{
|
||||
vbox_main.pack_start (txt_input, false, true, 0);
|
||||
content.add(vbox_main);
|
||||
content.margin = 6;
|
||||
|
||||
|
||||
//add buttons
|
||||
dlg.add_button(_("OK"),Gtk.ResponseType.OK);
|
||||
dlg.add_button(_("Cancel"),Gtk.ResponseType.CANCEL);
|
||||
|
||||
|
||||
//keyboard shortcuts
|
||||
txt_input.key_press_event.connect ((w, event) => {
|
||||
if (event.keyval == 65293) {
|
||||
@ -150,9 +150,9 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
window.destroy();
|
||||
}
|
||||
|
||||
|
||||
// combo ---------
|
||||
|
||||
|
||||
public bool gtk_combobox_set_value (ComboBox combo, int index, string val){
|
||||
|
||||
/* Conveniance function to set combobox value */
|
||||
@ -203,7 +203,7 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
public int gtk_combobox_get_value_enum (ComboBox combo, int index, int default_value){
|
||||
|
||||
/* Conveniance function to get combobox value */
|
||||
@ -222,7 +222,7 @@ namespace TeeJee.GtkHelper{
|
||||
// styles ----------------
|
||||
|
||||
public static int CSS_AUTO_CLASS_INDEX = 0;
|
||||
|
||||
|
||||
public static void gtk_apply_css(Gtk.Widget[] widgets, string css_style){
|
||||
var css_provider = new Gtk.CssProvider();
|
||||
var css = ".style_%d { %s }".printf(++CSS_AUTO_CLASS_INDEX, css_style);
|
||||
@ -233,16 +233,16 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
|
||||
foreach(var widget in widgets){
|
||||
|
||||
|
||||
widget.get_style_context().add_provider(
|
||||
css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
|
||||
widget.get_style_context().add_class("style_%d".printf(CSS_AUTO_CLASS_INDEX));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// treeview -----------------
|
||||
|
||||
|
||||
public int gtk_treeview_model_count(TreeModel model){
|
||||
int count = 0;
|
||||
TreeIter iter;
|
||||
@ -260,9 +260,9 @@ namespace TeeJee.GtkHelper{
|
||||
treeview.model = null;
|
||||
treeview.model = model;
|
||||
}
|
||||
|
||||
|
||||
// misc
|
||||
|
||||
|
||||
public bool gtk_container_has_child(Gtk.Container container, Gtk.Widget widget){
|
||||
foreach(var child in container.get_children()){
|
||||
if (child == widget){
|
||||
@ -273,7 +273,7 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
|
||||
// file chooser ----------------
|
||||
|
||||
|
||||
public Gtk.FileFilter create_file_filter(string group_name, string[] patterns) {
|
||||
var filter = new Gtk.FileFilter ();
|
||||
filter.set_filter_name(group_name);
|
||||
@ -287,21 +287,21 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
// add_notebook
|
||||
private Gtk.Notebook add_notebook(Gtk.Box box, bool show_tabs = true, bool show_border = true){
|
||||
|
||||
|
||||
// notebook
|
||||
var book = new Gtk.Notebook();
|
||||
book.margin = 0;
|
||||
book.show_tabs = show_tabs;
|
||||
book.show_border = show_border;
|
||||
|
||||
|
||||
box.pack_start(book, true, true, 0);
|
||||
|
||||
|
||||
return book;
|
||||
}
|
||||
|
||||
// add_treeview
|
||||
private Gtk.TreeView add_treeview(Gtk.Box box, Gtk.SelectionMode selection_mode = Gtk.SelectionMode.SINGLE){
|
||||
|
||||
|
||||
// TreeView
|
||||
var treeview = new TreeView();
|
||||
treeview.get_selection().mode = selection_mode;
|
||||
@ -320,26 +320,26 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
// add_column_text
|
||||
private Gtk.TreeViewColumn add_column_text(Gtk.TreeView treeview, string title, out Gtk.CellRendererText cell){
|
||||
|
||||
|
||||
// TreeViewColumn
|
||||
var col = new Gtk.TreeViewColumn();
|
||||
col.title = title;
|
||||
|
||||
|
||||
cell = new Gtk.CellRendererText();
|
||||
cell.xalign = (float) 0.0;
|
||||
col.pack_start (cell, false);
|
||||
treeview.append_column(col);
|
||||
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
// add_column_icon
|
||||
private Gtk.TreeViewColumn add_column_icon(Gtk.TreeView treeview, string title, out Gtk.CellRendererPixbuf cell){
|
||||
|
||||
|
||||
// TreeViewColumn
|
||||
var col = new Gtk.TreeViewColumn();
|
||||
col.title = title;
|
||||
|
||||
|
||||
cell = new Gtk.CellRendererPixbuf();
|
||||
cell.xpad = 2;
|
||||
col.pack_start (cell, false);
|
||||
@ -351,7 +351,7 @@ namespace TeeJee.GtkHelper{
|
||||
// add_column_icon_and_text
|
||||
private Gtk.TreeViewColumn add_column_icon_and_text(Gtk.TreeView treeview, string title,
|
||||
out Gtk.CellRendererPixbuf cell_pix, out Gtk.CellRendererText cell_text){
|
||||
|
||||
|
||||
// TreeViewColumn
|
||||
var col = new Gtk.TreeViewColumn();
|
||||
col.title = title;
|
||||
@ -359,7 +359,7 @@ namespace TeeJee.GtkHelper{
|
||||
cell_pix = new Gtk.CellRendererPixbuf();
|
||||
cell_pix.xpad = 2;
|
||||
col.pack_start (cell_pix, false);
|
||||
|
||||
|
||||
cell_text = new Gtk.CellRendererText();
|
||||
cell_text.xalign = (float) 0.0;
|
||||
col.pack_start (cell_text, false);
|
||||
@ -371,7 +371,7 @@ namespace TeeJee.GtkHelper{
|
||||
// add_column_radio_and_text
|
||||
private Gtk.TreeViewColumn add_column_radio_and_text(Gtk.TreeView treeview, string title,
|
||||
out Gtk.CellRendererToggle cell_radio, out Gtk.CellRendererText cell_text){
|
||||
|
||||
|
||||
// TreeViewColumn
|
||||
var col = new Gtk.TreeViewColumn();
|
||||
col.title = title;
|
||||
@ -381,7 +381,7 @@ namespace TeeJee.GtkHelper{
|
||||
cell_radio.radio = true;
|
||||
cell_radio.activatable = true;
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
|
||||
cell_text = new Gtk.CellRendererText();
|
||||
cell_text.xalign = (float) 0.0;
|
||||
col.pack_start (cell_text, false);
|
||||
@ -391,9 +391,9 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
|
||||
// add_column_icon_radio_text
|
||||
private Gtk.TreeViewColumn add_column_icon_radio_text(Gtk.TreeView treeview, string title,
|
||||
private Gtk.TreeViewColumn add_column_icon_radio_text(Gtk.TreeView treeview, string title,
|
||||
out Gtk.CellRendererPixbuf cell_pix, out Gtk.CellRendererToggle cell_radio, out Gtk.CellRendererText cell_text){
|
||||
|
||||
|
||||
// TreeViewColumn
|
||||
var col = new Gtk.TreeViewColumn();
|
||||
col.title = title;
|
||||
@ -407,7 +407,7 @@ namespace TeeJee.GtkHelper{
|
||||
cell_radio.radio = true;
|
||||
cell_radio.activatable = true;
|
||||
col.pack_start (cell_radio, false);
|
||||
|
||||
|
||||
cell_text = new Gtk.CellRendererText();
|
||||
cell_text.xalign = (float) 0.0;
|
||||
col.pack_start (cell_text, false);
|
||||
@ -425,7 +425,7 @@ namespace TeeJee.GtkHelper{
|
||||
scroll.vscrollbar_policy = PolicyType.ALWAYS;
|
||||
scroll.expand = true;
|
||||
box.add(scroll);
|
||||
|
||||
|
||||
var label = new Gtk.Label(text);
|
||||
label.xalign = (float) 0.0;
|
||||
label.yalign = (float) 0.0;
|
||||
@ -452,13 +452,13 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
// add_label
|
||||
private Gtk.Label add_label(Gtk.Box box, string text, bool bold = false, bool italic = false, bool large = false){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(bold ? " weight=\"bold\"" : ""),
|
||||
(italic ? " style=\"italic\"" : ""),
|
||||
(large ? " size=\"x-large\"" : ""),
|
||||
text);
|
||||
|
||||
|
||||
var label = new Gtk.Label(msg);
|
||||
label.set_use_markup(true);
|
||||
label.xalign = (float) 0.0;
|
||||
@ -469,19 +469,19 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
|
||||
private string format_text(string text, bool bold = false, bool italic = false, bool large = false){
|
||||
|
||||
|
||||
string msg = "<span%s%s%s>%s</span>".printf(
|
||||
(bold ? " weight=\"bold\"" : ""),
|
||||
(italic ? " style=\"italic\"" : ""),
|
||||
(large ? " size=\"x-large\"" : ""),
|
||||
escape_html(text));
|
||||
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
// add_label_header
|
||||
private Gtk.Label add_label_header(Gtk.Box box, string text, bool large_heading = false){
|
||||
|
||||
|
||||
var label = add_label(box, escape_html(text), true, false, large_heading);
|
||||
label.margin_bottom = 12;
|
||||
return label;
|
||||
@ -489,7 +489,7 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
// add_label_subnote
|
||||
private Gtk.Label add_label_subnote(Gtk.Box box, string text){
|
||||
|
||||
|
||||
var label = add_label(box, text, false, true);
|
||||
return label;
|
||||
}
|
||||
@ -507,7 +507,7 @@ namespace TeeJee.GtkHelper{
|
||||
}
|
||||
|
||||
radio.label = text;
|
||||
|
||||
|
||||
box.add(radio);
|
||||
|
||||
foreach(var child in radio.get_children()){
|
||||
@ -517,7 +517,7 @@ namespace TeeJee.GtkHelper{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return radio;
|
||||
}
|
||||
|
||||
@ -535,7 +535,7 @@ namespace TeeJee.GtkHelper{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
chk.toggled.connect(()=>{
|
||||
chk.active;
|
||||
@ -564,7 +564,7 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
// add_button
|
||||
private Gtk.Button add_button(Gtk.Box box, string text, string tooltip, Gtk.SizeGroup? size_group, Gtk.Image? icon = null){
|
||||
|
||||
|
||||
var button = new Gtk.Button();
|
||||
box.add(button);
|
||||
|
||||
@ -582,8 +582,8 @@ namespace TeeJee.GtkHelper{
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
public Gtk.ButtonBox add_button_box(Gtk.Container box, Gtk.Orientation orientation = Gtk.Orientation.HORIZONTAL,
|
||||
|
||||
public Gtk.ButtonBox add_button_box(Gtk.Container box, Gtk.Orientation orientation = Gtk.Orientation.HORIZONTAL,
|
||||
Gtk.ButtonBoxStyle layout = Gtk.ButtonBoxStyle.CENTER, int spacing = 6){
|
||||
|
||||
var bbox = new Gtk.ButtonBox(orientation);
|
||||
@ -600,7 +600,7 @@ namespace TeeJee.GtkHelper{
|
||||
SPREAD - Buttons are evenly spread across the box.
|
||||
START - Buttons are grouped towards the start of the box, (on the left for a HBox, or the top for a VBox).
|
||||
*/
|
||||
|
||||
|
||||
return bbox;
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class IconManager : GLib.Object {
|
||||
public static void init(string[] args, string app_name){
|
||||
|
||||
log_debug("IconManager: init()");
|
||||
|
||||
|
||||
search_paths = new Gee.ArrayList<string>();
|
||||
|
||||
string binpath = file_resolve_executable_path(args[0]);
|
||||
@ -91,7 +91,7 @@ public class IconManager : GLib.Object {
|
||||
public static void refresh_icon_theme(){
|
||||
|
||||
if (!GTK_INITIALIZED) { return; }
|
||||
|
||||
|
||||
theme = Gtk.IconTheme.get_default();
|
||||
foreach(string path in search_paths){
|
||||
theme.append_search_path(path);
|
||||
@ -99,7 +99,7 @@ public class IconManager : GLib.Object {
|
||||
}
|
||||
|
||||
public static Gdk.Pixbuf? lookup(string icon_name, int icon_size, bool symbolic = false, bool use_hardcoded = false, int scale = 1){
|
||||
|
||||
|
||||
Gdk.Pixbuf? pixbuf = null;
|
||||
|
||||
if (icon_name.length == 0){ return null; }
|
||||
@ -130,7 +130,7 @@ public class IconManager : GLib.Object {
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
|
||||
public static Gtk.Image? lookup_image(string icon_name, int icon_size, bool symbolic = false, bool use_hardcoded = false){
|
||||
|
||||
if (icon_name.length == 0){ return null; }
|
||||
@ -138,7 +138,7 @@ public class IconManager : GLib.Object {
|
||||
Gtk.Image image = new Gtk.Image();
|
||||
|
||||
Gdk.Pixbuf? pix = lookup(icon_name, icon_size, symbolic, use_hardcoded, image.scale_factor);
|
||||
|
||||
|
||||
if (pix == null){
|
||||
pix = lookup(GENERIC_ICON_IMAGE_MISSING, icon_size, symbolic, use_hardcoded, image.scale_factor);
|
||||
}
|
||||
@ -152,9 +152,9 @@ public class IconManager : GLib.Object {
|
||||
|
||||
public static Cairo.Surface? lookup_surface(string icon_name, int icon_size, int scale = 1, bool symbolic = false, bool use_hardcoded = false){
|
||||
if (icon_name.length == 0){ return null; }
|
||||
|
||||
|
||||
Gdk.Pixbuf? pix = lookup(icon_name, icon_size, symbolic, use_hardcoded, scale);
|
||||
|
||||
|
||||
if (pix == null){
|
||||
pix = lookup(GENERIC_ICON_IMAGE_MISSING, icon_size, symbolic, use_hardcoded, scale);
|
||||
}
|
||||
@ -167,7 +167,7 @@ public class IconManager : GLib.Object {
|
||||
Gdk.Pixbuf? pixbuf = null;
|
||||
|
||||
if (gicon == null){ return null; }
|
||||
|
||||
|
||||
try {
|
||||
var icon_info = theme.lookup_by_gicon(gicon, icon_size, Gtk.IconLookupFlags.FORCE_SIZE);
|
||||
if (icon_info != null){
|
||||
@ -184,7 +184,7 @@ public class IconManager : GLib.Object {
|
||||
public static Gtk.Image? lookup_animation(string gif_name){
|
||||
|
||||
if (gif_name.length == 0){ return null; }
|
||||
|
||||
|
||||
foreach(string search_path in search_paths){
|
||||
|
||||
foreach(string ext in new string[] { ".gif" }){
|
||||
@ -242,17 +242,17 @@ public class IconManager : GLib.Object {
|
||||
}
|
||||
|
||||
var emblemed = pixbuf.copy();
|
||||
|
||||
emblem.composite(emblemed,
|
||||
offset_x, offset_y,
|
||||
|
||||
emblem.composite(emblemed,
|
||||
offset_x, offset_y,
|
||||
emblem_size, emblem_size,
|
||||
offset_x, offset_y,
|
||||
1.0, 1.0,
|
||||
offset_x, offset_y,
|
||||
1.0, 1.0,
|
||||
Gdk.InterpType.BILINEAR, 255);
|
||||
|
||||
return emblemed;
|
||||
}
|
||||
|
||||
|
||||
public static Gdk.Pixbuf? add_overlay(Gdk.Pixbuf pixbuf_base, Gdk.Pixbuf pixbuf_overlay) {
|
||||
|
||||
int offset_x = (pixbuf_base.width - pixbuf_overlay.width) / 2 ;
|
||||
@ -260,35 +260,35 @@ public class IconManager : GLib.Object {
|
||||
var offset_y = (pixbuf_base.height - pixbuf_overlay.height) / 2 ;
|
||||
|
||||
var emblemed = pixbuf_base.copy();
|
||||
|
||||
pixbuf_overlay.composite(emblemed,
|
||||
offset_x, offset_y,
|
||||
|
||||
pixbuf_overlay.composite(emblemed,
|
||||
offset_x, offset_y,
|
||||
pixbuf_overlay.width, pixbuf_overlay.height,
|
||||
offset_x, offset_y,
|
||||
1.0, 1.0,
|
||||
offset_x, offset_y,
|
||||
1.0, 1.0,
|
||||
Gdk.InterpType.BILINEAR, 255);
|
||||
|
||||
return emblemed;
|
||||
}
|
||||
|
||||
|
||||
public static Gdk.Pixbuf? resize_icon(Gdk.Pixbuf pixbuf_image, int icon_size) {
|
||||
|
||||
|
||||
//log_debug("resize_icon()");
|
||||
|
||||
|
||||
var pixbuf_empty = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, icon_size, icon_size);
|
||||
pixbuf_empty.fill(0x00000000);
|
||||
|
||||
//log_debug("pixbuf_empty: %d, %d".printf(pixbuf_empty.width, pixbuf_empty.height));
|
||||
|
||||
|
||||
var pixbuf_resized = add_overlay(pixbuf_empty, pixbuf_image);
|
||||
|
||||
|
||||
//log_debug("pixbuf_resized: %d, %d".printf(pixbuf_resized.width, pixbuf_resized.height));
|
||||
|
||||
//copy_pixbuf_options(pixbuf_image, pixbuf_resized);
|
||||
|
||||
|
||||
return pixbuf_resized;
|
||||
}
|
||||
|
||||
|
||||
public static Gdk.Pixbuf? add_transparency (Gdk.Pixbuf pixbuf, int opacity = 130) {
|
||||
|
||||
var trans = pixbuf.copy();
|
||||
@ -302,14 +302,14 @@ public class IconManager : GLib.Object {
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
|
||||
public static Gdk.Pixbuf? load_pixbuf_from_file(string file_path, int icon_size){
|
||||
|
||||
|
||||
Gdk.Pixbuf? pixbuf = null;
|
||||
|
||||
|
||||
int width, height;
|
||||
Gdk.Pixbuf.get_file_info(file_path, out width, out height);
|
||||
|
||||
|
||||
if ((width <= icon_size) && (height <= icon_size)){
|
||||
try{
|
||||
// load without scaling
|
||||
@ -336,7 +336,7 @@ public class IconManager : GLib.Object {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class LinuxDistro : GLib.Object{
|
||||
public string codename = "";
|
||||
|
||||
public LinuxDistro(){
|
||||
|
||||
|
||||
dist_id = "";
|
||||
description = "";
|
||||
release = "";
|
||||
@ -44,7 +44,7 @@ public class LinuxDistro : GLib.Object{
|
||||
}
|
||||
|
||||
public string full_name(){
|
||||
|
||||
|
||||
if (dist_id == ""){
|
||||
return "";
|
||||
}
|
||||
@ -197,9 +197,9 @@ public class LinuxDistro : GLib.Object{
|
||||
}
|
||||
|
||||
public string dist_type {
|
||||
|
||||
|
||||
owned get{
|
||||
|
||||
|
||||
if (dist_id in "fedora rhel rocky centos almalinux"){
|
||||
return "redhat";
|
||||
}
|
||||
|
@ -8,28 +8,28 @@ using TeeJee.Misc;
|
||||
using Json;
|
||||
|
||||
public class MountEntry : GLib.Object{
|
||||
|
||||
|
||||
public Device device = null;
|
||||
public string mount_point = "";
|
||||
public string mount_options = "";
|
||||
|
||||
|
||||
public MountEntry(Device? device, string mount_point, string mount_options){
|
||||
|
||||
|
||||
this.device = device;
|
||||
this.mount_point = mount_point;
|
||||
this.mount_options = mount_options;
|
||||
}
|
||||
|
||||
public string subvolume_name(){
|
||||
|
||||
|
||||
if (mount_options.contains("subvol=")){
|
||||
|
||||
|
||||
string txt = mount_options.split("subvol=")[1].split(",")[0].strip();
|
||||
|
||||
|
||||
if (txt.has_prefix("/") && (txt.split("/").length == 2)){
|
||||
txt = txt.split("/")[1];
|
||||
}
|
||||
|
||||
|
||||
return txt;
|
||||
}
|
||||
else{
|
||||
@ -38,7 +38,7 @@ public class MountEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public string lvm_name(){
|
||||
|
||||
|
||||
if ((device != null) && (device.type == "lvm") && (device.mapped_name.length > 0)){
|
||||
return device.mapped_name.strip();
|
||||
}
|
||||
@ -48,13 +48,13 @@ public class MountEntry : GLib.Object{
|
||||
}
|
||||
|
||||
public static MountEntry? find_entry_by_mount_point(Gee.ArrayList<MountEntry> entries, string mount_path){
|
||||
|
||||
|
||||
foreach(var entry in entries){
|
||||
if (entry.mount_point == mount_path){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -28,15 +28,15 @@ using TeeJee.ProcessHelper;
|
||||
|
||||
// dep: notify-send
|
||||
public class OSDNotify : GLib.Object {
|
||||
|
||||
|
||||
private static DateTime dt_last_notification = null;
|
||||
public const int NOTIFICATION_INTERVAL = 3;
|
||||
|
||||
|
||||
public static int notify_send (
|
||||
string title, string message, int durationMillis,
|
||||
string urgency = "low", // low, normal, critical
|
||||
string dialog_type = "info" //error, info, warning
|
||||
){
|
||||
){
|
||||
|
||||
/* Displays notification bubble on the desktop */
|
||||
|
||||
@ -54,26 +54,26 @@ public class OSDNotify : GLib.Object {
|
||||
}
|
||||
|
||||
long seconds = 9999;
|
||||
|
||||
|
||||
if (dt_last_notification != null){
|
||||
|
||||
|
||||
DateTime dt_end = new DateTime.now_local();
|
||||
TimeSpan elapsed = dt_end.difference(dt_last_notification);
|
||||
seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND);
|
||||
}
|
||||
|
||||
if (seconds > NOTIFICATION_INTERVAL){
|
||||
|
||||
|
||||
if (cmd_exists("notify-send")){
|
||||
|
||||
|
||||
string desktop_entry = "timeshift-gtk";
|
||||
string hint = "string:desktop-entry:%s".printf(desktop_entry);
|
||||
|
||||
string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\" -h %s".printf(
|
||||
durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message, hint);
|
||||
|
||||
|
||||
retVal = exec_sync (s, null, null);
|
||||
|
||||
|
||||
dt_last_notification = new DateTime.now_local();
|
||||
}
|
||||
}
|
||||
@ -82,9 +82,9 @@ public class OSDNotify : GLib.Object {
|
||||
}
|
||||
|
||||
public static bool is_supported(){
|
||||
|
||||
|
||||
string path = get_cmd_path("notify-send");
|
||||
|
||||
|
||||
return (path != null) && (path.length > 0);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class RsyncTask : AsyncTask{
|
||||
public bool delete_after = false;
|
||||
public bool delete_excluded = false;
|
||||
public bool relative = false;
|
||||
|
||||
|
||||
public string rsync_log_file = "";
|
||||
public string exclude_from_file = "";
|
||||
public string link_from_path = "";
|
||||
@ -65,7 +65,7 @@ public class RsyncTask : AsyncTask{
|
||||
public int64 count_unchanged;
|
||||
|
||||
public StringBuilder log;
|
||||
|
||||
|
||||
public RsyncTask(){
|
||||
init_regular_expressions();
|
||||
status_lines = new GLib.Queue<string>();
|
||||
@ -75,7 +75,7 @@ public class RsyncTask : AsyncTask{
|
||||
if (regex_list != null){
|
||||
return; // already initialized
|
||||
}
|
||||
|
||||
|
||||
regex_list = new Gee.HashMap<string,Regex>();
|
||||
|
||||
/*
|
||||
@ -107,7 +107,7 @@ public class RsyncTask : AsyncTask{
|
||||
a ACL information changed.
|
||||
x extended attribute information changed.
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
//Example: status=-1
|
||||
regex_list["status"] = new Regex(
|
||||
@ -118,7 +118,7 @@ public class RsyncTask : AsyncTask{
|
||||
|
||||
regex_list["log-created"] = new Regex(
|
||||
"""[0-9\/]+ [0-9:.]+ \[[0-9]+\] ([<>ch.*])([.fdLDS])[+]{9} (.*)""");
|
||||
|
||||
|
||||
regex_list["deleted"] = new Regex(
|
||||
"""\*deleting[ \t]+(.*)""");
|
||||
|
||||
@ -136,7 +136,7 @@ public class RsyncTask : AsyncTask{
|
||||
|
||||
regex_list["log-unchanged"] = new Regex(
|
||||
"""[0-9\/]+ [0-9:.]+ \[[0-9]+\] ([.h])([.fdLDS])[ ]{9} (.*)""");
|
||||
|
||||
|
||||
regex_list["total-size"] = new Regex(
|
||||
"""total size is ([0-9,]+)[ \t]+speedup is [0-9.]+""");
|
||||
|
||||
@ -145,12 +145,12 @@ public class RsyncTask : AsyncTask{
|
||||
log_error (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void prepare() {
|
||||
string script_text = build_script();
|
||||
|
||||
|
||||
log_debug(script_text);
|
||||
|
||||
|
||||
save_bash_script_temp(script_text, script_file);
|
||||
log_debug("RsyncTask:prepare(): saved: %s".printf(script_file));
|
||||
|
||||
@ -173,7 +173,7 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
|
||||
private string build_script() {
|
||||
|
||||
|
||||
var cmd = "export LC_ALL=C.UTF-8\n";
|
||||
|
||||
if (io_nice){
|
||||
@ -222,15 +222,15 @@ public class RsyncTask : AsyncTask{
|
||||
if (dry_run){
|
||||
cmd += " --dry-run";
|
||||
}
|
||||
|
||||
|
||||
if (link_from_path.length > 0){
|
||||
if (!link_from_path.has_suffix("/")){
|
||||
link_from_path = "%s/".printf(link_from_path);
|
||||
}
|
||||
|
||||
|
||||
cmd += " --link-dest='%s'".printf(escape_single_quote(link_from_path));
|
||||
}
|
||||
|
||||
|
||||
if (rsync_log_file.length > 0){
|
||||
cmd += " --log-file='%s'".printf(escape_single_quote(rsync_log_file));
|
||||
}
|
||||
@ -244,27 +244,27 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
|
||||
source_path = remove_trailing_slash(source_path);
|
||||
|
||||
|
||||
dest_path = remove_trailing_slash(dest_path);
|
||||
|
||||
|
||||
cmd += " '%s/'".printf(escape_single_quote(source_path));
|
||||
|
||||
cmd += " '%s/'".printf(escape_single_quote(dest_path));
|
||||
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public Gee.ArrayList<FileItem> parse_log(string log_file_path){
|
||||
|
||||
var list = new Gee.ArrayList<FileItem>();
|
||||
|
||||
|
||||
string log_file = log_file_path;
|
||||
DataOutputStream dos_changes = null;
|
||||
|
||||
|
||||
if (!log_file.has_suffix("-changes")){
|
||||
|
||||
|
||||
string log_file_changes = log_file_path + "-changes";
|
||||
|
||||
|
||||
if (file_exists(log_file_changes)){
|
||||
// use it
|
||||
log_file = log_file_changes;
|
||||
@ -306,15 +306,15 @@ public class RsyncTask : AsyncTask{
|
||||
string item_status = "";
|
||||
|
||||
string item_basepath = path_combine(file_parent(log_file_path), "localhost");
|
||||
|
||||
|
||||
while ((line = dis.read_line(null)) != null) {
|
||||
|
||||
prg_count++;
|
||||
|
||||
|
||||
if (line.strip().length == 0) { continue; }
|
||||
|
||||
item_path = "";
|
||||
|
||||
|
||||
MatchInfo match;
|
||||
if (regex_list["created"].match(line, 0, out match)
|
||||
|| regex_list["log-created"].match(line, 0, out match)) {
|
||||
@ -322,9 +322,9 @@ public class RsyncTask : AsyncTask{
|
||||
if (dos_changes != null){
|
||||
dos_changes.put_string("%s\n".printf(line));
|
||||
}
|
||||
|
||||
|
||||
//log_debug("matched: created:%s".printf(line));
|
||||
|
||||
|
||||
item_path = match.fetch(3).split(" -> ")[0].strip();
|
||||
/*item_type = FileType.REGULAR;
|
||||
if (match.fetch(2) == "d"){
|
||||
@ -337,13 +337,13 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
else if (regex_list["log-deleted"].match(line, 0, out match)
|
||||
|| regex_list["deleted"].match(line, 0, out match)) {
|
||||
|
||||
|
||||
//log_debug("matched: deleted:%s".printf(line));
|
||||
|
||||
if (dos_changes != null){
|
||||
dos_changes.put_string("%s\n".printf(line));
|
||||
}
|
||||
|
||||
|
||||
item_path = match.fetch(1).split(" -> ")[0].strip();
|
||||
//item_type = item_path.has_suffix("/") ? FileType.DIRECTORY : FileType.REGULAR;
|
||||
item_status = "deleted";
|
||||
@ -356,16 +356,16 @@ public class RsyncTask : AsyncTask{
|
||||
if (dos_changes != null){
|
||||
dos_changes.put_string("%s\n".printf(line));
|
||||
}
|
||||
|
||||
|
||||
item_path = match.fetch(12).split(" -> ")[0].strip();
|
||||
|
||||
|
||||
/*if (match.fetch(2) == "d"){
|
||||
item_type = FileType.DIRECTORY;
|
||||
}
|
||||
else if (match.fetch(2) == "L"){
|
||||
item_is_symlink = true;
|
||||
}*/
|
||||
|
||||
|
||||
if (match.fetch(3) == "c"){
|
||||
item_status = "checksum";
|
||||
}
|
||||
@ -391,9 +391,9 @@ public class RsyncTask : AsyncTask{
|
||||
else{
|
||||
log_debug("not-matched: %s".printf(line));
|
||||
}
|
||||
|
||||
|
||||
if ((item_path.length > 0) && (item_path != "/./") && (item_path != "./")){
|
||||
|
||||
|
||||
item_disk_path = path_combine(item_basepath, item_path);
|
||||
|
||||
var item = new FileItem.from_disk_path_with_basic_info(item_disk_path);
|
||||
@ -414,16 +414,16 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
|
||||
log_debug("RsyncTask: parse_log(): exit");
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
// execution ----------------------------
|
||||
|
||||
public void execute() {
|
||||
|
||||
|
||||
log_debug("RsyncTask:execute()");
|
||||
|
||||
|
||||
prepare();
|
||||
|
||||
/*log_debug(string.nfill(70,'='));
|
||||
@ -431,12 +431,12 @@ public class RsyncTask : AsyncTask{
|
||||
log_debug(string.nfill(70,'='));
|
||||
log_debug(file_read(script_file));
|
||||
log_debug(string.nfill(70,'='));*/
|
||||
|
||||
|
||||
begin();
|
||||
|
||||
if (status == AppStatus.RUNNING){
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,15 +444,15 @@ public class RsyncTask : AsyncTask{
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(out_line);
|
||||
}
|
||||
|
||||
|
||||
public override void parse_stderr_line(string err_line){
|
||||
if (is_terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
update_progress_parse_console_output(err_line);
|
||||
}
|
||||
|
||||
@ -467,7 +467,7 @@ public class RsyncTask : AsyncTask{
|
||||
prg_count = status_line_count;
|
||||
progress = (prg_count * 1.0) / prg_count_total;
|
||||
}
|
||||
|
||||
|
||||
//MatchInfo match;
|
||||
//if (regex_list["status"].match(line, 0, out match)) {
|
||||
// status_line = match.fetch(12);
|
||||
@ -481,13 +481,13 @@ public class RsyncTask : AsyncTask{
|
||||
if (regex_list["created"].match(line, 0, out match)) {
|
||||
|
||||
//log_debug("matched: created:%s".printf(line));
|
||||
|
||||
|
||||
count_created++;
|
||||
status_line = match.fetch(3).split(" -> ")[0].strip();
|
||||
log.append(line + "\n");
|
||||
}
|
||||
else if (regex_list["deleted"].match(line, 0, out match)) {
|
||||
|
||||
|
||||
//log_debug("matched: deleted:%s".printf(line));
|
||||
|
||||
count_deleted++;
|
||||
@ -495,7 +495,7 @@ public class RsyncTask : AsyncTask{
|
||||
log.append(line + "\n");
|
||||
}
|
||||
else if (regex_list["unchanged"].match(line, 0, out match)) {
|
||||
|
||||
|
||||
//log_debug("matched: unchanged:%s".printf(line));
|
||||
|
||||
count_unchanged++;
|
||||
@ -508,7 +508,7 @@ public class RsyncTask : AsyncTask{
|
||||
count_modified++;
|
||||
status_line = match.fetch(12).split(" -> ")[0].strip();
|
||||
log.append(line + "\n");
|
||||
|
||||
|
||||
if (match.fetch(3) == "c"){
|
||||
count_checksum++;
|
||||
}
|
||||
@ -542,7 +542,7 @@ public class RsyncTask : AsyncTask{
|
||||
}
|
||||
|
||||
protected override void finish_task(){
|
||||
|
||||
|
||||
if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) {
|
||||
status = AppStatus.FINISHED;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ using TeeJee.FileSystem;
|
||||
using TeeJee.ProcessHelper;
|
||||
|
||||
public class SystemUser : GLib.Object {
|
||||
|
||||
|
||||
public string name = "";
|
||||
public string password = "";
|
||||
public int uid = -1;
|
||||
@ -57,7 +57,7 @@ public class SystemUser : GLib.Object {
|
||||
public bool has_encrypted_private_dirs = false;
|
||||
public Gee.ArrayList<string> encrypted_dirs = new Gee.ArrayList<string>();
|
||||
public Gee.ArrayList<string> encrypted_private_dirs = new Gee.ArrayList<string>();
|
||||
|
||||
|
||||
public bool is_selected = false;
|
||||
|
||||
public static Gee.HashMap<string,SystemUser> all_users;
|
||||
@ -67,7 +67,7 @@ public class SystemUser : GLib.Object {
|
||||
}
|
||||
|
||||
public static void query_users(bool no_passwords = true){
|
||||
|
||||
|
||||
if (no_passwords){
|
||||
all_users = read_users_from_file("/etc/passwd","","");
|
||||
}
|
||||
@ -94,13 +94,13 @@ public class SystemUser : GLib.Object {
|
||||
}
|
||||
|
||||
public static Gee.HashMap<string,SystemUser> read_users_from_file(
|
||||
|
||||
|
||||
string passwd_file, string shadow_file, string password){
|
||||
|
||||
|
||||
var list = new Gee.HashMap<string,SystemUser>();
|
||||
|
||||
// read 'passwd' file ---------------------------------
|
||||
|
||||
|
||||
string txt = file_read(passwd_file);
|
||||
|
||||
if (txt.length == 0){
|
||||
@ -122,7 +122,7 @@ public class SystemUser : GLib.Object {
|
||||
}
|
||||
|
||||
// read 'shadow' file ---------------------------------
|
||||
|
||||
|
||||
txt = file_read(shadow_file);
|
||||
|
||||
if (txt.length == 0){
|
||||
@ -140,11 +140,11 @@ public class SystemUser : GLib.Object {
|
||||
}
|
||||
|
||||
private static SystemUser? parse_line_passwd(string line){
|
||||
|
||||
|
||||
if ((line == null) || (line.length == 0)){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
SystemUser user = null;
|
||||
|
||||
//teejee:x:504:504:Tony George:/home/teejee:/bin/bash
|
||||
@ -182,16 +182,16 @@ public class SystemUser : GLib.Object {
|
||||
log_error("'passwd' file contains a record with non-standard fields" + ": %d".printf(fields.length));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private static SystemUser? parse_line_shadow(string line, Gee.HashMap<string,SystemUser> list){
|
||||
|
||||
|
||||
if ((line == null) || (line.length == 0)){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
SystemUser user = null;
|
||||
|
||||
//root:$1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1:15651:0:99999:7:::
|
||||
@ -228,9 +228,9 @@ public class SystemUser : GLib.Object {
|
||||
public void check_encrypted_dirs() {
|
||||
|
||||
// check encrypted home ------------------------------
|
||||
|
||||
|
||||
string ecryptfs_mount_file = "/home/.ecryptfs/%s/.ecryptfs/Private.mnt".printf(name);
|
||||
|
||||
|
||||
if (file_exists(ecryptfs_mount_file)){
|
||||
|
||||
string txt = file_read(ecryptfs_mount_file);
|
||||
@ -240,7 +240,7 @@ public class SystemUser : GLib.Object {
|
||||
string path = line.strip();
|
||||
|
||||
if (path.length == 0){ continue; }
|
||||
|
||||
|
||||
if (path == home_path){
|
||||
has_encrypted_home = true;
|
||||
}
|
||||
@ -252,7 +252,7 @@ public class SystemUser : GLib.Object {
|
||||
// check encrypted Private dirs --------------------------
|
||||
|
||||
ecryptfs_mount_file = "%s/.ecryptfs/Private.mnt".printf(home_path);
|
||||
|
||||
|
||||
if (file_exists(ecryptfs_mount_file)){
|
||||
|
||||
string txt = file_read(ecryptfs_mount_file);
|
||||
@ -262,7 +262,7 @@ public class SystemUser : GLib.Object {
|
||||
string path = line.strip();
|
||||
|
||||
if (path.length == 0){ continue; }
|
||||
|
||||
|
||||
if (path != home_path){
|
||||
has_encrypted_private_dirs = true;
|
||||
encrypted_private_dirs.add(path);
|
||||
@ -272,7 +272,7 @@ public class SystemUser : GLib.Object {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool is_system{
|
||||
get {
|
||||
return ((uid != 0) && (uid < 1000)) || (uid == 65534) || (name == "PinguyBuilder"); // 65534 - nobody
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace TeeJee.FileSystem{
|
||||
|
||||
/* Convenience functions for handling files and directories */
|
||||
@ -39,9 +39,9 @@ namespace TeeJee.FileSystem{
|
||||
public const int64 MiB = 1024 * KiB;
|
||||
public const int64 GiB = 1024 * MiB;
|
||||
public const int64 TiB = 1024 * GiB;
|
||||
|
||||
|
||||
// path helpers ----------------------------
|
||||
|
||||
|
||||
public string file_parent(string file_path){
|
||||
return File.new_for_path(file_path).get_parent().get_path();
|
||||
}
|
||||
@ -62,17 +62,17 @@ namespace TeeJee.FileSystem{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// file helpers -----------------------------
|
||||
|
||||
public bool file_or_dir_exists(string item_path){
|
||||
|
||||
|
||||
/* check if item exists on disk*/
|
||||
|
||||
var item = File.parse_name(item_path);
|
||||
return item.query_exists();
|
||||
}
|
||||
|
||||
|
||||
public bool file_exists (string file_path){
|
||||
/* Check if file exists */
|
||||
return (FileUtils.test(file_path, GLib.FileTest.EXISTS)
|
||||
@ -136,12 +136,12 @@ namespace TeeJee.FileSystem{
|
||||
try{
|
||||
|
||||
dir_create(file_parent(file_path));
|
||||
|
||||
|
||||
var file = File.new_for_path (file_path);
|
||||
if (file.query_exists ()) {
|
||||
file.delete ();
|
||||
}
|
||||
|
||||
|
||||
var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION);
|
||||
var data_stream = new DataOutputStream (file_stream);
|
||||
data_stream.put_string (contents);
|
||||
@ -193,7 +193,7 @@ namespace TeeJee.FileSystem{
|
||||
|
||||
try {
|
||||
var file = File.new_for_path (file_path);
|
||||
|
||||
|
||||
if (file.query_exists()) {
|
||||
|
||||
var info = file.query_info("%s".printf(FileAttribute.STANDARD_TYPE), FileQueryInfoFlags.NOFOLLOW_SYMLINKS); // don't follow symlinks
|
||||
@ -206,31 +206,31 @@ namespace TeeJee.FileSystem{
|
||||
catch (Error e) {
|
||||
log_error (e.message);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool file_gzip (string src_file){
|
||||
|
||||
|
||||
string dst_file = src_file + ".gz";
|
||||
file_delete(dst_file);
|
||||
|
||||
|
||||
string cmd = "gzip '%s'".printf(escape_single_quote(src_file));
|
||||
string std_out, std_err;
|
||||
exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
return file_exists(dst_file);
|
||||
}
|
||||
|
||||
public bool file_gunzip (string src_file){
|
||||
|
||||
|
||||
string dst_file = src_file;
|
||||
file_delete(dst_file);
|
||||
|
||||
|
||||
string cmd = "gunzip '%s'".printf(escape_single_quote(src_file));
|
||||
string std_out, std_err;
|
||||
exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
return file_exists(dst_file);
|
||||
}
|
||||
|
||||
@ -252,20 +252,20 @@ namespace TeeJee.FileSystem{
|
||||
return path_combine(GLib.Environment.get_current_dir(), file_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// file info -----------------
|
||||
|
||||
public int64 file_get_size(string file_path){
|
||||
|
||||
|
||||
try{
|
||||
|
||||
|
||||
File file = File.parse_name (file_path);
|
||||
|
||||
|
||||
if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){
|
||||
|
||||
|
||||
if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR)
|
||||
&& !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){
|
||||
|
||||
|
||||
return file.query_info("standard::size",0).get_size();
|
||||
}
|
||||
}
|
||||
@ -289,10 +289,10 @@ namespace TeeJee.FileSystem{
|
||||
catch (Error e) {
|
||||
log_error (e.message);
|
||||
}
|
||||
|
||||
|
||||
return (new DateTime.from_unix_utc(0)); //1970
|
||||
}
|
||||
|
||||
|
||||
public string file_get_symlink_target(string file_path){
|
||||
try{
|
||||
FileInfo info;
|
||||
@ -305,28 +305,28 @@ namespace TeeJee.FileSystem{
|
||||
catch (Error e) {
|
||||
log_error (e.message);
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// directory helpers ----------------------
|
||||
|
||||
|
||||
public bool dir_exists (string dir_path){
|
||||
/* Check if directory exists */
|
||||
return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR));
|
||||
}
|
||||
|
||||
|
||||
public bool dir_create (string dir_path, bool show_message = false){
|
||||
|
||||
/* Creates a directory along with parents */
|
||||
|
||||
try{
|
||||
var dir = File.parse_name (dir_path);
|
||||
|
||||
|
||||
if (dir.query_exists () == false) {
|
||||
|
||||
|
||||
bool ok = dir.make_directory_with_parents (null);
|
||||
|
||||
|
||||
if (show_message){
|
||||
if (ok){
|
||||
log_msg(_("Created directory") + ": %s".printf(dir_path));
|
||||
@ -336,7 +336,7 @@ namespace TeeJee.FileSystem{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Error e) {
|
||||
@ -347,20 +347,20 @@ namespace TeeJee.FileSystem{
|
||||
}
|
||||
|
||||
public bool dir_delete (string dir_path, bool show_message = false){
|
||||
|
||||
|
||||
/* Recursively deletes directory along with contents */
|
||||
|
||||
|
||||
if (!dir_exists(dir_path)){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string cmd = "rm -rf '%s'".printf(escape_single_quote(dir_path));
|
||||
|
||||
|
||||
log_debug(cmd);
|
||||
|
||||
|
||||
string std_out, std_err;
|
||||
int status = exec_sync(cmd, out std_out, out std_err);
|
||||
|
||||
|
||||
if (show_message){
|
||||
if (status == 0){
|
||||
log_msg(_("Deleted directory") + ": %s".printf(dir_path));
|
||||
@ -371,7 +371,7 @@ namespace TeeJee.FileSystem{
|
||||
log_error(std_err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
@ -399,20 +399,20 @@ namespace TeeJee.FileSystem{
|
||||
}
|
||||
|
||||
public bool filesystem_supports_hardlinks(string path, out bool is_readonly){
|
||||
|
||||
|
||||
bool supports_hardlinks = false;
|
||||
is_readonly = false;
|
||||
|
||||
|
||||
var test_file = path_combine(path, random_string() + "~");
|
||||
|
||||
|
||||
if (file_write(test_file,"")){
|
||||
|
||||
|
||||
var test_file2 = path_combine(path, random_string() + "~");
|
||||
|
||||
var cmd = "ln '%s' '%s'".printf(
|
||||
escape_single_quote(test_file),
|
||||
escape_single_quote(test_file2));
|
||||
|
||||
|
||||
log_debug(cmd);
|
||||
|
||||
int status = exec_sync(cmd);
|
||||
@ -421,18 +421,18 @@ namespace TeeJee.FileSystem{
|
||||
escape_single_quote(test_file));
|
||||
|
||||
log_debug(cmd);
|
||||
|
||||
|
||||
string std_out, std_err;
|
||||
status = exec_sync(cmd, out std_out, out std_err);
|
||||
log_debug("stdout: %s".printf(std_out));
|
||||
|
||||
|
||||
int64 count = 0;
|
||||
if (int64.try_parse(std_out, out count)){
|
||||
if (count > 1){
|
||||
supports_hardlinks = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
file_delete(test_file2); // delete if exists
|
||||
file_delete(test_file);
|
||||
}
|
||||
@ -444,9 +444,9 @@ namespace TeeJee.FileSystem{
|
||||
}
|
||||
|
||||
public Gee.ArrayList<string> dir_list_names(string path){
|
||||
|
||||
|
||||
var list = new Gee.ArrayList<string>();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File f_home = File.new_for_path (path);
|
||||
@ -469,15 +469,15 @@ namespace TeeJee.FileSystem{
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public bool chown(string dir_path, string user, string group = user){
|
||||
string cmd = "chown %s:%s -R '%s'".printf(user, group, escape_single_quote(dir_path));
|
||||
int status = exec_sync(cmd, null, null);
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
|
||||
// dir info -------------------
|
||||
|
||||
|
||||
// dep: find wc TODO: rewrite
|
||||
public long dir_count(string path){
|
||||
|
||||
@ -517,7 +517,7 @@ namespace TeeJee.FileSystem{
|
||||
public string format_file_size (
|
||||
uint64 size, bool binary_units = false,
|
||||
string unit = "", bool show_units = true, int decimals = 1){
|
||||
|
||||
|
||||
uint64 unit_k = binary_units ? 1024 : 1000;
|
||||
uint64 unit_m = binary_units ? 1024 * unit_k : 1000 * unit_k;
|
||||
uint64 unit_g = binary_units ? 1024 * unit_m : 1000 * unit_m;
|
||||
@ -526,7 +526,7 @@ namespace TeeJee.FileSystem{
|
||||
//log_debug("size: %'lld".printf(size));
|
||||
|
||||
string txt = "";
|
||||
|
||||
|
||||
if ((size > unit_t) && ((unit.length == 0) || (unit == "t"))){
|
||||
txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_t));
|
||||
if (show_units){
|
||||
@ -564,17 +564,17 @@ namespace TeeJee.FileSystem{
|
||||
}
|
||||
|
||||
public string escape_single_quote(string file_path){
|
||||
|
||||
|
||||
return file_path.replace("'","'\\''");
|
||||
}
|
||||
|
||||
|
||||
// dep: chmod
|
||||
public int chmod (string file, string permission){
|
||||
|
||||
string cmd = "chmod %s '%s'".printf(permission, escape_single_quote(file));
|
||||
return exec_sync (cmd, null, null);
|
||||
}
|
||||
|
||||
|
||||
public int rsync(string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){
|
||||
|
||||
/* Sync files with rsync */
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using Json;
|
||||
|
||||
namespace TeeJee.JsonHelper{
|
||||
@ -70,7 +70,7 @@ namespace TeeJee.JsonHelper{
|
||||
return def_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public uint64 json_get_uint64(Json.Object jobj, string member, uint64 def_value){
|
||||
if (jobj.has_member(member)){
|
||||
return uint64.parse(jobj.get_string_member(member));
|
||||
@ -85,7 +85,7 @@ namespace TeeJee.JsonHelper{
|
||||
Json.Object jobj,
|
||||
string member,
|
||||
Gee.ArrayList<string> def_value){
|
||||
|
||||
|
||||
if (jobj.has_member(member)){
|
||||
var jarray = jobj.get_array_member(member);
|
||||
var list = new Gee.ArrayList<string>();
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace TeeJee.Logging{
|
||||
|
||||
/* Functions for logging messages to console and log files */
|
||||
@ -73,7 +73,7 @@ namespace TeeJee.Logging{
|
||||
|
||||
public void log_error (string message, bool highlight = false,
|
||||
bool is_warning = false){
|
||||
|
||||
|
||||
if (!LOG_ENABLE) { return; }
|
||||
|
||||
string msg = "";
|
||||
@ -98,10 +98,10 @@ namespace TeeJee.Logging{
|
||||
|
||||
stdout.printf (msg);
|
||||
stdout.flush();
|
||||
|
||||
|
||||
try {
|
||||
string str = "[%s] %s: %s\n".printf(timestamp(), prefix, message);
|
||||
|
||||
|
||||
if (dos_log != null){
|
||||
dos_log.put_string (str);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace TeeJee.Misc {
|
||||
|
||||
/* Various utility functions */
|
||||
@ -38,9 +38,9 @@ namespace TeeJee.Misc {
|
||||
Intl.setlocale(GLib.LocaleCategory.COLLATE, type);
|
||||
Intl.setlocale(GLib.LocaleCategory.TIME, type);
|
||||
}
|
||||
|
||||
|
||||
// timestamp ----------------
|
||||
|
||||
|
||||
public string timestamp (bool show_millis = false){
|
||||
|
||||
/* Returns a formatted timestamp string */
|
||||
@ -48,7 +48,7 @@ namespace TeeJee.Misc {
|
||||
// NOTE: format() does not support milliseconds
|
||||
|
||||
DateTime now = new GLib.DateTime.now_local();
|
||||
|
||||
|
||||
if (show_millis){
|
||||
var msec = now.get_microsecond () / 1000;
|
||||
return "%s.%03d".printf(now.format("%H:%M:%S"), msec);
|
||||
@ -78,11 +78,11 @@ namespace TeeJee.Misc {
|
||||
public string format_date(DateTime date){
|
||||
return date.format ("%Y-%m-%d %H:%M");
|
||||
}
|
||||
|
||||
|
||||
public string format_date_12_hour(DateTime date){
|
||||
return date.format ("%Y-%m-%d %I:%M %p");
|
||||
}
|
||||
|
||||
|
||||
public string format_duration (long millis){
|
||||
|
||||
/* Converts time in milliseconds to format '00:00:00.0' */
|
||||
@ -108,7 +108,7 @@ namespace TeeJee.Misc {
|
||||
txt += "%.0fs".printf(secs);
|
||||
return txt;
|
||||
}
|
||||
|
||||
|
||||
public double parse_time (string time){
|
||||
|
||||
/* Converts time in format '00:00:00.0' to milliseconds */
|
||||
@ -127,7 +127,7 @@ namespace TeeJee.Misc {
|
||||
string[] arr = str.split(search);
|
||||
string new_txt = "";
|
||||
bool first = true;
|
||||
|
||||
|
||||
foreach(string part in arr){
|
||||
if (first){
|
||||
new_txt += part;
|
||||
@ -148,20 +148,20 @@ namespace TeeJee.Misc {
|
||||
|
||||
return new_txt;
|
||||
}
|
||||
|
||||
|
||||
public string escape_html(string html, bool pango_markup = true){
|
||||
string txt = html;
|
||||
|
||||
if (pango_markup){
|
||||
txt = txt
|
||||
.replace("\\u00", "")
|
||||
.replace("\\x" , "");
|
||||
.replace("\\x" , "");
|
||||
}
|
||||
else{
|
||||
txt = txt
|
||||
.replace(" ", " "); //pango markup throws an error with
|
||||
}
|
||||
|
||||
|
||||
txt = txt
|
||||
.replace("&" , "&")
|
||||
.replace("\"", """)
|
||||
@ -197,7 +197,7 @@ namespace TeeJee.Misc {
|
||||
public DateTime datetime_from_string (string date_time_string){
|
||||
|
||||
/* Converts date time string to DateTime
|
||||
*
|
||||
*
|
||||
* Supported inputs:
|
||||
* 'yyyy-MM-dd'
|
||||
* 'yyyy-MM-dd HH'
|
||||
@ -257,7 +257,7 @@ namespace TeeJee.Misc {
|
||||
|
||||
private string pad_numbers_in_string(
|
||||
string input, int max_length = 3, char pad_char = '0'){
|
||||
|
||||
|
||||
string sequence = "";
|
||||
string output = "";
|
||||
bool seq_started = false;
|
||||
@ -293,7 +293,7 @@ namespace TeeJee.Misc {
|
||||
output += sequence;
|
||||
sequence = "";
|
||||
}
|
||||
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -21,30 +21,30 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace TeeJee.ProcessHelper{
|
||||
|
||||
|
||||
using TeeJee.Logging;
|
||||
using TeeJee.FileSystem;
|
||||
using TeeJee.Misc;
|
||||
|
||||
public string TEMP_DIR;
|
||||
|
||||
|
||||
/* Convenience functions for executing commands and managing processes */
|
||||
|
||||
// execute process ---------------------------------
|
||||
|
||||
|
||||
public static void init_tmp(string subdir_name){
|
||||
string std_out, std_err;
|
||||
|
||||
TEMP_DIR = Environment.get_tmp_dir() + "/" + random_string();
|
||||
dir_create(TEMP_DIR);
|
||||
chmod(TEMP_DIR, "0750");
|
||||
|
||||
|
||||
exec_script_sync("echo 'ok'",out std_out,out std_err, true);
|
||||
|
||||
|
||||
if ((std_out == null) || (std_out.strip() != "ok")){
|
||||
|
||||
|
||||
TEMP_DIR = Environment.get_home_dir() + "/.temp/" + random_string();
|
||||
dir_create(TEMP_DIR);
|
||||
chmod(TEMP_DIR, "0750");
|
||||
@ -58,7 +58,7 @@ namespace TeeJee.ProcessHelper{
|
||||
dir_create(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
public int exec_sync (string cmd, out string? std_out = null, out string? std_err = null){
|
||||
|
||||
/* Executes single command synchronously.
|
||||
@ -75,10 +75,10 @@ namespace TeeJee.ProcessHelper{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int exec_script_sync (string script,
|
||||
out string? std_out = null, out string? std_err = null,
|
||||
bool supress_errors = false, bool run_as_admin = false,
|
||||
bool supress_errors = false, bool run_as_admin = false,
|
||||
bool cleanup_tmp = true, bool print_to_terminal = false){
|
||||
|
||||
/* Executes commands synchronously.
|
||||
@ -89,18 +89,18 @@ namespace TeeJee.ProcessHelper{
|
||||
|
||||
string sh_file = save_bash_script_temp(script, null, true, supress_errors);
|
||||
string sh_file_admin = "";
|
||||
|
||||
|
||||
if (run_as_admin){
|
||||
|
||||
|
||||
var script_admin = "#!/bin/bash\n";
|
||||
script_admin += "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY";
|
||||
script_admin += " '%s'".printf(escape_single_quote(sh_file));
|
||||
|
||||
|
||||
sh_file_admin = GLib.Path.build_filename(file_parent(sh_file),"script-admin.sh");
|
||||
|
||||
save_bash_script_temp(script_admin, sh_file_admin, true, supress_errors);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
string[] argv = new string[1];
|
||||
if (run_as_admin){
|
||||
@ -115,7 +115,7 @@ namespace TeeJee.ProcessHelper{
|
||||
int exit_code;
|
||||
|
||||
if (print_to_terminal){
|
||||
|
||||
|
||||
Process.spawn_sync (
|
||||
TEMP_DIR, //working dir
|
||||
argv, //argv
|
||||
@ -128,7 +128,7 @@ namespace TeeJee.ProcessHelper{
|
||||
);
|
||||
}
|
||||
else{
|
||||
|
||||
|
||||
Process.spawn_sync (
|
||||
TEMP_DIR, //working dir
|
||||
argv, //argv
|
||||
@ -147,7 +147,7 @@ namespace TeeJee.ProcessHelper{
|
||||
file_delete(sh_file_admin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
catch (Error e){
|
||||
@ -174,7 +174,7 @@ namespace TeeJee.ProcessHelper{
|
||||
argv[0] = scriptfile;
|
||||
|
||||
string[] env = Environ.get();
|
||||
|
||||
|
||||
Pid child_pid;
|
||||
Process.spawn_async_with_pipes(
|
||||
TEMP_DIR, //working dir
|
||||
@ -196,7 +196,7 @@ namespace TeeJee.ProcessHelper{
|
||||
bool force_locale = true, bool supress_errors = false){
|
||||
|
||||
string sh_path = script_path;
|
||||
|
||||
|
||||
/* Creates a temporary bash script with given commands
|
||||
* Returns the script file path */
|
||||
|
||||
@ -251,9 +251,9 @@ namespace TeeJee.ProcessHelper{
|
||||
public void exec_process_new_session(string command){
|
||||
exec_script_async("setsid %s &".printf(command));
|
||||
}
|
||||
|
||||
|
||||
// find process -------------------------------
|
||||
|
||||
|
||||
// dep: which
|
||||
public string get_cmd_path (string cmd_tool){
|
||||
|
||||
@ -288,7 +288,7 @@ namespace TeeJee.ProcessHelper{
|
||||
|
||||
string std_out, std_err;
|
||||
exec_sync("pidof \"%s\"".printf(name), out std_out, out std_err);
|
||||
|
||||
|
||||
if (std_out != null){
|
||||
string[] arr = std_out.split ("\n");
|
||||
if (arr.length > 0){
|
||||
@ -304,7 +304,7 @@ namespace TeeJee.ProcessHelper{
|
||||
/* Searches for process using the command line used to start the process.
|
||||
* Returns the process id if found.
|
||||
* */
|
||||
|
||||
|
||||
try {
|
||||
FileEnumerator enumerator;
|
||||
FileInfo info;
|
||||
@ -386,7 +386,7 @@ namespace TeeJee.ProcessHelper{
|
||||
|
||||
return (ret_val == 0);
|
||||
}
|
||||
|
||||
|
||||
// dep: ps TODO: Rewrite using /proc
|
||||
public int[] get_process_children (Pid parent_pid){
|
||||
|
||||
@ -414,7 +414,7 @@ namespace TeeJee.ProcessHelper{
|
||||
}
|
||||
|
||||
// manage process ---------------------------------
|
||||
|
||||
|
||||
public void process_quit(Pid process_pid, bool killChildren = true){
|
||||
|
||||
/* Kills specified process and its children (optional).
|
||||
@ -432,14 +432,14 @@ namespace TeeJee.ProcessHelper{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void process_kill(Pid process_pid, bool killChildren = true){
|
||||
|
||||
/* Kills specified process and its children (optional).
|
||||
* Sends signal SIGKILL to the process to kill it forcefully.
|
||||
* It is recommended to use the function process_quit() instead.
|
||||
* */
|
||||
|
||||
|
||||
int[] child_pids = get_process_children (process_pid);
|
||||
Posix.kill (process_pid, Posix.Signal.KILL);
|
||||
|
||||
@ -472,7 +472,7 @@ namespace TeeJee.ProcessHelper{
|
||||
public void process_quit_by_name(string cmd_name, string cmd_to_match, bool exact_match){
|
||||
|
||||
/* Kills a specific command */
|
||||
|
||||
|
||||
string std_out, std_err;
|
||||
exec_sync ("ps w -C '%s'".printf(cmd_name), out std_out, out std_err);
|
||||
//use 'ps ew -C conky' for all users
|
||||
@ -489,7 +489,7 @@ namespace TeeJee.ProcessHelper{
|
||||
}
|
||||
|
||||
// process priority ---------------------------------------
|
||||
|
||||
|
||||
public void process_set_priority (Pid procID, int prio){
|
||||
|
||||
/* Set process priority */
|
||||
|
@ -21,25 +21,25 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace TeeJee.System{
|
||||
|
||||
using TeeJee.ProcessHelper;
|
||||
using TeeJee.Logging;
|
||||
using TeeJee.Misc;
|
||||
using TeeJee.FileSystem;
|
||||
|
||||
|
||||
// user ---------------------------------------------------
|
||||
|
||||
public bool user_is_admin(){
|
||||
|
||||
|
||||
return (get_user_id_effective() == 0);
|
||||
}
|
||||
|
||||
|
||||
public int get_user_id(){
|
||||
|
||||
// returns actual user id of current user (even for applications executed with sudo and pkexec)
|
||||
|
||||
|
||||
string pkexec_uid = GLib.Environment.get_variable("PKEXEC_UID");
|
||||
|
||||
if (pkexec_uid != null){
|
||||
@ -56,7 +56,7 @@ namespace TeeJee.System{
|
||||
}
|
||||
|
||||
public int get_user_id_effective(){
|
||||
|
||||
|
||||
// returns effective user id (0 for applications executed with sudo and pkexec)
|
||||
|
||||
int uid = -1;
|
||||
@ -69,37 +69,37 @@ namespace TeeJee.System{
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
public string get_username(){
|
||||
|
||||
// returns actual username of current user (even for applications executed with sudo and pkexec)
|
||||
|
||||
|
||||
return get_username_from_uid(get_user_id());
|
||||
}
|
||||
|
||||
public string get_username_effective(){
|
||||
|
||||
// returns effective user id ('root' for applications executed with sudo and pkexec)
|
||||
|
||||
|
||||
return get_username_from_uid(get_user_id_effective());
|
||||
}
|
||||
|
||||
public int get_user_id_from_username(string username){
|
||||
|
||||
|
||||
// check local user accounts in /etc/passwd -------------------
|
||||
|
||||
foreach(var line in file_read("/etc/passwd").split("\n")){
|
||||
|
||||
|
||||
var arr = line.split(":");
|
||||
|
||||
|
||||
if ((arr.length >= 3) && (arr[0] == username)){
|
||||
|
||||
|
||||
return int.parse(arr[2]);
|
||||
}
|
||||
}
|
||||
|
||||
// not found --------------------
|
||||
|
||||
|
||||
log_error("UserId not found for userName: %s".printf(username));
|
||||
|
||||
return -1;
|
||||
@ -108,19 +108,19 @@ namespace TeeJee.System{
|
||||
public string get_username_from_uid(int user_id){
|
||||
|
||||
// check local user accounts in /etc/passwd -------------------
|
||||
|
||||
|
||||
foreach(var line in file_read("/etc/passwd").split("\n")){
|
||||
|
||||
|
||||
var arr = line.split(":");
|
||||
|
||||
|
||||
if ((arr.length >= 3) && (arr[2] == user_id.to_string())){
|
||||
|
||||
|
||||
return arr[0];
|
||||
}
|
||||
}
|
||||
|
||||
// not found --------------------
|
||||
|
||||
|
||||
log_error("Username not found for uid: %d".printf(user_id));
|
||||
|
||||
return "";
|
||||
@ -129,11 +129,11 @@ namespace TeeJee.System{
|
||||
public string get_user_home(string username = get_username()){
|
||||
|
||||
// check local user accounts in /etc/passwd -------------------
|
||||
|
||||
|
||||
foreach(var line in file_read("/etc/passwd").split("\n")){
|
||||
|
||||
|
||||
var arr = line.split(":");
|
||||
|
||||
|
||||
if ((arr.length >= 6) && (arr[0] == username)){
|
||||
|
||||
return arr[5];
|
||||
@ -152,7 +152,7 @@ namespace TeeJee.System{
|
||||
}
|
||||
|
||||
// application -----------------------------------------------
|
||||
|
||||
|
||||
public string get_app_path(){
|
||||
|
||||
/* Get path of current process */
|
||||
@ -250,7 +250,7 @@ namespace TeeJee.System{
|
||||
|
||||
public Gee.ArrayList<string> list_dir_names(string path){
|
||||
var list = new Gee.ArrayList<string>();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File f_home = File.new_for_path (path);
|
||||
@ -276,7 +276,7 @@ namespace TeeJee.System{
|
||||
}
|
||||
|
||||
// internet helpers ----------------------
|
||||
|
||||
|
||||
public bool shutdown (){
|
||||
|
||||
/* Shutdown the system immediately */
|
||||
@ -297,7 +297,7 @@ namespace TeeJee.System{
|
||||
string path = get_cmd_path(command);
|
||||
return ((path != null) && (path.length > 0));
|
||||
}
|
||||
|
||||
|
||||
// open -----------------------------
|
||||
|
||||
public bool xdg_open (string file, string user = ""){
|
||||
@ -327,7 +327,7 @@ namespace TeeJee.System{
|
||||
|
||||
string path;
|
||||
int status;
|
||||
|
||||
|
||||
if (xdg_open_try_first){
|
||||
//try using xdg-open
|
||||
path = get_cmd_path ("xdg-open");
|
||||
@ -340,7 +340,7 @@ namespace TeeJee.System{
|
||||
|
||||
foreach(string app_name in
|
||||
new string[]{ "nemo", "nautilus", "thunar", "io.elementary.files", "pantheon-files", "marlin", "dolphin" }){
|
||||
|
||||
|
||||
path = get_cmd_path (app_name);
|
||||
if ((path != null)&&(path != "")){
|
||||
string cmd = "%s '%s'".printf(app_name, escape_single_quote(dir_path));
|
||||
@ -369,7 +369,7 @@ namespace TeeJee.System{
|
||||
string path;
|
||||
int status;
|
||||
string cmd;
|
||||
|
||||
|
||||
path = get_cmd_path ("exo-open");
|
||||
if ((path != null)&&(path != "")){
|
||||
cmd = "exo-open '%s'".printf(escape_single_quote(txt_file));
|
||||
@ -394,7 +394,7 @@ namespace TeeJee.System{
|
||||
string path;
|
||||
int status;
|
||||
//string cmd;
|
||||
|
||||
|
||||
path = get_cmd_path ("exo-open");
|
||||
if ((path != null)&&(path != "")){
|
||||
status = exec_script_async ("exo-open \"" + url + "\"");
|
||||
@ -417,15 +417,15 @@ namespace TeeJee.System{
|
||||
}
|
||||
|
||||
public bool using_efi_boot(){
|
||||
|
||||
|
||||
/* Returns true if the system was booted in EFI mode
|
||||
* and false for BIOS mode */
|
||||
|
||||
|
||||
return dir_exists("/sys/firmware/efi");
|
||||
}
|
||||
|
||||
// timers --------------------------------------------------
|
||||
|
||||
|
||||
public GLib.Timer timer_start(){
|
||||
var timer = new GLib.Timer();
|
||||
timer.start();
|
||||
@ -464,7 +464,7 @@ namespace TeeJee.System{
|
||||
timer.stop();
|
||||
}
|
||||
log_msg("%s %lu\n".printf(seconds.to_string(), microseconds));
|
||||
}
|
||||
}
|
||||
|
||||
public void set_numeric_locale(string type){
|
||||
Intl.setlocale(GLib.LocaleCategory.NUMERIC, type);
|
||||
|
@ -34,14 +34,14 @@ public class TimeoutCounter : GLib.Object {
|
||||
public const int DEFAULT_SECONDS_TO_WAIT = 60;
|
||||
public int seconds_to_wait = 60;
|
||||
public bool exit_app = false;
|
||||
|
||||
|
||||
public void kill_process_on_timeout(
|
||||
string process_to_kill, int seconds_to_wait = DEFAULT_SECONDS_TO_WAIT, bool exit_app = false){
|
||||
|
||||
this.process_to_kill = process_to_kill;
|
||||
this.seconds_to_wait = seconds_to_wait;
|
||||
this.exit_app = exit_app;
|
||||
|
||||
|
||||
try {
|
||||
active = true;
|
||||
Thread.create<void> (start_counter_thread, true);
|
||||
@ -55,7 +55,7 @@ public class TimeoutCounter : GLib.Object {
|
||||
this.process_to_kill = "";
|
||||
this.seconds_to_wait = seconds_to_wait;
|
||||
this.exit_app = true;
|
||||
|
||||
|
||||
try {
|
||||
active = true;
|
||||
Thread.create<void> (start_counter_thread, true);
|
||||
@ -68,10 +68,10 @@ public class TimeoutCounter : GLib.Object {
|
||||
public void stop(){
|
||||
active = false;
|
||||
}
|
||||
|
||||
|
||||
public void start_counter_thread(){
|
||||
int secs = 0;
|
||||
|
||||
|
||||
while (active && (secs < seconds_to_wait)){
|
||||
Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 1000);
|
||||
secs += 1;
|
||||
|
12
src/makefile
12
src/makefile
@ -78,7 +78,7 @@ clean:
|
||||
rm -rfv ../release/*.{run,deb}
|
||||
rm -rfv *.c *.o *.mo
|
||||
rm -fv ${app_name} ${app_name}-gtk
|
||||
|
||||
|
||||
install:
|
||||
mkdir -p "$(DESTDIR)$(bindir)"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)"
|
||||
@ -90,7 +90,7 @@ install:
|
||||
mkdir -p "$(DESTDIR)$(appconfdir)"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)/${app_name}"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)/icons"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)/appdata"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)/appdata"
|
||||
mkdir -p "$(DESTDIR)$(sharedir)/metainfo"
|
||||
|
||||
# binary
|
||||
@ -98,7 +98,7 @@ install:
|
||||
install -m 0755 ${app_name}-gtk "$(DESTDIR)$(bindir)"
|
||||
#install -m 0755 ${app_name}-uninstall "$(DESTDIR)$(bindir)"
|
||||
install -m 0755 ${app_name}-launcher "$(DESTDIR)$(bindir)"
|
||||
|
||||
|
||||
# shared files
|
||||
cp -dpr --no-preserve=ownership -t "$(DESTDIR)$(sharedir)/${app_name}" ./share/${app_name}/*
|
||||
find $(DESTDIR)$(sharedir)/${app_name} -type d -exec chmod 755 {} \+
|
||||
@ -121,7 +121,7 @@ install:
|
||||
chmod --recursive 0644 $(DESTDIR)$(sharedir)/icons/hicolor/*/apps/${app_name}.png
|
||||
|
||||
# appdata
|
||||
#install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/appdata"
|
||||
#install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/appdata"
|
||||
install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/metainfo"
|
||||
|
||||
# translations
|
||||
@ -149,7 +149,7 @@ uninstall:
|
||||
|
||||
# man page
|
||||
rm -f "$(DESTDIR)$(man1dir)/${app_name}.1.gz"
|
||||
|
||||
|
||||
# app icon
|
||||
rm -f $(DESTDIR)$(sharedir)/icons/hicolor/*/apps/${app_name}.png
|
||||
|
||||
@ -157,5 +157,5 @@ uninstall:
|
||||
rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/${app_name}.mo
|
||||
|
||||
# appdata
|
||||
rm -f "$(DESTDIR)$(sharedir)/appdata/${app_name}.appdata.xml"
|
||||
rm -f "$(DESTDIR)$(sharedir)/appdata/${app_name}.appdata.xml"
|
||||
rm -f "$(DESTDIR)$(sharedir)/metainfo/${app_name}.appdata.xml"
|
||||
|
@ -22,7 +22,7 @@ MSG_INFO() {
|
||||
if [ "$2" == 0 ]; then
|
||||
add_newline='-n'
|
||||
fi
|
||||
|
||||
|
||||
if [ $COLORS_SUPPORTED -eq 0 ]; then
|
||||
echo -e ${add_newline} "[${Yellow}*${Reset}] ${Green}$1${Reset}"
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user