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")); } }
/// <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); } }
/// <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); }); }
/// <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); } }
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(); }
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; } }
//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(); }
public FilterWindow() { InitializeComponent(); if (Properties.Settings.Default.FilterPopupHintShown) { return; } MessageBox.Show(UiLang.Get("FilterFirstUsePopup")); Properties.Settings.Default.FilterPopupHintShown = true; Properties.Settings.Default.Save(); }
/// <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); } }
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; } }
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(); }
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); }
/// <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(""); }
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; }
/// <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(); } }
/// <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); }
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); }
/// <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); }
/// <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); }
private void DataStructureSync_OnClick(object sender, RoutedEventArgs e) { Info(UiLang.Get("SyncingDataStructure")); LibraryStructure.SyncDbWithFileTree(); }
private void Sync_OnClick(object sender, RoutedEventArgs e) { Info(String.Format(UiLang.Get("SyncDeviceSearch"), Properties.Settings.Default.DeviceModel)); UsbSync.ManualSync = true; UsbSync.Sync(); }
public override object ProvideValue(IServiceProvider serviceProvider) { return(String.IsNullOrWhiteSpace(Value) ? Value : UiLang.Get(Value)); }
private void UnknownDeviceHint_OnClick(object sender, RoutedEventArgs e) { MessageBox.Show(UiLang.Get("UnknownDeviceHint")); }
/// <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; }