示例#1
0
        public static void SelectBooksDir()
        {
            var booksDirDialog = new FolderBrowserDialog
            {
                Description = String.Format(UiLang.Get("SelectBookDirPrompt"), Properties.Settings.Default.BooksDir)
            };

            if (Directory.Exists(Properties.Settings.Default.BooksDir))
            {
                booksDirDialog.SelectedPath = Directory.Exists(Properties.Settings.Default.BooksDir) ? Path.GetFullPath(Properties.Settings.Default.BooksDir) : Path.GetFullPath("books");
            }

            var result = booksDirDialog.ShowDialog();

            if (result != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            try
            {
                File.GetAccessControl(booksDirDialog.SelectedPath);

                Properties.Settings.Default.BooksDir = booksDirDialog.SelectedPath;
                Properties.Settings.Default.BooksDirSelectionOffered = true;
                Properties.Settings.Default.Save();
            }
            catch (Exception)
            {
                MessageBox.Show(UiLang.Get("DirAccessDenied"));
            }
        }
示例#2
0
        /// <summary>
        /// Remove a book from the library
        /// </summary>
        /// <param name="bookFile">Path to the folder which contains the book files</param>
        public static void Discard(string bookFile) //Permanently remove a book from the library
        {
            if (!File.Exists(bookFile))
            {
                return;
            }

            const string sqlDeleteBook       = "DELETE FROM books WHERE Path = @Path";
            const string sqlDeleteCategories = "DELETE FROM categories WHERE Path = @Path";

            var bookFileRelativePath = GetRelativeBookFilePath(bookFile);

            try
            {
                File.Delete(bookFile);

                Db.NonQuery(sqlDeleteBook, new[] { new SQLiteParameter("Path", bookFileRelativePath) });
                Db.NonQuery(sqlDeleteCategories, new[] { new SQLiteParameter("Path", bookFileRelativePath) });

                LibraryStructure.GenerateFileTree();
                MainWindow.MW.BookGridReload();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                MainWindow.Info(String.Format(UiLang.Get("DiscardingBookFailed"), bookFile));
                DebugConsole.WriteLine("Book keeper: I was unable to delete " + bookFile + ": " + e);
            }
        }
示例#3
0
        /// <summary>
        /// Go through all database records along with all book files in the library root folder and remove any database entries which point to non-existing files,
        /// then attempt to generate database entries for all book files, which don't have them.
        /// </summary>
        public static void SyncDbWithFileTree()
        {
            MainWindow.Busy(true);

            Task.Factory.StartNew(() =>
            {
                GenerateFileTree();
                Tools.RemoveEmptyDirectories(Properties.Settings.Default.BooksDir);
                var fileTree           = GetFileTree();
                const string sql       = "SELECT Path FROM books";
                const string sqlDelete = "DELETE FROM books WHERE Path = @Path";
                var query    = Db.Query(sql);
                var pathList = new List <string>();

                MainWindow.Busy(UiLang.Get("BusyCleaningDb"));

                //Delete rows pointing to non-existing files
                while (query.Read())
                {
                    if (File.Exists(BookKeeper.GetAbsoluteBookFilePath(query["Path"].ToString())))
                    {
                        pathList.Add(query["Path"].ToString());
                    }
                    else
                    {
                        Db.NonQuery(sqlDelete, new[] { new SQLiteParameter("Path", query["Path"].ToString()) });
                    }
                }

                MainWindow.BusyMax(fileTree.Count(bookFile => !pathList.Contains(BookKeeper.GetRelativeBookFilePath(bookFile))));

                var i = 0;

                //Generate rows for any books missing them
                foreach (
                    var bookFile in
                    fileTree.Where(bookFile => !pathList.Contains(BookKeeper.GetRelativeBookFilePath(bookFile))))
                {
                    MainWindow.Busy(BookKeeper.GetRelativeBookFilePath(bookFile));
                    MainWindow.Busy(i++);

                    try
                    {
                        BookKeeper.GetData(bookFile);
                    }
                    catch (Exception e)
                    {
                        DebugConsole.WriteLine(
                            "Library structure: I found a book file without any entry in the database (" + bookFile +
                            "), but an error occurred during attempted adding: " + e);
                    }
                }

                MainWindow.MW.Dispatcher.Invoke(() => MainWindow.MW.BookGridReload());

                MainWindow.Busy(false);
            });
        }
示例#4
0
        /// <summary>
        /// Displays or removes busy indicator from the main window
        /// </summary>
        /// <param name="toggle">true = turn the indicator on, false = turn it off</param>
        public static void Busy(bool toggle)
        {
            if (toggle)
            {
                _busyOn++;
            }
            else
            {
                _busyOff++;
            }

            if (_busyTitleTimer == null && toggle)
            {
                MW.Dispatcher.Invoke(() =>
                {
                    MW.BusyText.Visibility   = MW.BusyBar.Visibility = Visibility.Visible;
                    MW.MenuStack.IsEnabled   = false;
                    MW.TaskBar.ProgressState = TaskbarItemProgressState.Indeterminate;
                });

                _busyTitleTimer = new Timer(300);

                _busyTitleTimer.Disposed += delegate
                {
                    MW.Dispatcher.Invoke(() => { MW.Title = "Bookpouch"; });
                    //After the timer gets disposed of, set the window title back to default
                };

                _busyTitleTimer.Elapsed += delegate
                {
                    MW.Dispatcher.Invoke(() =>
                    {
                        MW.Title = MW.Title.Substring(0, 2) == "▣•" ? "•▣" : "▣•";
                        //Switch between these two sets of symbols in the window's title, to make it look like a simple animation
                        MW.Title += " Bookpouch - " + UiLang.Get("Working");
                    });
                };

                _busyTitleTimer.Start();
            }
            else if (!toggle && _busyTitleTimer != null && _busyOff >= _busyOn)
            {
                MW.Dispatcher.Invoke(() =>
                {
                    MW.BusyText.Visibility     = MW.BusyBar.Visibility = Visibility.Collapsed;
                    MW.BusyBar.IsIndeterminate = true;
                    MW.TaskBar.ProgressState   = TaskbarItemProgressState.None;
                    MW.MenuStack.IsEnabled     = true;
                    MW.BusyText.Text           = String.Empty;
                });

                _busyTitleTimer.Stop();
                _busyTitleTimer.Dispose();
                _busyTitleTimer = default(Timer);
            }
        }
示例#5
0
        private void Discard_OnClick(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show(String.Format(UiLang.Get("BookDeleteConfirm"), BookInfoGet("Title")), UiLang.Get("BookDeleteConfirmTitle"), MessageBoxButton.YesNo) != MessageBoxResult.Yes)
            {
                return;
            }

            BookKeeper.Discard(_bookFile);
            Close();
        }
示例#6
0
        private void BookGrid_OnKeyUp(object sender, KeyEventArgs e)
        {
            var dataGrid           = (DataGrid)sender;
            var forcedSettingValue = (Keyboard.IsKeyDown(Key.LeftShift)
                ? true
                : (Keyboard.IsKeyDown(Key.LeftCtrl) ? false : (bool?)null));

            switch (e.Key)
            {
            case Key.Delete:
                if (
                    MessageBox.Show(
                        String.Format(UiLang.Get("DeleteBooksConfirm"),
                                      dataGrid.SelectedItems.Count), UiLang.Get("DiscardBook"), MessageBoxButton.YesNo) !=
                    MessageBoxResult.Yes)
                {
                    return;
                }

                foreach (var book in dataGrid.SelectedItems.Cast <Book>().ToList())
                {
                    BookKeeper.Discard(book.BookFile);
                }

                break;

            case Key.F:
                foreach (var book in dataGrid.SelectedItems.Cast <Book>().ToList())
                {
                    BookInfoSet("Favorite", (forcedSettingValue ?? (!book.Favorite)), book.BookFile);
                }

                BookGridReload();     //Reload grid in the main window
                break;

            case Key.S:
                foreach (var book in dataGrid.SelectedItems.Cast <Book>().ToList())
                {
                    BookInfoSet("Sync", (forcedSettingValue ?? (!book.Sync)), book.BookFile);
                }

                BookGridReload();     //Reload grid in the main window
                break;

            case Key.D:
                foreach (var book in dataGrid.SelectedItems.Cast <Book>().ToList())
                {
                    BookInfoSet("Sync", (forcedSettingValue ?? (!book.Sync)), book.BookFile);
                    BookInfoSet("Favorite", (forcedSettingValue ?? (!book.Favorite)), book.BookFile);
                }
                BookGridReload();     //Reload grid in the main window
                break;
            }
        }
示例#7
0
        //If name column header gets right clicked display text for live-filtering the book list
        private void BookGrid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var obj = e.OriginalSource as TextBlock;

            if (obj == null || obj.Text != UiLang.Get("FieldTitle"))
            {
                return;
            }

            FilterName.Visibility = Visibility.Visible;
            FilterName.Focus();
        }
示例#8
0
        public FilterWindow()
        {
            InitializeComponent();

            if (Properties.Settings.Default.FilterPopupHintShown)
            {
                return;
            }

            MessageBox.Show(UiLang.Get("FilterFirstUsePopup"));
            Properties.Settings.Default.FilterPopupHintShown = true;
            Properties.Settings.Default.Save();
        }
示例#9
0
        /// <summary>
        /// Add a new book into the library
        /// </summary>
        /// <param name="file">Path to the file which is being added</param>
        public static void Add(string file) //Add a new book into the library
        {
            DebugConsole.WriteLine("Book keeper: New book is being manually added into the library: " + file);

            if (!Directory.Exists(Properties.Settings.Default.BooksDir))
            {
                throw new DirectoryNotFoundException("Root directory in which the book files are stored was not found.");
            }

            var finfo = new FileInfo(file);
            var supportedExtensions = Properties.Settings.Default.FileExtensions.Split(';');

            if (!supportedExtensions.Contains(finfo.Extension.Substring(1), StringComparer.CurrentCultureIgnoreCase))
            {
                //Only allow files with supported extensions
                return;
            }

            if (!File.Exists(file))
            {
                throw new FileNotFoundException("The book file supplied for adding into the library doesn't exist.");
            }

            var dirName = Path.GetFileNameWithoutExtension(finfo.Name);
            //Name of the directory, in which the book file will be stored, name of the directory is identical to the file name, except without extension
            var dirPath    = Path.Combine(Properties.Settings.Default.BooksDir, dirName);
            var newDirPath = dirPath;
            int copyNumber;

            for (copyNumber = 1; Directory.Exists(newDirPath); copyNumber++) //If the folder already exists append a number to the new folder's name
            {
                newDirPath = dirPath + " (" + copyNumber + ")";
            }

            dirPath = newDirPath;                                                                                                                  //We are now sure, the folder name for the book storing folder doesn't already exist

            var fileName = Path.GetFileNameWithoutExtension(finfo.Name) + (copyNumber > 1 ? " (" + (copyNumber - 1) + ")" : "") + finfo.Extension; //If the parent directory got a number added to its name, add it to the book file name as well
            var path     = Path.Combine(dirPath, fileName);

            try
            {
                Directory.CreateDirectory(dirPath); //Create the dir in the default book folder, specified in the settings
                finfo.CopyTo(path, true);
                GenerateData(path);                 //Generate data for this book
            }
            catch (Exception e)
            {
                MainWindow.Info(String.Format(UiLang.Get("BookCopyError"), file), 1);
                DebugConsole.WriteLine("Book keeper: Copying of the book file " + file + " failed because: " + e);
            }
        }
示例#10
0
        private void MainWindow_OnKeyUp(object sender, KeyEventArgs e) //Allow user to refresh the book list with F5
        {
            switch (e.Key)
            {
            case Key.F5:
                BookGridReload();     //Reload grid
                break;

            case Key.F12:
                //Clear the info stack
                InfoQueue.Clear();
                Info(UiLang.Get("InfoQueueDeleted"));
                break;
            }
        }
示例#11
0
        private BookData _bookData;        //Dictionary containing the data about the book


        public EditBook(string bookFile)
        {
            _bookFile = bookFile;

            InitializeComponent();

            if (Properties.Settings.Default.AutoSavedEditsPopupShown)
            {
                return;
            }

            MessageBox.Show(UiLang.Get("EditBookAutoSavePopup"));
            Properties.Settings.Default.AutoSavedEditsPopupShown = true;
            Properties.Settings.Default.Save();
        }
示例#12
0
        private void SetFilterPreset_OnPreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var button       = (Button)sender;
            var filterPreset = (FilterPreset)button.DataContext;

            if (
                MessageBox.Show(
                    String.Format(UiLang.Get("DiscardFilterPresetConfirm"),
                                  button.Content), UiLang.Get("DiscardFilterPreset"), MessageBoxButton.YesNo) !=
                MessageBoxResult.Yes)
            {
                return;
            }

            Db.NonQuery("DELETE FROM filters WHERE Name = @Name", new [] { new SQLiteParameter("Name", filterPreset.Name) });

            _presetList.Remove(filterPreset);
        }
示例#13
0
        /// <summary>
        /// Get the drive letter for the reader device
        /// </summary>
        private static String GetDriveLetter()
        {
            try
            {
                var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskDrive");

                DebugConsole.WriteLine("Disk list:\n--------------------");

                foreach (var queryObj in searcher.Get().Cast <ManagementObject>())
                {
                    DebugConsole.WriteLine("Model: " + queryObj["Model"] + "; PnP ID: " + queryObj["PNPDeviceID"]);

                    if (!queryObj["PNPDeviceID"].ToString().Contains(Properties.Settings.Default.DevicePnpId) && !queryObj["Model"].ToString().Contains(Properties.Settings.Default.DeviceModel))
                    {
                        continue;
                    }

                    foreach (var partition in queryObj.GetRelated("Win32_DiskPartition").Cast <ManagementObject>())
                    {
                        foreach (var disk in partition.GetRelated("Win32_LogicalDisk"))
                        {
                            DebugConsole.WriteLine("--------------------");
                            return((string)disk["name"]);
                        }
                    }
                }

                DebugConsole.WriteLine("--------------------");
            }
            catch (Exception e)
            {
                Debug.WriteLine("Houston, we have a problem with getting the reader disk letter:\n" + e.Message);
            }

            if (ManualSync)
            {
                MainWindow.Info(UiLang.Get("SyncNoReadersFound"), 1);
            }

            ManualSync = false;

            return("");
        }
示例#14
0
        private void FilterPresetName_OnKeyUp(object sender, KeyEventArgs e)
        {
            var textBox = (TextBox)sender;

            if (e.Key != Key.Enter && e.Key != Key.Escape)
            {
                return;
            }

            if (e.Key == Key.Enter)
            {
                using (var ms = new MemoryStream())
                {
                    var bf = new BinaryFormatter();
                    bf.Serialize(ms, Filter);


                    using (var query = Db.Query("INSERT OR IGNORE INTO filters VALUES(@Name, @Parameters)", new[]
                    {
                        new SQLiteParameter("Name", textBox.Text),
                        new SQLiteParameter("Parameters", ms.GetBuffer())
                    }))
                    {
                        if (query.RecordsAffected > 0)
                        {
                            Info(UiLang.Get("FilterSavingPresetSuccessful"));
                            GenerateFilterPresetList();
                        }
                        else
                        {
                            Info(UiLang.Get("FilterSavingPresetDuplicate"), 1);
                            return;
                        }
                    }
                }


                textBox.Text = String.Empty;
            }

            FilterPresetName.Visibility = Visibility.Collapsed;
        }
示例#15
0
        /// <summary>
        /// Save data from the EditBook fields into the database
        /// </summary>
        /// <param name="key">Name of the BookData field to which to save the data</param>
        /// <param name="value">Value to be saved into the specified field</param>
        private void BookInfoSet(string key, object value)
        {
            if (_bookData == null)
            {
                return;
            }

            typeof(BookData).GetField(key).SetValue(_bookData, value);

            try
            {
                BookKeeper.SaveData(_bookData);
            }
            catch (Exception e)
            {
                MainWindow.Info(String.Format(UiLang.Get("DatFileNotAvailable"), _bookData.Title), 1);
                DebugConsole.WriteLine("Edit book: It was not possible to save the provided value into the data file: " + e.Message);
                Close();
            }
        }
示例#16
0
        /// <summary>
        /// Fetch data to fill the form fields, from the BookInfo object based on the key
        /// </summary>
        /// <param name="key">Name of the BookData field from which to get the data</param>
        /// <returns>Value from the BookData field specified by the given key</returns>
        private object BookInfoGet(string key)
        {
            if (_bookData == null) //Singleton, so we don't have to reopen the DB with saved info, after every form field loads and its load event handler calls BookInfoGet
            {
                try
                {
                    _bookData = BookKeeper.GetData(_bookFile);
                }
                catch (Exception)
                {
                    MainWindow.Info(UiLang.Get("BookInfoNotAvailable"), 1);
                    IsEnabled = false;
                    Close();
                    _bookData = new BookData();
                    return(null);
                }
            }

            return(typeof(BookData).GetField(key) != null ? typeof(BookData).GetField(key).GetValue(_bookData) : null);
        }
示例#17
0
        private void Add_OnClick(object sender, RoutedEventArgs e)
        {
            var supportedFiles = "*." + Properties.Settings.Default.FileExtensions.Replace(";", ";*.");
            var openFileDialog = new OpenFileDialog
            {
                Multiselect = true,
                Filter      = "eBook files|" + supportedFiles + "|All Files|*.*",
            };

            var filesSelected = openFileDialog.ShowDialog();

            if (filesSelected != true)
            {
                return;
            }

            Info(UiLang.Get("SyncFilesAdded"));

            var selectedFiles = openFileDialog.FileNames;

            AddBooksFromList(selectedFiles);
        }
示例#18
0
        /// <summary>
        /// Get a list of book files from the reader device
        /// </summary>
        private static String[] GetFileList()
        {
            var drive = GetDriveLetter();

            if (drive == "") //Reader is not connected to the pc or wasn't found, so there is no point to go on
            {
                return(null);
            }

            _deviceDir = drive + Properties.Settings.Default.DeviceBooksDir;

            if (!Directory.Exists(_deviceDir)) //Specified directory on the reader which should contain ebook files doesn't exist
            {
                MainWindow.Info(String.Format(UiLang.Get("SyncReaderDirNotFound"), Properties.Settings.Default.DeviceBooksDir, Properties.Settings.Default.DeviceModel), 1);

                return(null);
            }

            var extensions = Properties.Settings.Default.FileExtensions.Split(';');
            var files      = Directory.EnumerateFiles(_deviceDir).Where(f => extensions.Any(ext => f.EndsWith(ext, StringComparison.OrdinalIgnoreCase))).ToArray();

            return(files);
        }
示例#19
0
        /// <summary>
        /// Take all books files marked for sync and copy them onto the reader device, if one is found.
        /// If any book files are found on the reader device, which are not marked for sync in the local library, they will be deleted from the device.
        /// </summary>
        private static void SyncBookFiles()
        {
            var localBookList        = LibraryStructure.List();
            var localBookListForSync = (from bookData in localBookList where bookData.Sync select BookKeeper.GetAbsoluteBookFilePath(bookData.Path)).ToList();
            var bookList             = GetFileList();

            if (bookList == null) //The reader is not connected, or the specified storage folder on it doesn't exist, no point to continue
            {
                MainWindow.Busy(false);
                return;
            }

            var filesToDelete = (from file in bookList
                                 let fileName = Path.GetFileName(file)
                                                where !localBookListForSync.Select(Path.GetFileName).Contains(fileName)
                                                select file).ToArray();

            var filesToCopy = localBookListForSync.Where(
                file => File.Exists(file) && !bookList.Select(Path.GetFileName).Contains(Path.GetFileName(file))).ToArray();

            MainWindow.BusyMax(filesToDelete.Length + filesToCopy.Length);
            var busyCount = 0;

            foreach (var file in filesToDelete)
            //Delete files from the reader which don't exist in the local Sync list
            {
                MainWindow.Busy(busyCount++);
                MainWindow.Busy(file);

                try
                {
                    File.SetAttributes(file, FileAttributes.Normal);
                    File.Delete(file);
                }
                catch (Exception e)
                {
                    DebugConsole.WriteLine("Usb sync: Failed to delete " + file + ": " + e);
                }
            }

            foreach (var file in filesToCopy)
            //Copy files (which don't exist in the reader) into the reader, from the local Sync list
            {
                DebugConsole.WriteLine("Copying " + file);
                MainWindow.Busy(busyCount++);
                MainWindow.Busy(file);

                try
                {
                    if (file != null)
                    {
                        File.Copy(file, Path.Combine(_deviceDir, Path.GetFileName(file)));
                    }
                }
                catch (Exception e)
                {
                    MainWindow.Info(String.Format(UiLang.Get("SyncFileCopyFailed"), file));
                    DebugConsole.WriteLine("Usb sync: Error while copying " + file + ": " + e);
                }
            }

            MainWindow.Info(UiLang.Get("SyncFinished"));
            MainWindow.Busy(false);
        }
示例#20
0
 private void DataStructureSync_OnClick(object sender, RoutedEventArgs e)
 {
     Info(UiLang.Get("SyncingDataStructure"));
     LibraryStructure.SyncDbWithFileTree();
 }
示例#21
0
 private void Sync_OnClick(object sender, RoutedEventArgs e)
 {
     Info(String.Format(UiLang.Get("SyncDeviceSearch"), Properties.Settings.Default.DeviceModel));
     UsbSync.ManualSync = true;
     UsbSync.Sync();
 }
示例#22
0
 public override object ProvideValue(IServiceProvider serviceProvider)
 {
     return(String.IsNullOrWhiteSpace(Value) ? Value : UiLang.Get(Value));
 }
示例#23
0
 private void UnknownDeviceHint_OnClick(object sender, RoutedEventArgs e)
 {
     MessageBox.Show(UiLang.Get("UnknownDeviceHint"));
 }
示例#24
0
        /// <summary>
        /// Display filter parameters above the book grid
        /// </summary>
        private void GenerateFilterView()
        {
            if (Filter.ParameterCount == 0)
            {
                FilterWrap.Visibility = Visibility.Collapsed;
                return;
            }

            var keyNames = new Dictionary <string, string> //Localized names of the displayed search parameters
            {
                { "Title", UiLang.Get("FieldTitle") },
                { "Author", UiLang.Get("FieldAuthor") },
                { "Contributor", UiLang.Get("FieldContributor") },
                { "Publisher", UiLang.Get("FieldPublisher") },
                { "Language", UiLang.Get("FieldLanguage") },
                { "Published", UiLang.Get("FieldPublished") },
                { "Description", UiLang.Get("FieldDescription") },
                { "Series", UiLang.Get("FieldSeries") },
                { "Created", UiLang.Get("FieldCreated") },
                { "Favorite", UiLang.Get("FieldFavorite") },
                { "Sync", UiLang.Get("FieldSync") },
                { "Category", UiLang.Get("FieldCategory") },
                { "Path", UiLang.Get("FieldPath") },
            };

            FilterList.Children.Clear();

            foreach (var field in typeof(BookFilter).GetFields())
            {
                if (!keyNames.ContainsKey(field.Name) || field.GetValue(Filter) == null || field.GetValue(Filter).ToString() == String.Empty)
                {
                    continue;
                }

                var txtValue = field.GetValue(Filter);

                //Handle some special types like booleans for better displaying
                if (field.FieldType == typeof(DateTime) || field.FieldType == typeof(DateTime?))
                {
                    if ((DateTime)txtValue == DateTime.MinValue)
                    {
                        continue;
                    }

                    txtValue = ((DateTime)txtValue).Date.ToString("d");
                }
                else if (field.FieldType == typeof(Boolean) && (Boolean)txtValue == false)
                {
                    continue;
                }

                var value = new TextBlock
                {
                    Foreground   = Brushes.DodgerBlue,
                    Text         = (txtValue ?? String.Empty).ToString(),
                    TextWrapping = TextWrapping.Wrap
                };

                var name = new TextBlock
                {
                    Foreground = Brushes.Gray,
                    Text       = keyNames[field.Name] + ": "
                };

                var separator = new TextBlock
                {
                    Foreground = Brushes.Gray,
                    Text       = "; "
                };

                FilterList.Children.Add(name);
                FilterList.Children.Add(value);
                FilterList.Children.Add(separator);
            }

            FilterWrap.Visibility = Visibility.Visible;
        }