├── help ├── help.css ├── balloonrss.chm ├── img │ ├── blue16.png │ ├── locked.jpg │ ├── orange16.png │ ├── yellow16.png │ └── balloonRss_1.png ├── balloonrss.hhp ├── channelInformation.html ├── TableOfContents.hhc ├── usage.html ├── intro.html ├── channelSettings.html ├── advancedUsage.html └── applicationSettings.html ├── docs ├── screen.css ├── favicon.ico ├── img │ ├── down.gif │ ├── rss.gif │ ├── top.gif │ ├── blue16.png │ ├── orange16.png │ └── yellow16.png ├── screenshots │ ├── balloonRss_1.png │ ├── balloonRss_2.png │ ├── balloonRss_3.png │ ├── balloonRss_4.png │ └── balloonRss_5.png ├── ie6.css ├── ie7.css ├── print.css ├── support.html ├── screenshots.html ├── download.html ├── index.html ├── releasenotes.html └── usage.html ├── bin ├── BalloonRss.exe ├── de │ └── BalloonRss.resources.dll ├── pt │ └── BalloonRss.resources.dll └── BalloonRss.exe.config ├── install ├── yellow32.ico ├── update_language_files.bat ├── create_resources.bat ├── dotnet.nsh └── balloonRSS.nsi ├── src ├── Resources │ ├── rss.png │ ├── blau16.ico │ ├── blue16.ico │ ├── blue32.ico │ ├── locked.jpg │ ├── orange16.ico │ ├── unlocked.jpg │ ├── yellow16.ico │ └── yellow32.ico ├── Properties │ ├── AssemblyInfo.cs │ ├── Settings.settings │ ├── app.manifest │ └── Settings.Designer.cs ├── RssUpdateItem.cs ├── Settings.cs ├── BalloonRss.csproj ├── AboutBox.cs ├── utils │ └── NumericTextBox.cs ├── app.config ├── FormHistory.cs ├── AboutBox.resx ├── ChannelInfo.cs ├── RssItem.cs ├── FormChannelInfo.cs ├── ChannelList.cs ├── FormChannelSettingsEdit.cs ├── AboutBox.Designer.cs ├── FormSettings.cs └── FormChannelSettings.cs ├── .gitignore ├── balloonRss.sln └── README.md /help/help.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/help.css -------------------------------------------------------------------------------- /docs/screen.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screen.css -------------------------------------------------------------------------------- /bin/BalloonRss.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/bin/BalloonRss.exe -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /docs/img/down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/down.gif -------------------------------------------------------------------------------- /docs/img/rss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/rss.gif -------------------------------------------------------------------------------- /docs/img/top.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/top.gif -------------------------------------------------------------------------------- /docs/img/blue16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/blue16.png -------------------------------------------------------------------------------- /help/balloonrss.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/balloonrss.chm -------------------------------------------------------------------------------- /help/img/blue16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/img/blue16.png -------------------------------------------------------------------------------- /help/img/locked.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/img/locked.jpg -------------------------------------------------------------------------------- /install/yellow32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/install/yellow32.ico -------------------------------------------------------------------------------- /docs/img/orange16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/orange16.png -------------------------------------------------------------------------------- /docs/img/yellow16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/img/yellow16.png -------------------------------------------------------------------------------- /help/img/orange16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/img/orange16.png -------------------------------------------------------------------------------- /help/img/yellow16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/img/yellow16.png -------------------------------------------------------------------------------- /src/Resources/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/rss.png -------------------------------------------------------------------------------- /help/img/balloonRss_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/help/img/balloonRss_1.png -------------------------------------------------------------------------------- /src/Resources/blau16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/blau16.ico -------------------------------------------------------------------------------- /src/Resources/blue16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/blue16.ico -------------------------------------------------------------------------------- /src/Resources/blue32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/blue32.ico -------------------------------------------------------------------------------- /src/Resources/locked.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/locked.jpg -------------------------------------------------------------------------------- /src/Resources/orange16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/orange16.ico -------------------------------------------------------------------------------- /src/Resources/unlocked.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/unlocked.jpg -------------------------------------------------------------------------------- /src/Resources/yellow16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/yellow16.ico -------------------------------------------------------------------------------- /src/Resources/yellow32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/src/Resources/yellow32.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | .vscode/ 3 | Backup/ 4 | bin/Debug/ 5 | bin/balloonrss.chm 6 | bin/BalloonRss.pdb 7 | src/obj/ 8 | -------------------------------------------------------------------------------- /bin/de/BalloonRss.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/bin/de/BalloonRss.resources.dll -------------------------------------------------------------------------------- /bin/pt/BalloonRss.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/bin/pt/BalloonRss.resources.dll -------------------------------------------------------------------------------- /docs/screenshots/balloonRss_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screenshots/balloonRss_1.png -------------------------------------------------------------------------------- /docs/screenshots/balloonRss_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screenshots/balloonRss_2.png -------------------------------------------------------------------------------- /docs/screenshots/balloonRss_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screenshots/balloonRss_3.png -------------------------------------------------------------------------------- /docs/screenshots/balloonRss_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screenshots/balloonRss_4.png -------------------------------------------------------------------------------- /docs/screenshots/balloonRss_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embyt/balloonrss/HEAD/docs/screenshots/balloonRss_5.png -------------------------------------------------------------------------------- /docs/ie6.css: -------------------------------------------------------------------------------- 1 | /* =================================== 2 | Stylesheet for BalloonRSS 3 | 4 | File: bildschirm.css 5 | Date: 14. Februar 2009 6 | Author: Anna Morawek 7 | 8 | =================================== */ 9 | 10 | /* IE6: gibt div.galerie hasLayout */ 11 | div.gallery { height: 1%; } 12 | 13 | /* ================================== 14 | END OF STYLESHEET 15 | =============================== */ -------------------------------------------------------------------------------- /docs/ie7.css: -------------------------------------------------------------------------------- 1 | /* =================================== 2 | Stylesheet for BalloonRSS 3 | 4 | File: bildschirm.css 5 | Date: 14. Februar 2009 6 | Author: Anna Morawek 7 | 8 | =================================== */ 9 | 10 | 11 | /* Patch for PageZoom at horicontal navigation */ 12 | #navigation ul { word-spacing: 0; } 13 | 14 | 15 | 16 | /* ================================== 17 | END OF STYLESHEET 18 | =============================== */ -------------------------------------------------------------------------------- /install/update_language_files.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | rem This batch file includes new keys in the application language files 4 | rem Author: Roman Morawek 5 | rem resxsync is a utility to synchronise resx files, you may obtain it here: http://www.screwturn.eu/ResxSync.ashx 6 | 7 | echo Culture:de 8 | resxsync ..\src\Properties\Resources.resx ..\src\Resources\strings.de.resx /v /l 9 | 10 | echo. 11 | echo Culture:pt 12 | resxsync ..\src\Properties\Resources.resx ..\src\Resources\strings.pt.resx /v /l 13 | 14 | pause -------------------------------------------------------------------------------- /help/balloonrss.hhp: -------------------------------------------------------------------------------- 1 | [OPTIONS] 2 | Compatibility=1.1 or later 3 | Compiled file=balloonrss.chm 4 | Contents file=TableOfContents.hhc 5 | Default Font=MS Sans Serif,8,0 6 | Default Window=main_window 7 | Default topic=intro.html 8 | Display compile notes=No 9 | Display compile progress=No 10 | Full-text search=Yes 11 | Language=0x409 English (United States) 12 | Title=BalloonRSS - A Simple RSS Aggregator using Balloon Tooltips 13 | 14 | [WINDOWS] 15 | main_window=,"TableOfContents.hhc",,"intro.html","intro.html",,,,,0x42520,200,0x1046,[200,200,1000,800],,,,,,,0 16 | 17 | 18 | [FILES] 19 | channelInformation.html 20 | applicationSettings.html 21 | intro.html 22 | usage.html 23 | advancedUsage.html 24 | channelSettings.html 25 | 26 | [INFOTYPES] 27 | 28 | -------------------------------------------------------------------------------- /install/create_resources.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | rem This batch file creates the localization dlls to support different application languages 4 | rem Author: Roman Morawek 5 | 6 | echo Preparing resource files 7 | resgen ..\src\Resources\strings.de.resx BalloonRss.Properties.Resources.de.resources 8 | resgen ..\src\Resources\strings.pt.resx BalloonRss.Properties.Resources.pt.resources 9 | echo. 10 | 11 | echo Creating dll for culture de 12 | al /t:lib /embed:BalloonRss.Properties.Resources.de.resources /culture:de /out:BalloonRss.resources.dll 13 | del BalloonRss.Properties.Resources.de.resources 14 | move BalloonRss.resources.dll ..\bin\de 15 | 16 | echo Creating dll for culture pt 17 | al /t:lib /embed:BalloonRss.Properties.Resources.pt.resources /culture:pt /out:BalloonRss.resources.dll 18 | del BalloonRss.Properties.Resources.pt.resources 19 | move BalloonRss.resources.dll ..\bin\pt 20 | 21 | pause -------------------------------------------------------------------------------- /balloonRss.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30011.22 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BalloonRss", "src\BalloonRss.csproj", "{E31E97B8-7C0E-4552-9388-EF075E3EFDEE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E31E97B8-7C0E-4552-9388-EF075E3EFDEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E31E97B8-7C0E-4552-9388-EF075E3EFDEE}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E31E97B8-7C0E-4552-9388-EF075E3EFDEE}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E31E97B8-7C0E-4552-9388-EF075E3EFDEE}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {75BA5564-82E6-494F-BB3E-24F7E11E2DC4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /help/channelInformation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Channel Information Dialog 7 | 8 | 9 | 10 |

Channel Information Dialog

11 | 12 |

The channel information dialog displays data associated to the configured RSS channels in table format. For each channel, the following information is displayed:

13 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/print.css: -------------------------------------------------------------------------------- 1 | /* =================================== 2 | Stylesheet for BalloonRSS (printer version) 3 | 4 | File: print.css 5 | Date: 14. Februar 2009 6 | Author: Anna Morawek 7 | 8 | =================================== */ 9 | 10 | body { 11 | font-family: Arial, Verdana, Helvetica, sans-serif; 12 | font-family: "Times New Roman", Georgia, Times, serif; 13 | font-size: 10pt; 14 | line-height: 110%; 15 | } 16 | 17 | a {color: #99790f; /*ganzdunkelbraun_60*/} 18 | h1, h2,h3 { 19 | font-family: Verdana, Arial, Helvetica, sans-serif; 20 | color:#cca015; /*dunkelbraun*/ 21 | } 22 | h1 { font-size: 18pt; } 23 | h2 { 24 | font-size: 14pt; 25 | padding-top: 6pt; 26 | margin-top: 14pt; 27 | } 28 | h3 { font-size: 12pt; } 29 | 30 | .skiplink, 31 | .top, 32 | .banner, 33 | #downloadbar, 34 | #navigation { 35 | display: none; 36 | } 37 | 38 | .address { 39 | border-top: 1pt dotted #cca015; /*dunkelbraun*/ 40 | border-bottom: 1pt dotted #cca015; /*dunkelbraun*/ 41 | padding-top: 12pt; 42 | padding-bottom: 12pt; 43 | } 44 | 45 | #header { 46 | position: relative; 47 | padding: 6pt; /* oben - rechts - unten - links */ 48 | border: 1pt solid #cca015; /*dunkelbraun*/ 49 | margin-bottom: 12pt; 50 | font-family: Verdana, Arial, Helvetica, sans-serif; 51 | } 52 | #header p { 53 | position: absolute; 54 | top: 2pt; 55 | right: 20pt; 56 | padding: 0; 57 | font-size: 10pt; 58 | } 59 | #header p span { 60 | color: #cca015; /*dunkelbraun*/ 61 | font-size: 16pt; 62 | } 63 | #header img {width: 60px; height: 60px;} 64 | #header h1 { font-size: 6pt; } 65 | 66 | -------------------------------------------------------------------------------- /help/TableOfContents.hhc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 46 | 47 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Resources; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("BalloonRSS")] 10 | [assembly: AssemblyDescription("BalloonRSS is a simple RSS aggregator that displays incoming messages as balloon tooltips in the windows task bar. The news entries themselves are linked and read with the browser.")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("BalloonRSS")] 14 | [assembly: AssemblyCopyright("(C) 2020, Roman Morawek")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("4d74a4b9-bbdd-45d6-a40e-d7382fa5a9b8")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // KEEP THIS CONSISTENT WITH APPL_VERSION IN balloonRSS.nsi INSTALLER! 34 | [assembly: AssemblyVersion("2.9.0.0")] 35 | [assembly: AssemblyFileVersion("2.9.0.0")] 36 | [assembly: NeutralResourcesLanguageAttribute("en")] 37 | -------------------------------------------------------------------------------- /help/usage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Usage 7 | 8 | 9 | 10 |

Usage

11 | 12 |

As you start the application you get a notify icon in the windows task bar (at the right button, near the clock). All commands are accessed by the context menu (right click on the icon). Make sure that the icon is always shown and not hidden by configuring this in windows.

13 | 14 |

The first thing you might want to do is add your favorite RSS channels to be displayed. For this you need to select RSS Channel Settings and add them there. If you read multiple channels you may want to assign different priorities. Messages from higher priority RSS channels are more likely to be displayed. The effective priority is calculated by the pre-selected priority of the channel settings and the user's click rate. Thus, if you click more messages from one channel, this increases its effective priority and display probability.

15 | 16 |

A single left click on the application icon in the task bar enters pause mode. This is indicated with the color of the icon. No messages will be displayed in this status. Double clicking the icon may also have functionality if this is configured in the application settings.

17 | 18 |

Color codes of the icon:

19 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/RssUpdateItem.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2008 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Text; 21 | using BalloonRss.Properties; 22 | 23 | 24 | namespace BalloonRss 25 | { 26 | public class RssUpdateItem : RssItem 27 | { 28 | private int newVersion; 29 | public int NewVersion 30 | { 31 | get 32 | { 33 | return newVersion; 34 | } 35 | set 36 | { 37 | newVersion = value; 38 | title = Resources.str_updateTitle + (value/100) + "." + (value%100); 39 | } 40 | } 41 | 42 | private int currentVersion; 43 | public int CurrentVersion 44 | { 45 | get 46 | { 47 | return currentVersion; 48 | } 49 | set 50 | { 51 | currentVersion = value; 52 | link = Settings.Default.updateInfoUrl + value; 53 | } 54 | } 55 | 56 | 57 | public RssUpdateItem() 58 | { 59 | title = Resources.str_updateTitle; 60 | description = Resources.str_updateBody; 61 | author = "Roman Morawek"; 62 | link = Settings.Default.updateInfoUrl; 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Settings.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2007 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | namespace BalloonRss.Properties 20 | { 21 | 22 | 23 | // This class allows you to handle specific events on the settings class: 24 | // The SettingChanging event is raised before a setting's value is changed. 25 | // The PropertyChanged event is raised after a setting's value is changed. 26 | // The SettingsLoaded event is raised after the setting values are loaded. 27 | // The SettingsSaving event is raised before the setting values are saved. 28 | internal sealed partial class Settings { 29 | 30 | public Settings() { 31 | // // To add event handlers for saving and changing settings, uncomment the lines below: 32 | // 33 | // this.SettingChanging += this.SettingChangingEventHandler; 34 | // 35 | // this.SettingsSaving += this.SettingsSavingEventHandler; 36 | // 37 | } 38 | 39 | private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { 40 | // Add code to handle the SettingChangingEvent event here. 41 | } 42 | 43 | private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { 44 | // Add code to handle the SettingsSaving event here. 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /help/intro.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BalloonRSS - A Simple RSS Aggregator using Balloon Tooltips 7 | 8 | 9 | 10 | 14 | 15 |

Overview

16 | 17 |

BalloonRSS is a simple RSS reader that displays incoming messages as balloon tooltips in the windows task bar. The news entries themselves are linked to be read with the browser.

18 | 19 |

The messages are retrieved from a set of configurable RSS feed sites. The news entry to view next is selected by a pre-defined priority which is dynamically adapted according the user's interest, which is determined by the user's message click rate.

20 | 21 |

This program is free software; you can redistribute it and/or modify 22 | it under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; either version 3 of the license, or 23 | (at your option) any later version.

24 | 25 | 26 |

Features

27 |
    28 |
  • retrieves RSS messages from various sources
  • 29 |
  • performs priorisation of news
  • 30 |
  • displays the messages in a balloon tooltip pop-up in the task bar
  • 31 |
  • the messages are linked and opened within the browser as you click them
  • 32 |
  • adaptation of channel priority according the user's click rate
  • 33 |
  • the message frequency and viewing period is configurable
  • 34 |
  • configuration via GUI or using .xml files
  • 35 |
  • message history
  • 36 |
  • support of HTTP authentication
  • 37 |
  • support for multi-user environments
  • 38 |
  • automatically check for program updates (if enabled)
  • 39 |
  • multi-language support: English, German, Portuguese
  • 40 |
  • ...
  • 41 |
42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /help/channelSettings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Channel Settings Dialog 7 | 8 | 9 | 10 |

Channel Settings Dialog

11 | 12 |

The channel settings dialog allows the user to configure the RSS channels from which the messages are retrieved. The main channel settings dialog offers the following actions:

13 |
    14 |
  • New: This allows you to add a new RSS channel and will open the channel edit dialog box.
  • 15 | 16 |
  • Delete: The currently selected channel will be deleted.
  • 17 | 18 |
  • Edit: This opens the channel edit dialog box to modify the currently selected channel.
  • 19 | 20 |
  • OK / Cancel: Pressing the OK button will exit the dialog and change all your settings. The Cancel button will close the dialog and discard all changes.
  • 21 |
22 | 23 |

If there are pre-configured multi-user channels in your environment they will be indicated with a locked symbol . They can only be modified by the system administrator as described in advanced usage.

24 | 25 | 26 |

Edit RSS Channels Dialog

27 | 28 |

The edit RSS channel settings dialog allows the user to configure the settings of the selected or new RSS channel. The settings have the following meaning:

29 |
    30 |
  • Link: The URL of the RSS channel to retrieve.
  • 31 | 32 |
  • Priority: The pre-defined priority of the channel. The effective priority that is used by the program will be calculated based on this value and the user's click ratio.
  • 33 | 34 |
  • Mark RSS messages of this channel as read at application startup: If this checkbox is selected BalloonRSS will only display those RSS messages that arrive newly after program start. Therefore, all messages that are already present at the time of the first channel retrieval at application startup will be marked as read and will not be displayed then.
  • 35 |
36 | 37 |

BalloonRSS also supports RSS channels that require a user name and password via HTTP authentication. Please see advanced usage for more details on this topic.

38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BalloonRSS 2 | 3 | ## Overview 4 | 5 | BalloonRSS is a simple RSS aggregator that displays incoming messages as balloon tooltips in the windows task bar. The news entries themselves are linked and read with the browser. 6 | 7 | This project was initially hosted on [SourceForge](https://sourceforge.net/projects/balloonrss/) and transfered to GitHub in 2020. 8 | 9 | ## Features 10 | 11 | - Retrieves RSS messages from various sources 12 | - Performs priorisation of news 13 | - Displays the messages in a balloon tooltip pop-up in the task bar 14 | - The messages are linked and are opened within the browser if you click them 15 | - Adaptation of channel priority according the user's click rate 16 | - The message frequency and viewing period is configurable 17 | - Configuration via GUI 18 | - Message history 19 | - Support of HTTP authentication 20 | - Support for multi-user environments 21 | - Automatically check for program updates (if enabled) 22 | - Multi-language support: English, German, Portuguese 23 | - ... 24 | 25 | ## Supported systems 26 | 27 | BalloonRSS is developed to be used on any Win32 system, where the .NET framework 28 | is available, which includes: 29 | 30 | - Windows 7 31 | - Windows 8 32 | - Windows 10 33 | - Windows 11 34 | 35 | ## Installation 36 | 37 | - Start BalloonRSS_xxx_setup.exe and follow the steps on the screen 38 | - Start the application. Notice that the only entry point to the application is the icon in the notification area (usually on the bottom right). 39 | - Right click on the icon in the task bar and adapt the channel configuration with the RSS feeds of your choice. 40 | - You may want to configure that the icon in the notification area is always displayed 41 | 42 | The base message recurrence is set to 5 minutes per default, so you have to wait a bit until your first messages will appear. 43 | 44 | ## Usage 45 | 46 | As you start the application you get a notify icon in the windows task bar (at the right botton, near the clock). All commands are accessed by the context menu (right click on the icon). Make sure that the icon is always shown and not hidden by configuring this in windows. 47 | 48 | A single left click enters pause mode. Double clicking the icon may also have functionality if this is configured in the application settings. 49 | 50 | Color codes of the icon: 51 | 52 | - blue: application paused 53 | - yellow: messages pending 54 | - orange: no messages pending 55 | 56 | You can obtain further information from the application's help file or on the 57 | website: 58 | https://embyt.github.io/balloonrss/ 59 | -------------------------------------------------------------------------------- /docs/support.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - Support - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 33 | 34 | 44 | 45 |
46 | 47 |

Support & Feedback

48 |

Please use the GitHub issues tracker for bug, support or feature requests.

49 | 50 |
51 | top TOP 52 |
53 | 54 |
55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /help/advancedUsage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Advanced Usage 7 | 8 | 9 | 10 |

Advanced Usage

11 | 12 |

Private RSS Channels using HTTP Authentication

13 |

In some cases a private RSS feed might be protected by HTTP authentication where you must enter a username and a password to access it. You can use BalloonRSS also for such feeds. For this you need to edit the channel configuration file channelConfig.xml. It is located in the user data directory, e.g. at C:\Users\<user_name>\AppData\Roaming\BalloonRSS for Windows Vista and C:\Documents and Settings\<user_name>\Application Data\BalloonRSS for WinXP. This directory may be hidden and you may have to type the link in the explorer window directly to access it. There, you need to add the XML tags httpAuthUsername and httpAuthPassword to the configuration. Here you see an example:

14 |

channelConfig.xml:

15 |
16 | <channels>
17 |   <item>
18 |     <link>http://link_to_private_RSS_channel/rss.xml</link>
19 |     <priority>5</priority>
20 |     <httpAuthUsername>enter_username_here</httpAuthUsername>
21 |     <httpAuthPassword>enter_password_here</httpAuthPassword>
22 |   </item>
23 | </channels>
24 | 
25 |

This configuration is not visible within the graphical channel settings dialog. I think that protected RSS channels are an exceptional use case and I do not want to confuse the average user with such settings, which are normally not needed.

26 | 27 | 28 |

Configuration in Multi-User Environment

29 | 30 |

Pre-Definition of RSS Channel Settings

31 |

BalloonRSS uses 2 channel configuration files:

32 |
    33 |
  1. A user specific channel configuration (located in the user settings directory, e.g. C:\Users\<user_name>\AppData\Roaming\BalloonRSS)
  2. 34 |
  3. A computer specific channel configuration (located in the program directory, e.g. C:\Program Files\BalloonRSS).
  4. 35 |
36 | 37 |

Using the configuration dialogs in the GUI, you always modify user's channel entries. The global channel settings can only be changed by directly creating and editing the configuration .xml file.

38 | 39 |

The easiest way to configure the global channel settings is to configure the desired global channels as a user and then move the channelConfig.xml file from the user settings directory to the program directory. Afterwards you may add additional user channels.

40 | 41 |

Pre-Definition of Application Settings

42 |

You may pre-define application settings in a multi-user environment by putting a configuration file BalloonRss.exe.config in the program directory. You need to manually edit this XML file. You start by obtaining the default settings file from the GitHub project at /bin/BalloonRss.exe.config and modify it according your needs.

43 | 44 |

Once a user modifies its settings using the application configuration dialog, BalloonRSS will create a user specific setting file in the user directory. This file then overrides the global application settings.

45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/screenshots.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - Sreenshots - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 33 | 34 | 44 | 45 |
46 | 47 |

Screenshots

48 | 49 | 53 | 54 | 58 | 59 | 63 | 64 | 68 | 69 | 73 | 74 |
75 | top TOP 76 |
77 | 78 |
79 | 80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /src/BalloonRss.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0-windows 4 | WinExe 5 | BalloonRss.FormMain 6 | Resources\yellow32.ico 7 | false 8 | 282041D023C50110CF189BFA460BC6C941A5A64A 9 | BalloonRss_TemporaryKey.pfx 10 | false 11 | false 12 | ..\publish\ 13 | true 14 | Disk 15 | false 16 | Foreground 17 | 7 18 | Days 19 | false 20 | false 21 | true 22 | https://embyt.github.io/balloonrss 23 | en 24 | BalloonRSS 25 | 1 26 | 0.1.0.%2a 27 | false 28 | true 29 | LocalIntranet 30 | Properties\app.manifest 31 | false 32 | true 33 | true 34 | 35 | 36 | ..\bin\Debug\ 37 | true 38 | 39 | 40 | ..\bin\ 41 | true 42 | 43 | 44 | 45 | Component 46 | 47 | 48 | 49 | 50 | False 51 | .NET Framework 2.0 %28x86%29 52 | true 53 | 54 | 55 | False 56 | .NET Framework 3.0 %28x86%29 57 | false 58 | 59 | 60 | False 61 | .NET Framework 3.5 62 | false 63 | 64 | 65 | 66 | 67 | balloonrss.chm 68 | PreserveNewest 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | all 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 5 7 | 8 | 9 | 30 10 | 11 | 12 | 10 13 | 14 | 15 | 15 16 | 17 | 18 | False 19 | 20 | 21 | 5 22 | 23 | 24 | True 25 | 26 | 27 | 100 28 | 29 | 30 | 40 31 | 32 | 33 | http://balloonrss.sourceforge.net/checkforupdates.php?curVersion= 34 | 35 | 36 | channelConfig.xml 37 | 38 | 39 | #################################### 40 | 41 | 42 | ########### 43 | 44 | 45 | http://balloonrss.sourceforge.net/releaseinfo.html?curVersion= 46 | 47 | 48 | False 49 | 50 | 51 | 5 52 | 53 | 54 | True 55 | 56 | 57 | balloonrss.chm 58 | 59 | 60 | applicationSettings.html 61 | 62 | 63 | channelInformation.html 64 | 65 | 66 | channelSettings.html 67 | 68 | 69 | channelSettings.html#channel_edit 70 | 71 | 72 | 0 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/download.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - Download - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 31 | 32 | 42 | 43 |
44 | 45 |
46 |
47 |

48 | 49 | 50 | Download 51 | Download this file from GitHub 52 |

53 |

54 | BalloonRSS - 2.9 55 |
56 | Last Update: March 11th, 2010 57 |

58 | 59 |
60 |
61 | 62 |

Download & Installation

63 | 64 |

The source code as well as the released packages can be downloaded from the GitHub project.

65 | 66 | 67 |

Installation procedure:

68 |
    69 |
  1. Start BalloonRSS_xxx_setup.exe and follow the steps on the screen.
  2. 70 |
  3. Start the application. Notice that the only entry point to the application is the icon in the notification area (usually on the bottom right).
  4. 71 |
  5. Adapt the channel configuration with the RSS feeds of your choice.
  6. 72 |
73 | 74 |

The base recurrence is set to 5 minutes per default, so you have to wait a bit until your first messages will appear.

75 | 76 | 77 |

Supported Systems

78 | 79 |

BalloonRSS is developed to be used on any Win32 system where the .NET framework 2.0 is available, which includes all current Microsoft Windows operating systems:

80 |
    81 |
  • Windows 7
  • 82 |
  • Windows 8
  • 83 |
  • Windows 10
  • 84 |
85 | 86 | 87 |
88 | top TOP 89 |
90 | 91 | 92 |
93 | 94 |
95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/Properties/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Oz+rE+J5HYKJDy0h9n9kh734dkc= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | t40IoNSHGD9I5f9gFVrKA6v5FN4= 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | PNE49p61foYbrSn2UiWaTyNaNIA= 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/AboutBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Reflection; 6 | using System.Windows.Forms; 7 | 8 | namespace BalloonRss 9 | { 10 | partial class AboutBox : Form 11 | { 12 | public AboutBox() 13 | { 14 | InitializeComponent(); 15 | this.Text = "About " + AssemblyTitle; 16 | this.labelProductName.Text = AssemblyProduct + String.Format(" {0}.{1}", AssemblyVersion.Split('.')); 17 | this.labelCopyright.Text = AssemblyCopyright; 18 | } 19 | 20 | #region Assembly Attribute Accessors 21 | 22 | public string AssemblyTitle 23 | { 24 | get 25 | { 26 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 27 | if (attributes.Length > 0) 28 | { 29 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; 30 | if (titleAttribute.Title != "") 31 | { 32 | return titleAttribute.Title; 33 | } 34 | } 35 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location); 36 | } 37 | } 38 | 39 | public string AssemblyVersion 40 | { 41 | get 42 | { 43 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 44 | } 45 | } 46 | 47 | public string AssemblyDescription 48 | { 49 | get 50 | { 51 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 52 | if (attributes.Length == 0) 53 | { 54 | return ""; 55 | } 56 | return ((AssemblyDescriptionAttribute)attributes[0]).Description; 57 | } 58 | } 59 | 60 | public string AssemblyProduct 61 | { 62 | get 63 | { 64 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 65 | if (attributes.Length == 0) 66 | { 67 | return ""; 68 | } 69 | return ((AssemblyProductAttribute)attributes[0]).Product; 70 | } 71 | } 72 | 73 | public string AssemblyCopyright 74 | { 75 | get 76 | { 77 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 78 | if (attributes.Length == 0) 79 | { 80 | return ""; 81 | } 82 | return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; 83 | } 84 | } 85 | 86 | public string AssemblyCompany 87 | { 88 | get 89 | { 90 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 91 | if (attributes.Length == 0) 92 | { 93 | return ""; 94 | } 95 | return ((AssemblyCompanyAttribute)attributes[0]).Company; 96 | } 97 | } 98 | #endregion 99 | 100 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 101 | { 102 | try 103 | { 104 | // Change the color of the link text 105 | linkLabel1.LinkVisited = true; 106 | //Call the Process.Start method to open the default browser 107 | System.Diagnostics.Process.Start(linkLabel1.Text); 108 | } 109 | catch (Exception) 110 | { 111 | // ignore this failure 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /help/applicationSettings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Application Settings Dialog 7 | 8 | 9 | 10 |

Application Settings Dialog

11 | 12 |

The application settings dialog allows the user to configure the behavior of the application. The settings have the following meaning:

13 |
    14 |
  • Time between displaying two RSS messages: This value specifies the base time in minutes that elapses between two tooltip pop-ups with new RSS messages. The base time only applies between two messages as long as messages are available in the channel with the highest effective priority. As this channel has no more messages to display, the time span between 2 RSS messages will increase corresponding to the decrease in effective priority.
  • 15 | 16 |
  • Interval for retrieving new RSS messages: This value specifies the time in minutes between two retrievals of the RSS messages via the network. Thus, after each such interval, all RSS channels are retrieved.
  • 17 | 18 |
  • Timespan to display balloon pop-up: This value specifies the time interval in seconds, which a new RSS messages is displayed within the balloon tooltip. Consider that the Windows operating system controls the pop-up and may change the timing. I.e. the minimum time span is set to 10 seconds by the OS and the display interval will be extended if there is no user activity (e.g. using the mouse or keyboard).
  • 19 | 20 |
  • Start in pause mode: As this is described in the usage section BalloonRSS can be put into pause mode. If this checkbox is selected BalloonRSS will start in pause mode. You need to click the program item in the task bar to activate it then.
  • 21 | 22 |
  • Use channel name as pop-up title: Each displayed RSS message has two sections: the title and the content. Normally the title of the RSS message is displayed in the title section and its content is displayed below. If this checkbox is selected BalloonRSS will display the title of the RSS channel (instead of the RSS message) in the title field and the RSS message content below. BalloonRSS will not display the RSS message title then.
  • 23 | 24 |
  • Number of entries in message history: This value specifies the number of lines in the RSS message history dialog.
  • 25 | 26 |
  • Priority influence of message clicks: BalloonRSS calculates the effective priority of the RSS channels based on 2 inputs: the pre-defined priority of the channel and the number of user clicks onto RSS messages of this channel. This slider control enables the user to specify the influence of those 2 input characteristics. If the slider is put on the left side the influence of the pre-defined priority value is increased. If the slider is put to the right the click rate has higher influence. You can immediately check the results in the channel information dialog.
  • 27 | 28 |
  • Check for application updates: If this checkbox is selected BalloonRSS will check for potential updates on the SourceForge server. If a new version is available this will be reported as a message popup.
  • 29 | 30 |
  • Report network errors: If this checkbox is selected BalloonRSS will report any network error during retrieval of the RSS channels as a message popup. If the checkbox is not selected network errors will be ignored without notifying the user.
  • 31 | 32 |
  • Double click action: This drop-down list determines the action, which takes place as the application icon is double clicked. 33 |
      34 |
    • Do nothing: There is no action on double click.
    • 35 |
    • Display next message: The next RSS message is shown immediately. If no message is available nothing will happen. This equals to the action of the corresponding item in the main menu.
    • 36 |
    • Open last message: The details of the last shown RSS message will be opened within the web browser. If no message was shown yet nothing will happen. This equals to the action of the corresponding item in the main menu.
    • 37 |
  • 38 |
39 | 40 |

All settings except enabling the application update are kept on a per-user basis. Therefore a change in the settings will only change the program behavior of the current user.

41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 30 | 31 | 41 | 42 |
43 | 44 | 48 | 49 |

Overview

50 | 51 |

BalloonRSS is a simple RSS reader that displays incoming messages as balloon 52 | tooltips in the windows task bar. The news entries themselves are linked to be 53 | read with the browser.

54 | 55 |

The messages are retrieved from a set of configurable RSS feed sites. The news entry to view next is selected by a pre-defined priority which is dynamically adapted according the user's interest, which is determined by the user's message click rate.

56 | 57 |

This program is free software; you can redistribute it and/or modify 58 | it under the terms of the GNU General Public License (GPL) as published by 59 | the Free Software Foundation; either version 3 of the license, or 60 | (at your option) any later version.

61 | 62 | 63 |

Features

64 |
    65 |
  • retrieves RSS messages from various sources
  • 66 |
  • performs priorisation of news
  • 67 |
  • displays the messages in a balloon tooltip pop-up in the task bar
  • 68 |
  • the messages are linked and opened within the browser as you click them
  • 69 |
  • adaptation of channel priority according the user's click rate
  • 70 |
  • the message frequency and viewing period is configurable
  • 71 |
  • configuration via GUI or using .xml files
  • 72 |
  • message history
  • 73 |
  • support of HTTP authentication
  • 74 |
  • support for multi-user environments
  • 75 |
  • automatically check for program updates (if enabled)
  • 76 |
  • application help with context specific entries
  • 77 |
  • multi-language support: English, German, Portuguese
  • 78 |
  • ...
  • 79 |
80 | 81 |
82 | top TOP 83 |
84 | 85 |
86 | 87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /src/utils/NumericTextBox.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2008 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | /* this class is taken from the MSDN example */ 20 | 21 | using System; 22 | using System.Windows.Forms; 23 | using System.Globalization; 24 | 25 | namespace BalloonRss 26 | { 27 | public class NumericTextBox : TextBox 28 | { 29 | private bool allowSpace = false; 30 | 31 | private int minValue; 32 | private int maxValue; 33 | private String description; 34 | 35 | public NumericTextBox(int minValue, int maxValue, String description) 36 | { 37 | this.minValue = minValue; 38 | this.maxValue = maxValue; 39 | this.description = description; 40 | this.TextAlign = HorizontalAlignment.Right; 41 | } 42 | 43 | // Restricts the entry of characters to digits (including hex), the negative sign, 44 | // the decimal point, and editing keystrokes (backspace). 45 | protected override void OnKeyPress(KeyPressEventArgs e) 46 | { 47 | base.OnKeyPress(e); 48 | 49 | NumberFormatInfo numberFormatInfo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat; 50 | String decimalSeparator = numberFormatInfo.NumberDecimalSeparator; 51 | String groupSeparator = numberFormatInfo.NumberGroupSeparator; 52 | String negativeSign = numberFormatInfo.NegativeSign; 53 | 54 | String keyInput = e.KeyChar.ToString(); 55 | 56 | if (Char.IsDigit(e.KeyChar)) 57 | { 58 | // Digits are OK 59 | } 60 | else if (keyInput.Equals(decimalSeparator) || keyInput.Equals(groupSeparator) || keyInput.Equals(negativeSign)) 61 | { 62 | // Decimal and negative numbers are not OK 63 | // swallow this invalid key 64 | e.Handled = true; 65 | } 66 | else if (e.KeyChar == '\b') 67 | { 68 | // Backspace key is OK 69 | } 70 | else if ((ModifierKeys & (Keys.Control | Keys.Alt)) != 0) 71 | { 72 | // Let the edit control handle control and alt key combinations 73 | } 74 | else if (this.allowSpace && e.KeyChar == ' ') 75 | { 76 | 77 | } 78 | else 79 | { 80 | // swallow this invalid key 81 | e.Handled = true; 82 | // MessageBeep(); 83 | } 84 | } 85 | 86 | public int IntValue 87 | { 88 | get 89 | { 90 | return Int32.Parse(this.Text); 91 | } 92 | } 93 | 94 | public bool IsValueValid() 95 | { 96 | int value; 97 | try 98 | { 99 | value = IntValue; 100 | } 101 | catch(Exception) 102 | { 103 | return false; 104 | } 105 | 106 | if ( (value >= minValue) && (value <= maxValue) ) 107 | return true; 108 | else 109 | return false; 110 | } 111 | 112 | public String GetErrorMessage() 113 | { 114 | if (IntValue < minValue) 115 | return description + ": " + Properties.Resources.str_settingsErrorValueToSmall + minValue + "."; 116 | 117 | if (IntValue > maxValue) 118 | return description + ": " + Properties.Resources.str_settingsErrorValueToLarge + maxValue + "."; 119 | 120 | return null; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /src/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 5 15 | 16 | 17 | 30 18 | 19 | 20 | 10 21 | 22 | 23 | 15 24 | 25 | 26 | False 27 | 28 | 29 | 5 30 | 31 | 32 | True 33 | 34 | 35 | False 36 | 37 | 38 | True 39 | 40 | 41 | channelSettings.html 42 | 43 | 44 | channelSettings.html#channel_edit 45 | 46 | 47 | 0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 100 55 | 56 | 57 | 40 58 | 59 | 60 | http://balloonrss.sourceforge.net/checkforupdates.php?curVersion= 61 | 62 | 63 | channelConfig.xml 64 | 65 | 66 | #################################### 67 | 68 | 69 | ########### 70 | 71 | 72 | http://balloonrss.sourceforge.net/releaseinfo.html?curVersion= 73 | 74 | 75 | 5 76 | 77 | 78 | balloonrss.chm 79 | 80 | 81 | applicationSettings.html 82 | 83 | 84 | channelInformation.html 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /bin/BalloonRss.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 5 15 | 16 | 17 | 30 18 | 19 | 20 | 10 21 | 22 | 23 | 15 24 | 25 | 26 | False 27 | 28 | 29 | 5 30 | 31 | 32 | True 33 | 34 | 35 | False 36 | 37 | 38 | True 39 | 40 | 41 | channelSettings.html 42 | 43 | 44 | channelSettings.html#channel_edit 45 | 46 | 47 | 0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 100 55 | 56 | 57 | 40 58 | 59 | 60 | http://balloonrss.sourceforge.net/checkforupdates.php?curVersion= 61 | 62 | 63 | channelConfig.xml 64 | 65 | 66 | #################################### 67 | 68 | 69 | ########### 70 | 71 | 72 | http://balloonrss.sourceforge.net/releaseinfo.html?curVersion= 73 | 74 | 75 | 5 76 | 77 | 78 | balloonrss.chm 79 | 80 | 81 | applicationSettings.html 82 | 83 | 84 | channelInformation.html 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/FormHistory.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2010 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Windows.Forms; 22 | using BalloonRss.Properties; 23 | 24 | 25 | namespace BalloonRss 26 | { 27 | class FormHistory : Form 28 | { 29 | private int panelWidth = 400; 30 | private int panelHeight = 200; 31 | 32 | private RssItem[] rssHistory; 33 | private ListView listView; 34 | 35 | 36 | public FormHistory(Queue rssHistory) 37 | { 38 | // store associated data 39 | this.rssHistory = rssHistory.ToArray(); 40 | 41 | // build GUI 42 | this.SuspendLayout(); 43 | InitializeComponent(); 44 | FillHistoryList(); 45 | this.ResumeLayout(); 46 | } 47 | 48 | 49 | private void InitializeComponent() 50 | { 51 | // 52 | // listHistory 53 | // 54 | this.listView = new ListView(); 55 | this.listView.Dock = System.Windows.Forms.DockStyle.Fill; 56 | this.listView.UseCompatibleStateImageBehavior = false; 57 | this.listView.View = View.Details; 58 | this.listView.AllowColumnReorder = true; 59 | this.listView.FullRowSelect = true; 60 | this.listView.DoubleClick += new EventHandler(OnItemActivate); 61 | 62 | // 63 | // FormHistory 64 | // 65 | this.ClientSize = new System.Drawing.Size(panelWidth, panelHeight); 66 | this.Controls.Add(this.listView); 67 | this.MinimizeBox = false; 68 | this.Text = Resources.str_historyFormTitle; 69 | this.Icon = Resources.ico_yellow32; 70 | } 71 | 72 | 73 | protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 74 | { 75 | try 76 | { 77 | // close window using Escape key 78 | if (msg.WParam.ToInt32() == (int)Keys.Escape) 79 | Dispose(); 80 | } 81 | catch (Exception) 82 | { 83 | } 84 | 85 | return base.ProcessCmdKey(ref msg, keyData); 86 | } 87 | 88 | 89 | private void FillHistoryList() 90 | { 91 | ListViewItem[] listItems = new ListViewItem[rssHistory.Length]; 92 | 93 | // set the table headers 94 | listView.Columns.Add(Resources.str_historyHeaderId, -2, HorizontalAlignment.Center); 95 | listView.Columns.Add(Resources.str_historyHeaderTitle, -2, HorizontalAlignment.Left); 96 | listView.Columns.Add(Resources.str_historyHeaderChannel, -2, HorizontalAlignment.Left); 97 | listView.Columns.Add(Resources.str_historyHeaderTimestamp, -2, HorizontalAlignment.Left); 98 | 99 | // create the list items 100 | for (int i = 0; i < rssHistory.Length; i++) 101 | { 102 | listItems[i] = new ListViewItem("" + (i + 1)); 103 | // add title, if unavailable use description (one is always there) 104 | if (rssHistory[rssHistory.Length - 1 - i].title != null) 105 | listItems[i].SubItems.Add(rssHistory[rssHistory.Length - 1 - i].title); 106 | else 107 | listItems[i].SubItems.Add(rssHistory[rssHistory.Length - 1 - i].description); 108 | // add feed link 109 | if (rssHistory[rssHistory.Length - 1 - i].GetType() != typeof(RssUpdateItem)) 110 | listItems[i].SubItems.Add(rssHistory[rssHistory.Length - 1 - i].channel.channelInfo.link); 111 | else 112 | listItems[i].SubItems.Add(""); 113 | // add time and link (not shown) 114 | listItems[i].SubItems.Add(rssHistory[rssHistory.Length - 1 - i].dispDate.ToShortTimeString()); 115 | listItems[i].SubItems.Add(rssHistory[rssHistory.Length - 1 - i].link); 116 | } 117 | listView.Items.AddRange(listItems); 118 | } 119 | 120 | 121 | // as an item is double clicked, open the link 122 | private void OnItemActivate(object sender, EventArgs e) 123 | { 124 | foreach (ListViewItem listItem in listView.SelectedItems) 125 | { 126 | // start the link of the RSS item 127 | RssItem rssItem = rssHistory[rssHistory.Length - 1 - listItem.Index]; 128 | if (rssItem.GetType() != typeof(RssUpdateItem)) 129 | { 130 | rssItem.channel.ActivateItem(rssItem); 131 | } 132 | else 133 | { 134 | // this is an application update information 135 | System.Diagnostics.Process.Start(rssItem.link); 136 | } 137 | } 138 | 139 | // close window 140 | Dispose(); 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /src/AboutBox.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /docs/releasenotes.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - Release Notes - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 31 | 32 | 42 | 43 |
44 | 45 | 46 |

Release Notes

47 | 48 |

Release 2.9 (March 11th, 2010)

49 |
    50 |
  • add configurable double click action
  • 51 |
  • close all dialogs also using the escape key
  • 52 |
  • rephrasing of some strings
  • 53 |
  • prevent repeated/cascading dialog opening
  • 54 |
  • bugfix: some http proxies aborted with an authentication error
  • 55 |
56 | 57 |

Release 2.8 (July 26th, 2009)

58 |
    59 |
  • support RSS feeds, which only define the title or content of an RSS item but not both
  • 60 |
61 | 62 |

Release 2.7 (February 15th, 2009)

63 |
    64 |
  • support for authenticated HTTP requests
  • 65 |
  • add help system
  • 66 |
  • add feature to mark all RSS messages as read at program startup
  • 67 |
  • bug fix: could not edit priority tag in channel list
  • 68 |
69 | 70 |

Release 2.6 (February 2nd, 2009)

71 |
    72 |
  • add about dialog with version information
  • 73 |
  • change unit of some settings from seconds to minutes
  • 74 |
  • bug fix: task bar icon did not disappear immediately on exit
  • 75 |
  • bug fix: autostart feature did not work in non-English OS versions
  • 76 |
77 | 78 |

Release 2.5 (January 5th, 2009)

79 |
    80 |
  • allow RSS channels that are retrieved via file requests (and not via HTTP)
  • 81 |
  • improve robustness of HTML tag stripping
  • 82 |
  • extend default width of channel info dialog
  • 83 |
84 | 85 |

Release 2.4 (December 28th, 2008)

86 |
    87 |
  • add possibility to use global channel config settings in addition to user specific channel configuration
  • 88 |
  • display locked or unlocked icon in channel settings for global / user channel settings, respectively
  • 89 |
  • check for duplicate channel on "new" and "edit" in channel settings
  • 90 |
  • installer: allow program group selection
  • 91 |
92 | 93 |

Release 2.3 (August 2nd, 2008)

94 |
    95 |
  • strip HTML characters, which are present in some RSS feeds
  • 96 |
  • add option to disable network error reporting
  • 97 |
  • various string updates
  • 98 |
  • bug fix: click ration was calculated wrong if "mark all read" was used
  • 99 |
  • bug fix: a race condition could have occured if the channel settings dialog was shortly opened during channel retrieval
  • 100 |
  • bug fix: a null pointer exception occured if a new version of BalloonRSS was found in auto-update and the settings were set to view the channel as title
  • 101 |
102 | 103 |

Release 2.2 (March 15th, 2008)

104 |
    105 |
  • support atom RSS feed format
  • 106 |
  • add "mark all read" feature
  • 107 |
  • change design of main context menu to modern UI look
  • 108 |
  • provide setting to start application in pause mode
  • 109 |
  • use application icon in installer and uninstaller
  • 110 |
  • provide default channel settings from resource file instead of defaultChannels.xml, which is now not needed anymore
  • 111 |
  • provide language specific default RSS channels
  • 112 |
  • improve format checks on the xml files and user input
  • 113 |
  • switch to C# 2008 development environment
  • 114 |
115 | 116 |

Release 2.1 (January 25th, 2008)

117 |
    118 |
  • add German translation
  • 119 |
  • add Portuguese translation
  • 120 |
  • multiple language support
  • 121 |
  • possibility to check for available application updates
  • 122 |
  • make the view rate dependent on channel priority
  • 123 |
  • bug fix: avoid exception in case of RSS feed with empty description text
  • 124 |
125 | 126 |

Release 2.0 (January 6th, 2008)

127 |
    128 |
  • record opened RSS messages
  • 129 |
  • derive effective priority based on viewed and opened messages
  • 130 |
  • extend channel information dialog with click rate and effective priority
  • 131 |
  • add possibility to delete collected channel data
  • 132 |
  • add uninstall information to Add/Remove Programs
  • 133 |
134 | 135 |

Release 1.2 (December 16th, 2007)

136 |
    137 |
  • NSIS installer update: remove application dependent data
  • 138 |
  • user dependent channel configuration
  • 139 |
  • allow application start also without channel config file
  • 140 |
  • display welcome pop-up at first application start
  • 141 |
  • just start a single application instance per user
  • 142 |
  • add "last update" entry in channel information
  • 143 |
  • add "retrieve RSS channels" feature
  • 144 |
  • add slashdot as a second default RSS channel
  • 145 |
146 | 147 |

Release 1.1 (November 11th, 2007)

148 |
    149 |
  • add application settings dialog
  • 150 |
  • add channel config dialog
  • 151 |
  • update README.txt, including a usage description
  • 152 |
  • add pause functionality
  • 153 |
  • change icon usage: blue icon is now used for pause mode
  • 154 |
  • add the display time in message history dialog
  • 155 |
156 | 157 |

Release 1.0 (October 24th, 2007)

158 |
    159 |
  • added NSIS installer program
  • 160 |
  • remove icon from ALT-TAB menu
  • 161 |
  • add channel information dialog
  • 162 |
  • add history dialog
  • 163 |
  • add last message / next message feature
  • 164 |
165 | 166 |
167 | top TOP 168 |
169 | 170 |
171 | 172 |
173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /docs/usage.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | BalloonRSS - Usage - A simple RSS aggregator using balloon tooltips 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 32 | 33 | 43 | 44 |
45 | 46 |

Usage

47 | 48 |

As you start the application you get a notify icon in the windows task bar (at the right button, near the clock). All commands are accessed by the context menu (right click on the icon). Make sure that the icon is always shown and not hidden by configuring this in windows.

49 | 50 |

The first thing you might want to do is add your favorite RSS channels to be displayed. For this you need to select RSS Channel Settings and add them there. If you read multiple channels you may want to assign different priorities. Messages from higher priority RSS channels are more likely to be displayed. The effective priority is calculated by the pre-selected priority of the channel settings and the user's click rate. Thus, if you click more messages from one channel, this increases its effective priority and display probability.

51 | 52 |

A single left click on the application icon in the task bar enters pause mode. This is indicated with the color of the icon. No messages will be displayed in this status. Double clicking the icon may also have functionality if this is configured in the application settings.

53 | 54 |

Color codes of the icon:

55 |
    56 |
  • yellow icon yellow: application active with messages pending
  • 57 |
  • orange icon orange: application active without messages pending
  • 58 |
  • blue icon blue: application paused
  • 59 |
60 | 61 |

Further information can be obtained by the application help system. Just press F1 in any configuration dialog to get specific help on it.

62 | 63 | 64 |

Advanced Usage

65 | 66 |

Private RSS Channels using HTTP Authentication

67 |

In some cases a private RSS feed might be protected by HTTP authentication where you must enter a username and a password to access it. You can use BalloonRSS also for such feeds. For this you need to edit the channel configuration file channelConfig.xml. It is located in the user data directory, e.g. at C:\Users\<user_name>\AppData\Roaming\BalloonRSS for Windows Vista and C:\Documents and Settings\<user_name>\Application Data\BalloonRSS for WinXP. This directory may be hidden and you may have to type the link in the explorer window directly to access it. There, you need to add the XML tags httpAuthUsername and httpAuthPassword to the configuration. Here you see an example:

68 |

channelConfig.xml:

69 |
 70 | <channels>
 71 |   <item>
 72 |     <link>http://link_to_private_RSS_channel/rss.xml</link>
 73 |     <priority>5</priority>
 74 |     <httpAuthUsername>enter_username_here</httpAuthUsername>
 75 |     <httpAuthPassword>enter_password_here</httpAuthPassword>
 76 |   </item>
 77 | </channels>
 78 | 
79 |

This configuration is not visible within the graphical channel settings dialog. I think that protected RSS channels are an exceptional use case and I do not want to confuse the average user with such settings, which are normally not needed.

80 | 81 | 82 |

Configuration in Multi-User Environment

83 | 84 |

Pre-Definition of RSS Channel Settings

85 |

BalloonRSS uses 2 channel configuration files:

86 |
    87 |
  1. A user specific channel configuration (located in the user settings directory, e.g. C:\Users\<user_name>\AppData\Roaming\BalloonRSS)
  2. 88 |
  3. A computer specific channel configuration (located in the program directory, e.g. C:\Program Files\BalloonRSS).
  4. 89 |
90 | 91 |

Using the configuration dialogs in the GUI, you always modify user's channel entries. The global channel settings can only be changed by directly creating and editing the configuration .xml file.

92 | 93 |

The easiest way to configure the global channel settings is to configure the desired global channels as a user and then move the channelConfig.xml file from the user settings directory to the program directory. Afterwards you may add additional user channels.

94 | 95 |

Pre-Definition of Application Settings

96 |

You may pre-define application settings in a multi-user environment by putting a configuration file BalloonRss.exe.config in the program directory. You need to manually edit this XML file. You start by obtaining the default settings file from the git repository at /bin/BalloonRss.exe.config and modify it according your needs.

97 | 98 |

Once a user modifies its settings using the application configuration dialog, BalloonRSS will create a user specific setting file in the user directory. This file then overrides the global application settings.

99 | 100 |
101 | top TOP 102 |
103 | 104 |
105 | 106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /src/ChannelInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2009 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Text; 21 | using System.Xml; 22 | using BalloonRss.Properties; 23 | 24 | 25 | namespace BalloonRss 26 | { 27 | public class ChannelInfo 28 | { 29 | private const String xmlLinkName = "link"; 30 | private const String xmlPriorityName = "priority"; 31 | private const String xmlAuthUserName = "httpAuthUsername"; 32 | private const String xmlAuthPwdName = "httpAuthPassword"; 33 | private const String xmlMarkAsReadName = "markAsReadAtStartup"; 34 | 35 | public String link; 36 | public byte priority; 37 | public bool globalChannel = false; 38 | public String httpAuthUsername = null; 39 | public String httpAuthPassword = null; 40 | public bool markAsReadAtStartup = false; 41 | 42 | 43 | // the empty constructor is used as a new channel is entered 44 | public ChannelInfo() 45 | { 46 | link = Resources.str_channelSettingsDefault1Link; 47 | priority = Settings.Default.defaultChannelPriority; 48 | } 49 | 50 | 51 | // this constructor is used as the default channels are initialized 52 | public ChannelInfo(string link, string priority) 53 | { 54 | // check and save link 55 | this.link = link; 56 | if (!IsValidLink(link)) 57 | { 58 | throw new FormatException(); 59 | } 60 | 61 | // check and save priority 62 | try 63 | { 64 | this.priority = Convert.ToByte(priority); 65 | } 66 | catch (Exception) 67 | { 68 | // if the priority is illegal, use the default without comment 69 | this.priority = Settings.Default.defaultChannelPriority; 70 | } 71 | } 72 | 73 | 74 | // the clone constructor is used for temporary editing channels 75 | public ChannelInfo(ChannelInfo templateChannel) 76 | { 77 | link = templateChannel.link; 78 | priority = templateChannel.priority; 79 | globalChannel = templateChannel.globalChannel; 80 | httpAuthUsername = templateChannel.httpAuthUsername; 81 | httpAuthPassword = templateChannel.httpAuthPassword; 82 | markAsReadAtStartup = templateChannel.markAsReadAtStartup; 83 | } 84 | 85 | 86 | // this constructor is used by reading the config file 87 | public ChannelInfo(XmlNode itemNode) 88 | { 89 | // default settings 90 | link = null; 91 | priority = Settings.Default.defaultChannelPriority; 92 | 93 | // the xml node we get is already a channel node 94 | foreach (XmlNode xmlChild in itemNode) 95 | { 96 | String curTag = xmlChild.Name.Trim(); 97 | 98 | // what xml tag did we find? 99 | switch (curTag) 100 | { 101 | // the mandatory link tag 102 | case xmlLinkName: 103 | link = xmlChild.InnerText; 104 | if (!IsValidLink(link)) 105 | throw new FormatException(); 106 | break; 107 | 108 | // the optional priority tag 109 | case xmlPriorityName: 110 | // if this raises an exception, that's fine 111 | priority = Convert.ToByte(xmlChild.InnerText); 112 | break; 113 | 114 | // the optional http auth user tag 115 | case xmlAuthUserName: 116 | httpAuthUsername = xmlChild.InnerText; 117 | break; 118 | 119 | // the optional http auth pwd tag 120 | case xmlAuthPwdName: 121 | httpAuthPassword = xmlChild.InnerText; 122 | break; 123 | 124 | case xmlMarkAsReadName: 125 | // if this raises an exception, that's fine 126 | markAsReadAtStartup = Convert.ToBoolean(xmlChild.InnerText); 127 | break; 128 | 129 | // skip all unknown tags without comment 130 | default: 131 | break; 132 | } 133 | } 134 | 135 | // the link field is mandatory 136 | if (link == null) 137 | throw new FormatException(Resources.str_balloonErrorChannelLinkTag); 138 | } 139 | 140 | 141 | // this is used as the channel settings are written to the xml file 142 | public void DumpChannelInfo(XmlDocument channelFile, XmlElement xmlChannelInfo) 143 | { 144 | // save link tag 145 | XmlElement xmlLink = channelFile.CreateElement(xmlLinkName); 146 | xmlLink.InnerText = this.link; 147 | xmlChannelInfo.AppendChild(xmlLink); 148 | 149 | // save priority tag 150 | XmlElement xmlPriority = channelFile.CreateElement(xmlPriorityName); 151 | xmlPriority.InnerText = this.priority.ToString(); 152 | xmlChannelInfo.AppendChild(xmlPriority); 153 | 154 | // save "mark as read" tag 155 | XmlElement xmlMarkAsRead = channelFile.CreateElement(xmlMarkAsReadName); 156 | xmlMarkAsRead.InnerText = this.markAsReadAtStartup.ToString(); 157 | xmlChannelInfo.AppendChild(xmlMarkAsRead); 158 | 159 | // save http auth user tag 160 | if (httpAuthUsername != null) 161 | { 162 | XmlElement xmlAuthUser = channelFile.CreateElement(xmlAuthUserName); 163 | xmlAuthUser.InnerText = this.httpAuthUsername.ToString(); 164 | xmlChannelInfo.AppendChild(xmlAuthUser); 165 | } 166 | // save http auth pwd tag 167 | if (httpAuthPassword != null) 168 | { 169 | XmlElement xmlAuthPwd = channelFile.CreateElement(xmlAuthPwdName); 170 | xmlAuthPwd.InnerText = this.httpAuthPassword.ToString(); 171 | xmlChannelInfo.AppendChild(xmlAuthPwd); 172 | } 173 | } 174 | 175 | 176 | public static bool IsValidLink(String link) 177 | { 178 | if (Uri.IsWellFormedUriString(link, UriKind.RelativeOrAbsolute) 179 | && (link.Trim().Length > 0)) 180 | return true; 181 | else 182 | return false; 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/RssItem.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2008 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Text; 21 | using System.Text.RegularExpressions; 22 | using System.Xml; 23 | 24 | 25 | namespace BalloonRss 26 | { 27 | public class RssItem 28 | { 29 | public String title = null; 30 | public String description = null; 31 | public String author = null; 32 | public String link = null; 33 | public DateTime pubDate = DateTime.MinValue; 34 | 35 | public DateTime creationDate = DateTime.MinValue; 36 | public DateTime dispDate = DateTime.MinValue; 37 | public RssChannel channel; 38 | 39 | 40 | protected RssItem() 41 | { 42 | pubDate = DateTime.MinValue; 43 | creationDate = DateTime.Now; 44 | channel = null; 45 | dispDate = DateTime.MinValue; 46 | } 47 | 48 | public RssItem(XmlNode xmlNode, RssChannel channel) 49 | { 50 | this.creationDate = DateTime.Now; 51 | this.channel = channel; 52 | 53 | // parse it 54 | foreach (XmlNode curXmlNode in xmlNode.ChildNodes) 55 | { 56 | String curTag = curXmlNode.Name.Trim().ToLower(); 57 | 58 | switch (curTag) 59 | { 60 | // mandatory attributes 61 | case "title": 62 | this.title = StripHtml(curXmlNode.InnerText); 63 | break; 64 | case "link": 65 | if (channel.channelType != "feed") 66 | { 67 | this.link = curXmlNode.InnerText; 68 | } 69 | else 70 | { 71 | this.link = curXmlNode.Attributes.GetNamedItem("href").Value; 72 | } 73 | break; 74 | case "description": // for rss and rdf feeds 75 | case "summary": // for atom feeds 76 | this.description = StripHtml(curXmlNode.InnerText); 77 | break; 78 | 79 | // optional attributes 80 | case "author": 81 | this.author = curXmlNode.InnerText; 82 | break; 83 | case "pubdate": // for rss and rdf feeds 84 | case "updated": // for atom feeds 85 | this.pubDate = ParseDate(curXmlNode.InnerText); 86 | break; 87 | 88 | default: 89 | // skip all other tags 90 | break; 91 | } 92 | } 93 | 94 | // some feeds use empty fields which is not acceptable 95 | if (title == "") 96 | title = null; 97 | if (description == "") 98 | description = null; 99 | 100 | // the title and description fields are mandatory 101 | if ((title == null) && (description == null)) 102 | throw new FormatException("Could not find title and description field in RSS item"); 103 | } 104 | 105 | 106 | private String StripHtml(String text) 107 | { 108 | String escapedText = null; 109 | 110 | // strip all html tags like and translate special chars like & 111 | try 112 | { 113 | // let the XML classes do the format conversion 114 | XmlNode xmlNode = new XmlDocument().CreateElement("stripEntity"); 115 | xmlNode.InnerXml = text; 116 | escapedText = xmlNode.InnerText; 117 | } 118 | catch (XmlException) 119 | { 120 | // the XML classes could not convert the text 121 | // it seems that the text was already escaped or is illegal (which happens!) 122 | // e.g. we get an exception for strings like "harry & sally" 123 | 124 | // should we still remove the tags like ? Yes. 125 | 126 | // first, remove special characters like & 127 | int lastMatchPosEnd = 0; 128 | escapedText = ""; 129 | foreach (Match match in Regex.Matches(text, @"&[^;]{2,10};")) 130 | { 131 | // convert identified character 132 | // again, try to use the XML classes for this 133 | string replacement; 134 | try 135 | { 136 | XmlNode charXmlNode = new XmlDocument().CreateElement("charNode"); 137 | charXmlNode.InnerXml = match.Value; 138 | replacement = charXmlNode.InnerText; 139 | } 140 | catch (Exception) 141 | { 142 | // fallback to "?" in case of wrong regex match 143 | replacement = "?"; 144 | } 145 | 146 | // append to string 147 | escapedText += text.Substring(lastMatchPosEnd, match.Index - lastMatchPosEnd) + replacement; 148 | lastMatchPosEnd = match.Index + match.Length; 149 | } 150 | // append rest of string 151 | escapedText += text.Substring(lastMatchPosEnd); 152 | 153 | // replace

and
with carrige returns 154 | escapedText = Regex.Replace(escapedText, @"<(p|br)\s?/?>", "\n"); 155 | 156 | // remove the remaining tags 157 | escapedText = Regex.Replace(escapedText, @"<[^>]+>", ""); 158 | } 159 | catch (Exception) 160 | { 161 | // we do not expect any other exceptions here 162 | // just take the unmodified text in this case 163 | escapedText = text; 164 | } 165 | 166 | return escapedText; 167 | } 168 | 169 | 170 | private DateTime ParseDate(String text) 171 | { 172 | DateTime dateTime = DateTime.MinValue; 173 | 174 | try 175 | { 176 | dateTime = DateTime.Parse(text); 177 | } 178 | catch (FormatException) 179 | { 180 | // we might get an parse exception in case of US non-standard time, like "Thu, 05 May 2005 14:50:52 EDT" 181 | // truncate until last blank then and retry 182 | text = text.Substring(0, text.LastIndexOf(" ")); 183 | try 184 | { 185 | dateTime = DateTime.Parse(text); 186 | } 187 | catch (FormatException) 188 | { 189 | } 190 | } 191 | 192 | return dateTime; 193 | } 194 | 195 | 196 | public DateTime GetDate() 197 | { 198 | if (pubDate != DateTime.MinValue) 199 | return pubDate; 200 | else 201 | return creationDate; 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/FormChannelInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2010 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Windows.Forms; 21 | using BalloonRss.Properties; 22 | 23 | 24 | namespace BalloonRss 25 | { 26 | class FormChannelInfo : Form 27 | { 28 | private const int panelWidth = 600; 29 | private const int panelHeight = 200; 30 | 31 | private RssChannel[] rssChannel; 32 | private ListView listView; 33 | private ListViewItem[] listItems; 34 | private ContextMenuStrip contextMenu; 35 | 36 | 37 | public FormChannelInfo(RssChannel[] rssChannel) 38 | { 39 | // store references to the channels 40 | this.rssChannel = rssChannel; 41 | 42 | // build GUI 43 | this.SuspendLayout(); 44 | InitializeComponent(); 45 | FillChannelList(); 46 | this.ResumeLayout(); 47 | } 48 | 49 | 50 | private void InitializeComponent() 51 | { 52 | // contextMenu 53 | contextMenu = new ContextMenuStrip(); 54 | ToolStripMenuItem menuItem = new ToolStripMenuItem(); 55 | menuItem.Text = Resources.str_channelContextMenuMarkRead; 56 | menuItem.Click += new EventHandler(MiMarkAllReadClick); 57 | contextMenu.Items.Add(menuItem); 58 | menuItem = new ToolStripMenuItem(); 59 | menuItem.Text = Resources.str_channelContextMenuClearData; 60 | menuItem.Click += new EventHandler(MiClearChannelDataClick); 61 | contextMenu.Items.Add(menuItem); 62 | 63 | // listView 64 | this.listView = new System.Windows.Forms.ListView(); 65 | this.listView.Dock = System.Windows.Forms.DockStyle.Fill; 66 | this.listView.UseCompatibleStateImageBehavior = false; 67 | this.listView.View = View.Details; 68 | this.listView.AllowColumnReorder = true; 69 | this.listView.FullRowSelect = true; 70 | this.listView.DoubleClick += new EventHandler(OnItemActivate); 71 | //this.listView.ContextMenuStrip = contextMenu; 72 | this.listView.MouseClick += new MouseEventHandler(ListView_MouseClick); 73 | 74 | // Form 75 | this.ClientSize = new System.Drawing.Size(panelWidth, panelHeight); 76 | this.Controls.Add(this.listView); 77 | this.MinimizeBox = false; 78 | this.MaximizeBox = false; 79 | this.Text = Resources.str_channelFormTitle; 80 | this.Icon = Resources.ico_yellow32; 81 | this.HelpButton = true; 82 | this.HelpRequested += new HelpEventHandler(FormChannelInfo_HelpRequested); 83 | } 84 | 85 | void FormChannelInfo_HelpRequested(object sender, HelpEventArgs hlpevent) 86 | { 87 | Help.ShowHelp(this, Settings.Default.helpFilename, HelpNavigator.Topic, Settings.Default.helpNameChannelInfo); 88 | } 89 | 90 | 91 | protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 92 | { 93 | try 94 | { 95 | // close window using Escape key 96 | if (msg.WParam.ToInt32() == (int)Keys.Escape) 97 | Dispose(); 98 | } 99 | catch (Exception) 100 | { 101 | } 102 | 103 | return base.ProcessCmdKey(ref msg, keyData); 104 | } 105 | 106 | 107 | private void FillChannelList() 108 | { 109 | listItems = new ListViewItem[rssChannel.Length]; 110 | 111 | // set the table headers 112 | listView.Columns.Add(Resources.str_channelHeaderTitle, -2, HorizontalAlignment.Left); 113 | listView.Columns.Add(Resources.str_channelHeaderPrio, -2, HorizontalAlignment.Center); 114 | listView.Columns.Add(Resources.str_channelHeaderClickRate, -2, HorizontalAlignment.Center); 115 | listView.Columns.Add(Resources.str_channelHeaderEffPrio, -2, HorizontalAlignment.Center); 116 | listView.Columns.Add(Resources.str_channelHeaderCount, -2, HorizontalAlignment.Center); 117 | listView.Columns.Add(Resources.str_channelHeaderTotal, -2, HorizontalAlignment.Center); 118 | listView.Columns.Add(Resources.str_channelHeaderLastUpdate, -2, HorizontalAlignment.Center); 119 | 120 | // create the list items 121 | for (int i = 0; i < rssChannel.Length; i++) 122 | { 123 | listItems[i] = new ListViewItem(); 124 | FillListSubItems(i); 125 | } 126 | listView.Items.AddRange(listItems); 127 | } 128 | 129 | // this fills the text of a list item 130 | // the list item has to be created before 131 | private void FillListSubItems(int index) 132 | { 133 | string viewCount = "-"; 134 | if (rssChannel[index].channelViewedCount > 0) 135 | viewCount = "" + 100 * rssChannel[index].channelOpenedCount / rssChannel[index].channelViewedCount + " %"; 136 | 137 | // we need to clear potential old list data for the case of a refresh 138 | listItems[index].SubItems.Clear(); 139 | 140 | // add the text data 141 | listItems[index].Text = rssChannel[index].title; 142 | listItems[index].SubItems.AddRange(new string[] { 143 | "" + rssChannel[index].channelInfo.priority, 144 | viewCount, 145 | "" + rssChannel[index].effectivePriority, 146 | "" + rssChannel[index].Count, 147 | "" + rssChannel[index].channelMessageCount, 148 | "" + rssChannel[index].lastUpdate, 149 | "" + rssChannel[index].channelInfo.link, 150 | } ); 151 | } 152 | 153 | 154 | // start link to channel on double click 155 | private void OnItemActivate(object sender, EventArgs e) 156 | { 157 | foreach (ListViewItem item in listView.SelectedItems) 158 | { 159 | // start the link of the channel 160 | System.Diagnostics.Process.Start(item.SubItems[7].Text); 161 | } 162 | 163 | // close window 164 | Dispose(); 165 | } 166 | 167 | 168 | // display context menu 169 | private void ListView_MouseClick(object sender, MouseEventArgs e) 170 | { 171 | if ((e.Button == MouseButtons.Right) && (e.Clicks == 1)) 172 | { 173 | contextMenu.Show(listView, e.Location); 174 | } 175 | } 176 | 177 | 178 | // mark all channel data as read for all selected list items 179 | private void MiMarkAllReadClick(object sender, EventArgs e) 180 | { 181 | foreach (ListViewItem item in listView.SelectedItems) 182 | { 183 | rssChannel[item.Index].MarkAllRead(); 184 | // also update the display 185 | FillListSubItems(item.Index); 186 | } 187 | } 188 | 189 | // clear channel data as read for all selected list items 190 | private void MiClearChannelDataClick(object sender, EventArgs e) 191 | { 192 | foreach (ListViewItem item in listView.SelectedItems) 193 | { 194 | rssChannel[item.Index].ClearChannelData(); 195 | // also update the display 196 | FillListSubItems(item.Index); 197 | } 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /install/dotnet.nsh: -------------------------------------------------------------------------------- 1 | ; 2 | ;BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | ; Copyright (C) 2007 Roman Morawek 4 | ; 5 | ; This program is free software: you can redistribute it and/or modify 6 | ; it under the terms of the GNU General Public License as published by 7 | ; the Free Software Foundation, either version 3 of the License, or 8 | ; (at your option) any later version. 9 | ; 10 | ; This program is distributed in the hope that it will be useful, 11 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ; GNU General Public License for more details. 14 | ; 15 | ; You should have received a copy of the GNU General Public License 16 | ; along with this program. If not, see . 17 | ; 18 | 19 | 20 | ;-------------------------------- 21 | ;Definitions 22 | ; URL to the .NET Framework 2.0 download 23 | ; No different locales needed for it is multilingual 24 | !define URL_DOTNET "http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe" 25 | 26 | 27 | ;-------------------------------- 28 | ; Declaring variables 29 | Var "DOTNET_RETURN_CODE" 30 | 31 | 32 | ;-------------------------------- 33 | ; Section for .NET Framework 34 | ; This downloads and installs Miscrosoft .NET Framework 2.0 35 | ; if not found on the system 36 | 37 | Section $(SEC_DOTNET) SecDotNet 38 | Call IsDotNETInstalled 39 | Pop $R3 40 | ; IsDotNETInstalled returns 1 for yes and 0 for no 41 | StrCmp $R3 "1" lbl_isinstalled lbl_notinstalled 42 | 43 | lbl_notinstalled: 44 | 45 | SectionIn RO 46 | ; the following Goto and Label is for consistencey. 47 | Goto lbl_DownloadRequired 48 | 49 | lbl_DownloadRequired: 50 | MessageBox MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON2 "$(DESC_DOTNET_DECISION)" /SD IDNO \ 51 | IDYES +2 IDNO lbl_Done 52 | DetailPrint "$(DESC_DOWNLOADING1) $(DESC_SHORTDOTNET)..." 53 | ; "Downloading Microsoft .Net Framework" 54 | ;AddSize 286720 ;already included above 55 | nsisdl::download /TRANSLATE "$(DESC_DOWNLOADING)" "$(DESC_CONNECTING)" \ 56 | "$(DESC_SECOND)" "$(DESC_MINUTE)" "$(DESC_HOUR)" "$(DESC_PLURAL)" \ 57 | "$(DESC_PROGRESS)" "$(DESC_REMAINING)" \ 58 | /TIMEOUT=30000 "${URL_DOTNET}" "$PLUGINSDIR\dotnetfx.exe" 59 | Pop $0 60 | StrCmp "$0" "success" lbl_continue 61 | DetailPrint "$(DESC_DOWNLOADFAILED) $0" 62 | Abort 63 | 64 | ; start installation of .NET framework 65 | lbl_continue: 66 | DetailPrint "$(DESC_INSTALLING) $(DESC_SHORTDOTNET)..." 67 | Banner::show /NOUNLOAD "$(DESC_INSTALLING) $(DESC_SHORTDOTNET)..." 68 | nsExec::ExecToStack '"$PLUGINSDIR\dotnetfx.exe" /q /c:"install.exe /noaspupgrade /q"' 69 | pop $DOTNET_RETURN_CODE 70 | Banner::destroy 71 | SetRebootFlag false 72 | ; silence the compiler 73 | Goto lbl_NoDownloadRequired 74 | 75 | lbl_NoDownloadRequired: 76 | 77 | ; obtain any error code and inform the user ($DOTNET_RETURN_CODE) 78 | ; If nsExec is unable to execute the process, 79 | ; it will return "error" 80 | ; If the process timed out it will return "timeout" 81 | ; else it will return the return code from the executed process. 82 | StrCmp "$DOTNET_RETURN_CODE" "" lbl_NoError 83 | StrCmp "$DOTNET_RETURN_CODE" "0" lbl_NoError 84 | StrCmp "$DOTNET_RETURN_CODE" "3010" lbl_NoError 85 | StrCmp "$DOTNET_RETURN_CODE" "8192" lbl_NoError 86 | StrCmp "$DOTNET_RETURN_CODE" "error" lbl_Error 87 | StrCmp "$DOTNET_RETURN_CODE" "timeout" lbl_TimeOut 88 | ; It's a .Net Error 89 | StrCmp "$DOTNET_RETURN_CODE" "4101" lbl_Error_DuplicateInstance 90 | StrCmp "$DOTNET_RETURN_CODE" "4097" lbl_Error_NotAdministrator 91 | StrCmp "$DOTNET_RETURN_CODE" "1633" lbl_Error_InvalidPlatform lbl_FatalError 92 | ; all others are fatal 93 | 94 | lbl_Error_DuplicateInstance: 95 | DetailPrint "$(ERROR_DUPLICATE_INSTANCE)" 96 | GoTo lbl_Done 97 | 98 | lbl_Error_NotAdministrator: 99 | DetailPrint "$(ERROR_NOT_ADMINISTRATOR)" 100 | GoTo lbl_Done 101 | 102 | lbl_Error_InvalidPlatform: 103 | DetailPrint "$(ERROR_INVALID_PLATFORM)" 104 | GoTo lbl_Done 105 | 106 | lbl_TimeOut: 107 | DetailPrint "$(DESC_DOTNET_TIMEOUT)" 108 | GoTo lbl_Done 109 | 110 | lbl_Error: 111 | DetailPrint "$(ERROR_DOTNET_INVALID_PATH)" 112 | GoTo lbl_Done 113 | 114 | lbl_FatalError: 115 | DetailPrint "$(ERROR_DOTNET_FATAL)[$DOTNET_RETURN_CODE]" 116 | GoTo lbl_Done 117 | 118 | lbl_Done: 119 | DetailPrint "$(DESC_LONGDOTNET) $(NOT_INSTALLED)" 120 | MessageBox MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON2 "$(FAILED_DOTNET_INSTALL)" /SD IDNO \ 121 | IDYES +2 IDNO 0 122 | DetailPrint "${APPL_NAME} $(NOT_INSTALLED)" 123 | Abort 124 | 125 | lbl_NoError: 126 | 127 | lbl_isinstalled: 128 | SectionEnd 129 | 130 | 131 | ;-------------------------------- 132 | ;Descriptions 133 | 134 | ; Language strings 135 | 136 | 137 | ; strings needed for .NET install 138 | LangString DESC_REMAINING ${LANG_ENGLISH} " (%d %s%s remaining)" 139 | LangString DESC_PROGRESS ${LANG_ENGLISH} "%dkB of %dkB @ %d.%01dkB/s" 140 | LangString DESC_PLURAL ${LANG_ENGLISH} "s" 141 | LangString DESC_HOUR ${LANG_ENGLISH} "hour" 142 | LangString DESC_MINUTE ${LANG_ENGLISH} "minute" 143 | LangString DESC_SECOND ${LANG_ENGLISH} "second" 144 | LangString DESC_CONNECTING ${LANG_ENGLISH} "Connecting..." 145 | LangString DESC_DOWNLOADING ${LANG_ENGLISH} "Downloading %s" 146 | LangString DESC_LONGDOTNET ${LANG_ENGLISH} "Microsoft .Net Framework 2.0" 147 | LangString DESC_SHORTDOTNET ${LANG_ENGLISH} "Microsoft .Net Framework 2.0" 148 | LangString DESC_DOTNET_DECISION ${LANG_ENGLISH} "$(DESC_SHORTDOTNET) was not \ 149 | found on your system. \ 150 | $\nIt is strongly advised that you install $(DESC_SHORTDOTNET) before continuing. \ 151 | $\nIf you choose to continue, you will need to connect to the Internet \ 152 | $\nbefore proceeding. \ 153 | $\n$\nShould $(DESC_SHORTDOTNET) be installed now?" 154 | LangString SEC_DOTNET ${LANG_ENGLISH} "$(DESC_SHORTDOTNET)" 155 | LangString DESC_INSTALLING ${LANG_ENGLISH} "Installing" 156 | LangString DESC_DOWNLOADING1 ${LANG_ENGLISH} "Downloading" 157 | LangString DESC_DOWNLOADFAILED ${LANG_ENGLISH} "Download Failed:" 158 | LangString ERROR_DUPLICATE_INSTANCE ${LANG_ENGLISH} "The $(DESC_SHORTDOTNET) Installer is already running." 159 | LangString ERROR_NOT_ADMINISTRATOR ${LANG_ENGLISH} "You are not administrator." 160 | LangString ERROR_INVALID_PLATFORM ${LANG_ENGLISH} "OS not supported." 161 | LangString DESC_DOTNET_TIMEOUT ${LANG_ENGLISH} "The installation of the $(DESC_SHORTDOTNET) has timed out." 162 | LangString ERROR_DOTNET_INVALID_PATH ${LANG_ENGLISH} "The $(DESC_SHORTDOTNET) Installation $\n was not found in the following location:$\n" 163 | LangString ERROR_DOTNET_FATAL ${LANG_ENGLISH} "A fatal error occurred during the installation $\nof $(DESC_SHORTDOTNET)." 164 | LangString FAILED_DOTNET_INSTALL ${LANG_ENGLISH} "$(DESC_LONGDOTNET) was not installed. \ 165 | $\n${APPL_NAME} may not function properly until $(DESC_LONGDOTNET) is installed. \ 166 | $\n$\nDo you still want to install ${APPL_NAME}?" 167 | LangString NOT_INSTALLED ${LANG_ENGLISH} "was not installed." 168 | 169 | 170 | ;-------------------------------- 171 | ; diverse functions 172 | 173 | ;-------------------------------- 174 | ; Check for .NET Framework install 175 | 176 | Function IsDotNETInstalled 177 | Push $0 178 | Push $1 179 | Push $2 180 | Push $3 181 | Push $4 182 | 183 | ReadRegStr $4 HKEY_LOCAL_MACHINE \ 184 | "Software\Microsoft\.NETFramework" "InstallRoot" 185 | # remove trailing back slash 186 | Push $4 187 | Exch $EXEDIR 188 | Exch $EXEDIR 189 | Pop $4 190 | # if the root directory doesn't exist .NET is not installed 191 | IfFileExists $4 0 noDotNET 192 | 193 | StrCpy $0 0 194 | 195 | EnumStart: 196 | EnumRegKey $2 HKEY_LOCAL_MACHINE \ 197 | "Software\Microsoft\.NETFramework\Policy" $0 198 | IntOp $0 $0 + 1 199 | StrCmp $2 "" noDotNET 200 | 201 | StrCpy $1 0 202 | 203 | EnumPolicy: 204 | EnumRegValue $3 HKEY_LOCAL_MACHINE \ 205 | "Software\Microsoft\.NETFramework\Policy\$2" $1 206 | IntOp $1 $1 + 1 207 | StrCmp $3 "" EnumStart 208 | IfFileExists "$4\$2.$3" foundDotNET EnumPolicy 209 | 210 | noDotNET: 211 | StrCpy $0 0 212 | Goto done 213 | 214 | foundDotNET: 215 | StrCpy $0 1 216 | 217 | done: 218 | Pop $4 219 | Pop $3 220 | Pop $2 221 | Pop $1 222 | Exch $0 223 | FunctionEnd 224 | -------------------------------------------------------------------------------- /src/ChannelList.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2009 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.Xml; 23 | using System.IO; 24 | using BalloonRss.Properties; 25 | 26 | 27 | namespace BalloonRss 28 | { 29 | class ChannelList : List 30 | { 31 | private const String xmlRootNodeName = "channels"; 32 | private const String xmlItemName = "item"; 33 | 34 | 35 | // the constructor loads the channel config file 36 | public ChannelList(out bool fallbackToDefaultChannels) 37 | { 38 | fallbackToDefaultChannels = false; 39 | 40 | // first, we try to read the global config file; 41 | try 42 | { 43 | ParseChannelConfigFile(GetGlobalChannelConfigFilename()); 44 | } 45 | catch (Exception) 46 | { 47 | // if it does not exist we just ignore it 48 | } 49 | // mark the global channels (to distinguish for editing) 50 | foreach (ChannelInfo curChannel in this) 51 | curChannel.globalChannel = true; 52 | 53 | // second, we try to read the user config file; 54 | // if it does not exist and the global config was also empty, we use default settings 55 | try 56 | { 57 | ParseChannelConfigFile(GetUserChannelConfigFilename()); 58 | } 59 | catch (DirectoryNotFoundException) 60 | { 61 | // create settings directory 62 | Directory.CreateDirectory(Path.GetDirectoryName(GetUserChannelConfigFilename())); 63 | 64 | // if the global config file was inexistant or empty, create default channels 65 | if (this.Count == 0) 66 | { 67 | LoadDefaultChannelSettings(); 68 | fallbackToDefaultChannels = true; 69 | } 70 | } 71 | catch (Exception) 72 | { 73 | // this may be a FileNotFoundException or another exception in case of an illegal config file 74 | // we have to load default channels 75 | // if the global config file was inexistant or empty, create default channels 76 | if (this.Count == 0) 77 | { 78 | LoadDefaultChannelSettings(); 79 | fallbackToDefaultChannels = true; 80 | } 81 | } 82 | } 83 | 84 | 85 | private static String GetUserChannelConfigFilename() 86 | { 87 | return System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) 88 | + Path.DirectorySeparatorChar + "BalloonRSS" 89 | + Path.DirectorySeparatorChar + Settings.Default.configFilename; 90 | } 91 | 92 | private static String GetGlobalChannelConfigFilename() 93 | { 94 | return Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) 95 | + Path.DirectorySeparatorChar + Settings.Default.configFilename; 96 | } 97 | 98 | 99 | private void LoadDefaultChannelSettings() 100 | { 101 | // there might be channels left from a config file read attempt; clear them 102 | this.Clear(); 103 | 104 | // create up to 4 default channels 105 | try 106 | { 107 | ChannelInfo newChannel = new ChannelInfo( 108 | Properties.Resources.str_channelSettingsDefault1Link, 109 | Properties.Resources.str_channelSettingsDefault1Priority); 110 | this.Add(newChannel); 111 | } 112 | catch (Exception) { }; 113 | 114 | try 115 | { 116 | ChannelInfo newChannel = new ChannelInfo( 117 | Properties.Resources.str_channelSettingsDefault2Link, 118 | Properties.Resources.str_channelSettingsDefault2Priority); 119 | if (IsNewChannel(newChannel, null)) 120 | this.Add(newChannel); 121 | } 122 | catch (Exception) { }; 123 | 124 | try 125 | { 126 | ChannelInfo newChannel = new ChannelInfo( 127 | Properties.Resources.str_channelSettingsDefault3Link, 128 | Properties.Resources.str_channelSettingsDefault3Priority); 129 | if (IsNewChannel(newChannel, null)) 130 | this.Add(newChannel); 131 | } 132 | catch (Exception) { }; 133 | 134 | try 135 | { 136 | ChannelInfo newChannel = new ChannelInfo( 137 | Properties.Resources.str_channelSettingsDefault4Link, 138 | Properties.Resources.str_channelSettingsDefault4Priority); 139 | if (IsNewChannel(newChannel, null)) 140 | this.Add(newChannel); 141 | } 142 | catch (Exception) { }; 143 | 144 | // as the last step, dump the settings file 145 | SaveToFile(); 146 | } 147 | 148 | 149 | // this parses and loads the channel config file 150 | // in case of any error an exception shall be thrown 151 | private void ParseChannelConfigFile(string configFilename) 152 | { 153 | // open xml configuration file 154 | XmlDocument configFile = new XmlDocument(); 155 | configFile.Load(configFilename); 156 | 157 | // check root tag 158 | if (configFile.DocumentElement.Name != xmlRootNodeName) 159 | throw new FormatException(Resources.str_balloonErrorConfigChannelTag); 160 | 161 | // loop over all channel entries 162 | XmlNodeList itemList = configFile.GetElementsByTagName(xmlItemName); 163 | foreach (XmlNode xmlNode in itemList) 164 | { 165 | // create new channel with this information 166 | ChannelInfo newChannel = new ChannelInfo(xmlNode); 167 | 168 | // search for duplicate node 169 | if (!IsNewChannel(newChannel, null)) 170 | throw new FormatException("duplicate link found"); 171 | 172 | this.Add(newChannel); 173 | } 174 | // configuration read finished 175 | } 176 | 177 | 178 | public bool IsNewChannel(ChannelInfo searchChannel, ChannelInfo excludeChannel) 179 | { 180 | foreach (ChannelInfo curChannel in this) 181 | { 182 | if (curChannel != excludeChannel) 183 | { 184 | if (curChannel.link == searchChannel.link) 185 | return false; 186 | } 187 | } 188 | return true; 189 | } 190 | 191 | 192 | // dump the current channel list to the xml file 193 | public void SaveToFile() 194 | { 195 | // write this information in the channel file 196 | XmlDocument channelFile = new XmlDocument(); 197 | XmlNode xmlRoot; 198 | 199 | // create root node 200 | xmlRoot = channelFile.CreateElement(xmlRootNodeName); 201 | channelFile.AppendChild(xmlRoot); 202 | 203 | // add content 204 | foreach (ChannelInfo curChannelInfo in this) 205 | { 206 | // only store user specific channel settings and do not modify global channels 207 | if (curChannelInfo.globalChannel == false) 208 | { 209 | XmlElement xmlChannelInfo = channelFile.CreateElement(xmlItemName); 210 | curChannelInfo.DumpChannelInfo(channelFile, xmlChannelInfo); 211 | xmlRoot.AppendChild(xmlChannelInfo); 212 | } 213 | } 214 | 215 | // save the file 216 | channelFile.Save(GetUserChannelConfigFilename()); 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /install/balloonRSS.nsi: -------------------------------------------------------------------------------- 1 | ; 2 | ;BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | ; Copyright (C) 2008 Roman Morawek 4 | ; 5 | ; This program is free software: you can redistribute it and/or modify 6 | ; it under the terms of the GNU General Public License as published by 7 | ; the Free Software Foundation, either version 3 of the License, or 8 | ; (at your option) any later version. 9 | ; 10 | ; This program is distributed in the hope that it will be useful, 11 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ; GNU General Public License for more details. 14 | ; 15 | ; You should have received a copy of the GNU General Public License 16 | ; along with this program. If not, see . 17 | ; 18 | 19 | ;-------------------------------- 20 | ;Definitions 21 | !define APPL_NAME "BalloonRSS" 22 | !define APPL_VERSION "2.9" ; keep this consistent with AssemblyInfo.cs! 23 | !define PRODUCT_PUBLISHER "Roman Morawek" 24 | !define PRODUCT_PUBLISHER_WEB_SITE "https://www.embyt.com" 25 | !define PRODUCT_WEB_SITE "https://embyt.github.io/balloonrss" 26 | !define PRODUCT_DOWNLOAD_SITE "https://github.com/embyt/balloonrss/releases" 27 | 28 | !define BASEDIR ".." 29 | 30 | 31 | ;-------------------------------- 32 | ;Includes 33 | !include dotnet.nsh 34 | !include "MUI2.nsh" 35 | 36 | 37 | ;-------------------------------- 38 | ;User defined macros 39 | !macro CheckAppRunning APP_PROCESS_NAME 40 | StrCpy $0 "${APP_PROCESS_NAME}" 41 | DetailPrint "Searching for processes called '$0'" 42 | KillProc::FindProcesses 43 | StrCmp $1 "-1" wooops 44 | Goto AppRunning 45 | 46 | AppRunning: 47 | DetailPrint "-> Found $0 processes running" 48 | StrCmp $0 "0" AppNotRunning 49 | MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "${APP_PROCESS_NAME} is currently running. $\n$\nDo you want to close it and continue installation?" IDYES KillApp 50 | DetailPrint "Installation Aborted!" 51 | Abort 52 | KillApp: 53 | StrCpy $0 "${APP_PROCESS_NAME}" 54 | DetailPrint "Killing all processes called '$0'" 55 | KillProc::KillProcesses 56 | StrCmp $1 "-1" wooops 57 | DetailPrint "-> Killed $0 processes, failed to kill $1 processes" 58 | sleep 1500 59 | Goto AppNotRunning 60 | wooops: 61 | DetailPrint "-> Error: Something went wrong :-(" 62 | Abort 63 | AppNotRunning: 64 | DetailPrint "No Application Instances Found" 65 | !macroend 66 | 67 | 68 | ;-------------------------------- 69 | ;General 70 | 71 | ;Name and file 72 | Name "${APPL_NAME} ${APPL_VERSION}" 73 | OutFile "${APPL_NAME}_${APPL_VERSION}_setup.exe" 74 | 75 | ;Default installation folder 76 | InstallDir "$PROGRAMFILES\${APPL_NAME}" 77 | 78 | ;Get installation folder from registry if available 79 | InstallDirRegKey HKLM "Software\${APPL_NAME}" "Install_Dir" 80 | 81 | ;Start Menu Folder Page Configuration 82 | !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${APPL_NAME}" 83 | !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" 84 | !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${APPL_NAME}" 85 | !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start_Menu_Folder" 86 | 87 | ;Set installer icon 88 | !define MUI_ICON yellow32.ico 89 | !define MUI_UNICON yellow32.ico 90 | 91 | ;-------------------------------- 92 | ;Variables 93 | 94 | Var StartMenuFolder 95 | 96 | ;-------------------------------- 97 | ;Pages 98 | 99 | !insertmacro MUI_PAGE_WELCOME 100 | !insertmacro MUI_PAGE_LICENSE "${BASEDIR}\license.txt" 101 | !insertmacro MUI_PAGE_DIRECTORY 102 | !insertmacro MUI_PAGE_COMPONENTS 103 | !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder 104 | !insertmacro MUI_PAGE_INSTFILES 105 | !define MUI_FINISHPAGE_RUN "$INSTDIR\BalloonRss.exe" 106 | !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" 107 | !insertmacro MUI_PAGE_FINISH 108 | 109 | !insertmacro MUI_UNPAGE_CONFIRM 110 | !insertmacro MUI_UNPAGE_COMPONENTS 111 | !insertmacro MUI_UNPAGE_INSTFILES 112 | 113 | 114 | ;-------------------------------- 115 | ;Languages 116 | 117 | !insertmacro MUI_LANGUAGE "English" 118 | 119 | 120 | ;-------------------------------- 121 | ;Installer Sections 122 | 123 | Section "General" SecGeneral 124 | 125 | SectionIn RO 126 | 127 | ; Kill application if it already runs 128 | !insertmacro CheckAppRunning "BalloonRss.exe" 129 | 130 | ; Set output path to the installation directory. 131 | SetOutPath "$INSTDIR" 132 | 133 | File "${BASEDIR}\bin\BalloonRss.exe" 134 | File "${BASEDIR}\README.txt" 135 | File "${BASEDIR}\help\balloonrss.chm" 136 | 137 | ;Create shortcuts 138 | !insertmacro MUI_STARTMENU_WRITE_BEGIN Application 139 | CreateDirectory "$SMPROGRAMS\$StartMenuFolder" 140 | CreateShortCut "$SMPROGRAMS\$StartMenuFolder\${APPL_NAME}.lnk" "$INSTDIR\BalloonRss.exe" 141 | !insertmacro MUI_STARTMENU_WRITE_END 142 | 143 | ;Store installation folder 144 | WriteRegStr HKLM "Software\${APPL_NAME}" "Install_Dir" $INSTDIR 145 | 146 | ; Write the uninstall keys for Windows 147 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "DisplayName" "${APPL_NAME}" 148 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "UninstallString" '"$INSTDIR\uninstall.exe"' 149 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "NoModify" 1 150 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "NoRepair" 1 151 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "Publisher" "${PRODUCT_PUBLISHER}" 152 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "URLInfoAbout" "${PRODUCT_PUBLISHER_WEB_SITE}" 153 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "DisplayVersion" "${APPL_VERSION}" 154 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "HelpLink" "${PRODUCT_WEB_SITE}" 155 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" "URLUpdateInfo" "${PRODUCT_DOWNLOAD_SITE}" 156 | ;also available: ReadMe, Comments 157 | 158 | ; Create uninstaller 159 | WriteUninstaller "uninstall.exe" 160 | 161 | SectionEnd 162 | 163 | 164 | ;-------------------------------- 165 | ; Optional section (can be disabled by the user) 166 | 167 | Section "Language Files" SecLanguage 168 | File /r /x .svn "${BASEDIR}\bin\de" 169 | File /r /x .svn "${BASEDIR}\bin\pt" 170 | SectionEnd 171 | 172 | Section "Source Code" SecSource 173 | File "${BASEDIR}\license.txt" 174 | File "${BASEDIR}\balloonRss.sln" 175 | File /r /x obj /x .svn /x BalloonRss.csproj.user "${BASEDIR}\src" 176 | SectionEnd 177 | 178 | Section "Autostart Program" SecAutostart 179 | CreateShortCut "$SMSTARTUP\${APPL_NAME}.lnk" "$INSTDIR\BalloonRss.exe" "" "$INSTDIR\BalloonRss.exe" 0 180 | SectionEnd 181 | 182 | 183 | ;-------------------------------- 184 | ;Uninstaller Sections 185 | 186 | Section "un.General" SecUnGeneral 187 | 188 | ; Kill application if it already runs 189 | !insertmacro CheckAppRunning "BalloonRss.exe" 190 | 191 | ; Remove files and uninstaller 192 | Delete /REBOOTOK "$INSTDIR\BalloonRss.exe" 193 | RMDir /r "$INSTDIR" 194 | 195 | ; Remove shortcuts, if any 196 | !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder 197 | Delete "$SMPROGRAMS\$StartMenuFolder\${APPL_NAME}.lnk" 198 | RMDir "$SMPROGRAMS\$StartMenuFolder" ; this will just remove the dir if it is emty 199 | Delete "$SMSTARTUP\${APPL_NAME}.lnk" 200 | 201 | ; Remove registry keys 202 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPL_NAME}" 203 | DeleteRegKey HKLM "SOFTWARE\${APPL_NAME}" 204 | DeleteRegKey HKCU "Software\${APPL_NAME}" 205 | 206 | SectionEnd 207 | 208 | 209 | Section "un.Data" SecUnData 210 | RMDir /r "$APPDATA\${APPL_NAME}" 211 | SectionEnd 212 | 213 | 214 | ;-------------------------------- 215 | ;Descriptions 216 | 217 | ; Language strings 218 | LangString DESC_SecGeneral ${LANG_ENGLISH} "Installs the required application files." 219 | LangString DESC_SecDotNet ${LANG_ENGLISH} "Installs the Microsoft .NET framework, which is required for this application. This will be skipped if the .NET framework is already present." 220 | LangString DESC_SecLanguage ${LANG_ENGLISH} "Installs language files for German and Portuguese." 221 | LangString DESC_SecSource ${LANG_ENGLISH} "Installs the source code." 222 | LangString DESC_SecAutostart ${LANG_ENGLISH} "Launch ${APPL_NAME} on start-up." 223 | 224 | LangString DESC_SecUnGeneral ${LANG_ENGLISH} "Uninstalls the application." 225 | LangString DESC_SecUnData ${LANG_ENGLISH} "Removes application specific settings and data." 226 | 227 | 228 | ;Assign language strings to sections 229 | !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN 230 | !insertmacro MUI_DESCRIPTION_TEXT ${SecGeneral} $(DESC_SecGeneral) 231 | !insertmacro MUI_DESCRIPTION_TEXT ${SecDotNet} $(DESC_SecDotNet) 232 | !insertmacro MUI_DESCRIPTION_TEXT ${SecLanguage} $(DESC_SecLanguage) 233 | !insertmacro MUI_DESCRIPTION_TEXT ${SecSource} $(DESC_SecSource) 234 | !insertmacro MUI_DESCRIPTION_TEXT ${SecAutostart} $(DESC_SecAutostart) 235 | !insertmacro MUI_FUNCTION_DESCRIPTION_END 236 | 237 | !insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN 238 | !insertmacro MUI_DESCRIPTION_TEXT ${SecUnGeneral} $(DESC_SecUnGeneral) 239 | !insertmacro MUI_DESCRIPTION_TEXT ${SecUnData} $(DESC_SecUnData) 240 | !insertmacro MUI_UNFUNCTION_DESCRIPTION_END 241 | -------------------------------------------------------------------------------- /src/FormChannelSettingsEdit.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2009 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Windows.Forms; 21 | using BalloonRss.Properties; 22 | 23 | 24 | namespace BalloonRss 25 | { 26 | class FormChannelSettingsEdit : Form 27 | { 28 | // GUI elements 29 | private Label fillLabel; 30 | private Control cntlUrl; 31 | private Control cntlPriority; 32 | private Control cntlMarkAsRead; 33 | 34 | // class data 35 | private ChannelInfo channelInfo; 36 | 37 | 38 | public FormChannelSettingsEdit(ChannelInfo channelInfo, bool newChannel) 39 | { 40 | this.channelInfo = channelInfo; 41 | 42 | // create panel 43 | InitializeComponent(newChannel); 44 | } 45 | 46 | 47 | private void InitializeComponent(bool newChannel) 48 | { 49 | this.SuspendLayout(); 50 | 51 | // the main container panel 52 | FlowLayoutPanel flPanelMain = new FlowLayoutPanel(); 53 | flPanelMain.FlowDirection = FlowDirection.TopDown; 54 | flPanelMain.AutoSize = true; 55 | //flPanelMain.Dock = DockStyle.Fill; 56 | flPanelMain.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; 57 | 58 | // setting controls 59 | Panel panel; 60 | int maxXSize = 0; 61 | cntlUrl = CreateSettingControl(channelInfo.link, Resources.str_channelSettingsHeaderTitle, out panel); 62 | maxXSize = Math.Max(maxXSize, panel.Width); 63 | flPanelMain.Controls.Add(panel); 64 | cntlPriority = CreateSettingControl(channelInfo.priority, Resources.str_channelSettingsHeaderPriority, out panel, 0, Byte.MaxValue); 65 | maxXSize = Math.Max(maxXSize, panel.Width); 66 | flPanelMain.Controls.Add(panel); 67 | cntlMarkAsRead = CreateSettingControl(channelInfo.markAsReadAtStartup, Resources.str_channelSettingsHeaderMarkAsRead, out panel); 68 | maxXSize = Math.Max(maxXSize, panel.Width); 69 | flPanelMain.Controls.Add(panel); 70 | 71 | // OK/Cancel button panel 72 | FlowLayoutPanel flPanel = new FlowLayoutPanel(); 73 | flPanel.FlowDirection = FlowDirection.LeftToRight; 74 | Button okButton = new Button(); 75 | okButton.Text = Resources.str_settingsFormOKButton; 76 | okButton.Click += new EventHandler(this.OnOK); 77 | this.AcceptButton = okButton; 78 | flPanel.Controls.Add(okButton); 79 | Button cancelButton = new Button(); 80 | cancelButton.Text = Resources.str_settingsFormCancelButton; 81 | cancelButton.Click += new EventHandler(this.OnCancel); 82 | this.CancelButton = cancelButton; 83 | flPanel.Controls.Add(cancelButton); 84 | flPanel.AutoSize = true; 85 | flPanel.Anchor = AnchorStyles.Right; 86 | flPanelMain.Controls.Add(flPanel); 87 | 88 | // add a dummy element to resize the settings to full horizontal scale 89 | fillLabel = new Label(); 90 | fillLabel.Size = new System.Drawing.Size(maxXSize, 0); 91 | flPanelMain.Controls.Add(fillLabel); 92 | 93 | // dialog settings 94 | if (newChannel) 95 | this.Text = Resources.str_channelSettingsNewFormTitle; 96 | else 97 | this.Text = Resources.str_channelSettingsEditFormTitle; 98 | this.MinimizeBox = false; 99 | this.MaximizeBox = false; 100 | this.Icon = Resources.ico_yellow32; 101 | this.Controls.Add(flPanelMain); 102 | this.Resize += new EventHandler(this.OnResize); 103 | this.HelpButton = true; 104 | this.HelpRequested += new HelpEventHandler(FormChannelSettingsEdit_HelpRequested); 105 | 106 | this.ResumeLayout(); 107 | 108 | // now, we can resize it 109 | this.ClientSize = new System.Drawing.Size(maxXSize, flPanelMain.Height); 110 | this.MinimumSize = this.Size; 111 | } 112 | 113 | void FormChannelSettingsEdit_HelpRequested(object sender, HelpEventArgs hlpevent) 114 | { 115 | Help.ShowHelp(this, Settings.Default.helpFilename, HelpNavigator.Topic, Settings.Default.helpNameChannelSettingsEdit); 116 | } 117 | 118 | 119 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel) 120 | { 121 | return CreateSettingControl(settingsObject, labelText, out panel, 0, 0); 122 | } 123 | 124 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel, int minValue, int maxValue) 125 | { 126 | // create the label 127 | Label label = new Label(); 128 | label.Text = labelText + ":"; 129 | label.Anchor = System.Windows.Forms.AnchorStyles.Left; 130 | label.Size = new System.Drawing.Size( 131 | TextRenderer.MeasureText(label.Text, label.Font).Width, 132 | TextRenderer.MeasureText(label.Text, label.Font).Height); 133 | 134 | // create the settings control 135 | Control control; 136 | if ( (settingsObject.GetType() == typeof(int)) || (settingsObject.GetType() == typeof(byte)) ) 137 | { 138 | control = new NumericTextBox(minValue, maxValue, labelText); 139 | control.Width = TextRenderer.MeasureText(maxValue.ToString(), control.Font).Width; 140 | control.Text = "" + settingsObject; 141 | } 142 | else if (settingsObject.GetType() == typeof(String)) 143 | { 144 | control = new TextBox(); 145 | control.Text = "" + settingsObject; 146 | control.Width = Math.Max( 147 | TextRenderer.MeasureText(control.Text, control.Font).Width, 148 | TextRenderer.MeasureText(Settings.Default.channelSettingsLinkTextfieldSize, control.Font).Width); 149 | (control as TextBox).TextAlign = HorizontalAlignment.Left; 150 | } 151 | else if (settingsObject.GetType() == typeof(bool)) 152 | { 153 | control = new CheckBox(); 154 | ((CheckBox)control).Checked = (bool)settingsObject; 155 | } 156 | else 157 | throw new Exception("Internal error: Illegal settings data type"); 158 | 159 | //control.Anchor = AnchorStyles.Right; 160 | control.Dock = DockStyle.Right; 161 | control.AutoSize = true; 162 | 163 | // create the panel 164 | panel = new Panel(); 165 | label.Location = new System.Drawing.Point(0, Math.Max((control.Height - label.Height) / 2, 0)); 166 | panel.Size = new System.Drawing.Size(label.Width + control.Width + 5, Math.Max(label.Height, control.Height)); 167 | panel.Anchor = AnchorStyles.Left | AnchorStyles.Right; 168 | panel.Controls.Add(label); 169 | panel.Controls.Add(control); 170 | 171 | return control; 172 | } 173 | 174 | 175 | private bool CheckData(out String errorMessage) 176 | { 177 | errorMessage = null; 178 | 179 | // check link format 180 | if (!ChannelInfo.IsValidLink(cntlUrl.Text)) 181 | { 182 | errorMessage = Resources.str_channelSettingsIllegalLink + cntlUrl.Text; 183 | return false; 184 | } 185 | 186 | // check data ranges 187 | if (!(cntlPriority as NumericTextBox).IsValueValid()) 188 | { 189 | errorMessage = (cntlPriority as NumericTextBox).GetErrorMessage(); 190 | return false; 191 | } 192 | 193 | return true; 194 | } 195 | 196 | 197 | private void GetData() 198 | { 199 | // store the data in the associated channel info 200 | // the data were already checked for validy before 201 | channelInfo.link = cntlUrl.Text; 202 | 203 | // do not use "feed://" prefix 204 | if (channelInfo.link.StartsWith("feed://")) 205 | { 206 | channelInfo.link = "http://" + channelInfo.link.Substring(7); 207 | } 208 | 209 | channelInfo.priority = (byte)(cntlPriority as NumericTextBox).IntValue; 210 | channelInfo.markAsReadAtStartup = (cntlMarkAsRead as CheckBox).Checked; 211 | } 212 | 213 | 214 | private void OnResize(object sender, EventArgs e) 215 | { 216 | fillLabel.Size = new System.Drawing.Size(this.ClientSize.Width-5, 0); 217 | } 218 | 219 | private void OnOK(object sender, EventArgs e) 220 | { 221 | String errorMessage; 222 | 223 | // close window 224 | if (CheckData(out errorMessage) == false) 225 | { 226 | MessageBox.Show( 227 | errorMessage, 228 | Resources.str_settingsFormErrorHeader, 229 | MessageBoxButtons.OK, 230 | MessageBoxIcon.Error); 231 | } 232 | else 233 | { 234 | GetData(); 235 | this.DialogResult = DialogResult.OK; 236 | Dispose(); 237 | } 238 | } 239 | 240 | private void OnCancel(object sender, EventArgs e) 241 | { 242 | // close window 243 | this.DialogResult = DialogResult.Cancel; 244 | Dispose(); 245 | } 246 | } 247 | } -------------------------------------------------------------------------------- /src/AboutBox.Designer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2010 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | namespace BalloonRss 20 | { 21 | partial class AboutBox 22 | { 23 | ///

24 | /// Required designer variable. 25 | /// 26 | private System.ComponentModel.IContainer components = null; 27 | 28 | /// 29 | /// Clean up any resources being used. 30 | /// 31 | protected override void Dispose(bool disposing) 32 | { 33 | if (disposing && (components != null)) 34 | { 35 | components.Dispose(); 36 | } 37 | base.Dispose(disposing); 38 | } 39 | 40 | #region Windows Form Designer generated code 41 | 42 | /// 43 | /// Required method for Designer support - do not modify 44 | /// the contents of this method with the code editor. 45 | /// 46 | private void InitializeComponent() 47 | { 48 | this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); 49 | this.logoPictureBox = new System.Windows.Forms.PictureBox(); 50 | this.labelProductName = new System.Windows.Forms.Label(); 51 | this.labelCopyright = new System.Windows.Forms.Label(); 52 | this.okButton = new System.Windows.Forms.Button(); 53 | this.labelEmail = new System.Windows.Forms.Label(); 54 | this.linkLabel1 = new System.Windows.Forms.LinkLabel(); 55 | this.tableLayoutPanel.SuspendLayout(); 56 | ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); 57 | this.SuspendLayout(); 58 | // 59 | // tableLayoutPanel 60 | // 61 | this.tableLayoutPanel.ColumnCount = 2; 62 | this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120F)); 63 | this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); 64 | this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); 65 | this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); 66 | this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 1); 67 | this.tableLayoutPanel.Controls.Add(this.okButton, 1, 4); 68 | this.tableLayoutPanel.Controls.Add(this.labelEmail, 1, 2); 69 | this.tableLayoutPanel.Controls.Add(this.linkLabel1, 1, 3); 70 | this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; 71 | this.tableLayoutPanel.Location = new System.Drawing.Point(12, 11); 72 | this.tableLayoutPanel.Margin = new System.Windows.Forms.Padding(4); 73 | this.tableLayoutPanel.Name = "tableLayoutPanel"; 74 | this.tableLayoutPanel.RowCount = 5; 75 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); 76 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); 77 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); 78 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); 79 | this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 31F)); 80 | this.tableLayoutPanel.Size = new System.Drawing.Size(403, 142); 81 | this.tableLayoutPanel.TabIndex = 0; 82 | // 83 | // logoPictureBox 84 | // 85 | this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; 86 | this.logoPictureBox.Image = global::BalloonRss.Properties.Resources.rss; 87 | this.logoPictureBox.Location = new System.Drawing.Point(0, 0); 88 | this.logoPictureBox.Margin = new System.Windows.Forms.Padding(0, 0, 13, 0); 89 | this.logoPictureBox.Name = "logoPictureBox"; 90 | this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 4); 91 | this.logoPictureBox.Size = new System.Drawing.Size(107, 108); 92 | this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; 93 | this.logoPictureBox.TabIndex = 12; 94 | this.logoPictureBox.TabStop = false; 95 | // 96 | // labelProductName 97 | // 98 | this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; 99 | this.labelProductName.Location = new System.Drawing.Point(128, 0); 100 | this.labelProductName.Margin = new System.Windows.Forms.Padding(8, 0, 4, 0); 101 | this.labelProductName.MaximumSize = new System.Drawing.Size(0, 21); 102 | this.labelProductName.Name = "labelProductName"; 103 | this.labelProductName.Size = new System.Drawing.Size(271, 21); 104 | this.labelProductName.TabIndex = 19; 105 | this.labelProductName.Text = "BalloonRSS"; 106 | this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 107 | // 108 | // labelCopyright 109 | // 110 | this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; 111 | this.labelCopyright.Location = new System.Drawing.Point(128, 27); 112 | this.labelCopyright.Margin = new System.Windows.Forms.Padding(8, 0, 4, 0); 113 | this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 21); 114 | this.labelCopyright.Name = "labelCopyright"; 115 | this.labelCopyright.Size = new System.Drawing.Size(271, 21); 116 | this.labelCopyright.TabIndex = 21; 117 | this.labelCopyright.Text = "(C) 2009, Roman Morawek"; 118 | this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 119 | // 120 | // okButton 121 | // 122 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 123 | this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 124 | this.okButton.Location = new System.Drawing.Point(303, 115); 125 | this.okButton.Margin = new System.Windows.Forms.Padding(0); 126 | this.okButton.Name = "okButton"; 127 | this.okButton.Size = new System.Drawing.Size(100, 27); 128 | this.okButton.TabIndex = 24; 129 | this.okButton.Text = "&OK"; 130 | // 131 | // labelEmail 132 | // 133 | this.labelEmail.Dock = System.Windows.Forms.DockStyle.Fill; 134 | this.labelEmail.Location = new System.Drawing.Point(128, 54); 135 | this.labelEmail.Margin = new System.Windows.Forms.Padding(8, 0, 4, 0); 136 | this.labelEmail.MaximumSize = new System.Drawing.Size(0, 21); 137 | this.labelEmail.Name = "labelEmail"; 138 | this.labelEmail.Size = new System.Drawing.Size(271, 21); 139 | this.labelEmail.TabIndex = 25; 140 | this.labelEmail.Text = "balloonrss@embyt.com"; 141 | this.labelEmail.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 142 | // 143 | // linkLabel1 144 | // 145 | this.linkLabel1.AutoSize = true; 146 | this.linkLabel1.Dock = System.Windows.Forms.DockStyle.Fill; 147 | this.linkLabel1.Location = new System.Drawing.Point(128, 81); 148 | this.linkLabel1.Margin = new System.Windows.Forms.Padding(8, 0, 4, 0); 149 | this.linkLabel1.MaximumSize = new System.Drawing.Size(0, 21); 150 | this.linkLabel1.Name = "linkLabel1"; 151 | this.linkLabel1.Size = new System.Drawing.Size(271, 21); 152 | this.linkLabel1.TabIndex = 26; 153 | this.linkLabel1.TabStop = true; 154 | this.linkLabel1.Text = "https://embyt.github.io/balloonrss"; 155 | this.linkLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 156 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); 157 | // 158 | // AboutBox 159 | // 160 | this.AcceptButton = this.okButton; 161 | this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); 162 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 163 | this.CancelButton = this.okButton; 164 | this.ClientSize = new System.Drawing.Size(427, 164); 165 | this.Controls.Add(this.tableLayoutPanel); 166 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 167 | this.Margin = new System.Windows.Forms.Padding(4); 168 | this.MaximizeBox = false; 169 | this.MinimizeBox = false; 170 | this.Name = "AboutBox"; 171 | this.Padding = new System.Windows.Forms.Padding(12, 11, 12, 11); 172 | this.ShowIcon = false; 173 | this.ShowInTaskbar = false; 174 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 175 | this.Text = "AboutBox"; 176 | this.tableLayoutPanel.ResumeLayout(false); 177 | this.tableLayoutPanel.PerformLayout(); 178 | ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); 179 | this.ResumeLayout(false); 180 | 181 | } 182 | 183 | #endregion 184 | 185 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; 186 | private System.Windows.Forms.PictureBox logoPictureBox; 187 | private System.Windows.Forms.Label labelProductName; 188 | private System.Windows.Forms.Label labelCopyright; 189 | private System.Windows.Forms.Button okButton; 190 | private System.Windows.Forms.Label labelEmail; 191 | private System.Windows.Forms.LinkLabel linkLabel1; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BalloonRss.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("5")] 29 | public int displayIntervall { 30 | get { 31 | return ((int)(this["displayIntervall"])); 32 | } 33 | set { 34 | this["displayIntervall"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("30")] 41 | public int retrieveIntervall { 42 | get { 43 | return ((int)(this["retrieveIntervall"])); 44 | } 45 | set { 46 | this["retrieveIntervall"] = value; 47 | } 48 | } 49 | 50 | [global::System.Configuration.UserScopedSettingAttribute()] 51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 52 | [global::System.Configuration.DefaultSettingValueAttribute("10")] 53 | public int balloonTimespan { 54 | get { 55 | return ((int)(this["balloonTimespan"])); 56 | } 57 | set { 58 | this["balloonTimespan"] = value; 59 | } 60 | } 61 | 62 | [global::System.Configuration.UserScopedSettingAttribute()] 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 64 | [global::System.Configuration.DefaultSettingValueAttribute("15")] 65 | public int historyDepth { 66 | get { 67 | return ((int)(this["historyDepth"])); 68 | } 69 | set { 70 | this["historyDepth"] = value; 71 | } 72 | } 73 | 74 | [global::System.Configuration.UserScopedSettingAttribute()] 75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 76 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 77 | public bool channelAsTitle { 78 | get { 79 | return ((bool)(this["channelAsTitle"])); 80 | } 81 | set { 82 | this["channelAsTitle"] = value; 83 | } 84 | } 85 | 86 | [global::System.Configuration.UserScopedSettingAttribute()] 87 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 88 | [global::System.Configuration.DefaultSettingValueAttribute("5")] 89 | public byte clickInfluence { 90 | get { 91 | return ((byte)(this["clickInfluence"])); 92 | } 93 | set { 94 | this["clickInfluence"] = value; 95 | } 96 | } 97 | 98 | [global::System.Configuration.UserScopedSettingAttribute()] 99 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 100 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 101 | public bool checkForUpdates { 102 | get { 103 | return ((bool)(this["checkForUpdates"])); 104 | } 105 | set { 106 | this["checkForUpdates"] = value; 107 | } 108 | } 109 | 110 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 111 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 112 | [global::System.Configuration.DefaultSettingValueAttribute("100")] 113 | public int updateCheckIntervall { 114 | get { 115 | return ((int)(this["updateCheckIntervall"])); 116 | } 117 | } 118 | 119 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 120 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 121 | [global::System.Configuration.DefaultSettingValueAttribute("40")] 122 | public int updateDisplayIntervall { 123 | get { 124 | return ((int)(this["updateDisplayIntervall"])); 125 | } 126 | } 127 | 128 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 129 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 130 | [global::System.Configuration.DefaultSettingValueAttribute("http://balloonrss.sourceforge.net/checkforupdates.php?curVersion=")] 131 | public string updateCheckUrl { 132 | get { 133 | return ((string)(this["updateCheckUrl"])); 134 | } 135 | } 136 | 137 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 138 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 139 | [global::System.Configuration.DefaultSettingValueAttribute("channelConfig.xml")] 140 | public string configFilename { 141 | get { 142 | return ((string)(this["configFilename"])); 143 | } 144 | } 145 | 146 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 147 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 148 | [global::System.Configuration.DefaultSettingValueAttribute("####################################")] 149 | public string channelSettingsLinkTextfieldSize { 150 | get { 151 | return ((string)(this["channelSettingsLinkTextfieldSize"])); 152 | } 153 | } 154 | 155 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 156 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 157 | [global::System.Configuration.DefaultSettingValueAttribute("###########")] 158 | public string SettingsTextfieldSize { 159 | get { 160 | return ((string)(this["SettingsTextfieldSize"])); 161 | } 162 | } 163 | 164 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 165 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 166 | [global::System.Configuration.DefaultSettingValueAttribute("http://balloonrss.sourceforge.net/releaseinfo.html?curVersion=")] 167 | public string updateInfoUrl { 168 | get { 169 | return ((string)(this["updateInfoUrl"])); 170 | } 171 | } 172 | 173 | [global::System.Configuration.UserScopedSettingAttribute()] 174 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 175 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 176 | public bool startPaused { 177 | get { 178 | return ((bool)(this["startPaused"])); 179 | } 180 | set { 181 | this["startPaused"] = value; 182 | } 183 | } 184 | 185 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 186 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 187 | [global::System.Configuration.DefaultSettingValueAttribute("5")] 188 | public byte defaultChannelPriority { 189 | get { 190 | return ((byte)(this["defaultChannelPriority"])); 191 | } 192 | } 193 | 194 | [global::System.Configuration.UserScopedSettingAttribute()] 195 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 196 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 197 | public bool reportNetworkErrors { 198 | get { 199 | return ((bool)(this["reportNetworkErrors"])); 200 | } 201 | set { 202 | this["reportNetworkErrors"] = value; 203 | } 204 | } 205 | 206 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 207 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 208 | [global::System.Configuration.DefaultSettingValueAttribute("balloonrss.chm")] 209 | public string helpFilename { 210 | get { 211 | return ((string)(this["helpFilename"])); 212 | } 213 | } 214 | 215 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 216 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 217 | [global::System.Configuration.DefaultSettingValueAttribute("applicationSettings.html")] 218 | public string helpNameApplicationSettings { 219 | get { 220 | return ((string)(this["helpNameApplicationSettings"])); 221 | } 222 | } 223 | 224 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 225 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 226 | [global::System.Configuration.DefaultSettingValueAttribute("channelInformation.html")] 227 | public string helpNameChannelInfo { 228 | get { 229 | return ((string)(this["helpNameChannelInfo"])); 230 | } 231 | } 232 | 233 | [global::System.Configuration.UserScopedSettingAttribute()] 234 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 235 | [global::System.Configuration.DefaultSettingValueAttribute("channelSettings.html")] 236 | public string helpNameChannelSettings { 237 | get { 238 | return ((string)(this["helpNameChannelSettings"])); 239 | } 240 | set { 241 | this["helpNameChannelSettings"] = value; 242 | } 243 | } 244 | 245 | [global::System.Configuration.UserScopedSettingAttribute()] 246 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 247 | [global::System.Configuration.DefaultSettingValueAttribute("channelSettings.html#channel_edit")] 248 | public string helpNameChannelSettingsEdit { 249 | get { 250 | return ((string)(this["helpNameChannelSettingsEdit"])); 251 | } 252 | set { 253 | this["helpNameChannelSettingsEdit"] = value; 254 | } 255 | } 256 | 257 | [global::System.Configuration.UserScopedSettingAttribute()] 258 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 259 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 260 | public int doubleClickAction { 261 | get { 262 | return ((int)(this["doubleClickAction"])); 263 | } 264 | set { 265 | this["doubleClickAction"] = value; 266 | } 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/FormSettings.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2009 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Windows.Forms; 21 | using BalloonRss.Properties; 22 | 23 | 24 | namespace BalloonRss 25 | { 26 | class FormSettings : Form 27 | { 28 | private Label fillLabel; 29 | private Control cntlDisplayIntervall; 30 | private Control cntlRetrieveIntervall; 31 | private Control cntlBalloonTimespan; 32 | private Control cntlChannelAsTitle; 33 | private Control cntlHistoryDepth; 34 | private Control cntlClickInfluence; 35 | private Control cntlCheckForUpdates; 36 | private Control cntlStartPaused; 37 | private Control cntlReportNetworkErrors; 38 | private Control cntlDoubleClickAction; 39 | 40 | 41 | public FormSettings() 42 | { 43 | // create panel 44 | InitializeComponent(); 45 | } 46 | 47 | 48 | private void InitializeComponent() 49 | { 50 | Panel panel; 51 | Button button; 52 | 53 | this.SuspendLayout(); 54 | 55 | // the main container panel 56 | FlowLayoutPanel flPanelMain = new FlowLayoutPanel(); 57 | flPanelMain.FlowDirection = FlowDirection.TopDown; 58 | flPanelMain.AutoSize = true; 59 | flPanelMain.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; 60 | 61 | // setting 62 | int maxXSize = 0; 63 | cntlDisplayIntervall = CreateSettingControl(Settings.Default.displayIntervall, Resources.str_settingsDisplayIntervall, out panel, 1, Int32.MaxValue); 64 | maxXSize = Math.Max(maxXSize, panel.Width); 65 | flPanelMain.Controls.Add(panel); 66 | cntlRetrieveIntervall = CreateSettingControl(Settings.Default.retrieveIntervall, Resources.str_settingsRetrieveIntervall, out panel, 5, Int32.MaxValue); 67 | maxXSize = Math.Max(maxXSize, panel.Width); 68 | flPanelMain.Controls.Add(panel); 69 | cntlBalloonTimespan = CreateSettingControl(Settings.Default.balloonTimespan, Resources.str_settingsBalloonTimespan, out panel, 10, Int32.MaxValue); 70 | maxXSize = Math.Max(maxXSize, panel.Width); 71 | flPanelMain.Controls.Add(panel); 72 | cntlStartPaused = CreateSettingControl(Settings.Default.startPaused, Resources.str_settingsStartPaused, out panel); 73 | maxXSize = Math.Max(maxXSize, panel.Width); 74 | flPanelMain.Controls.Add(panel); 75 | cntlChannelAsTitle = CreateSettingControl(Settings.Default.channelAsTitle, Resources.str_settingsChannelAsTitle, out panel); 76 | maxXSize = Math.Max(maxXSize, panel.Width); 77 | flPanelMain.Controls.Add(panel); 78 | cntlHistoryDepth = CreateSettingControl(Settings.Default.historyDepth, Resources.str_settingsHistoryDepth, out panel, 0, Int32.MaxValue); 79 | maxXSize = Math.Max(maxXSize, panel.Width); 80 | flPanelMain.Controls.Add(panel); 81 | cntlClickInfluence = CreateSettingControl(Settings.Default.clickInfluence, Resources.str_settingsClickInfluence, out panel, 0, 10); 82 | maxXSize = Math.Max(maxXSize, panel.Width); 83 | flPanelMain.Controls.Add(panel); 84 | cntlCheckForUpdates = CreateSettingControl(Settings.Default.checkForUpdates, Resources.str_settingsCheckForUpdates, out panel); 85 | maxXSize = Math.Max(maxXSize, panel.Width); 86 | flPanelMain.Controls.Add(panel); 87 | cntlReportNetworkErrors = CreateSettingControl(Settings.Default.reportNetworkErrors, Resources.str_settingsReportNetworkErrors, out panel); 88 | maxXSize = Math.Max(maxXSize, panel.Width); 89 | flPanelMain.Controls.Add(panel); 90 | String[] settingsList = new String[] { Resources.str_settingsDoubleClickActionOption0, Resources.str_settingsDoubleClickActionOption1, Resources.str_settingsDoubleClickActionOption2 }; 91 | cntlDoubleClickAction = CreateSettingControl(Settings.Default.doubleClickAction, Resources.str_settingsDoubleClickAction, out panel, settingsList); 92 | maxXSize = Math.Max(maxXSize, panel.Width); 93 | flPanelMain.Controls.Add(panel); 94 | 95 | // OK/Cancel button panel 96 | FlowLayoutPanel flPanel = new FlowLayoutPanel(); 97 | flPanel.FlowDirection = FlowDirection.LeftToRight; 98 | button = new Button(); 99 | button.Text = Resources.str_settingsFormOKButton; 100 | button.Click += new EventHandler(this.OnOK); 101 | this.AcceptButton = button; 102 | flPanel.Controls.Add(button); 103 | button = new Button(); 104 | button.Text = Resources.str_settingsFormCancelButton; 105 | button.Click += new EventHandler(this.OnCancel); 106 | this.CancelButton = button; 107 | flPanel.Controls.Add(button); 108 | flPanel.AutoSize = true; 109 | flPanel.Anchor = AnchorStyles.Right; 110 | flPanelMain.Controls.Add(flPanel); 111 | 112 | // add a dummy element to resize the settings to full horizontal scale 113 | fillLabel = new Label(); 114 | fillLabel.Size = new System.Drawing.Size(maxXSize, 0); 115 | flPanelMain.Controls.Add(fillLabel); 116 | 117 | // dialog settings 118 | this.MinimizeBox = false; 119 | this.MaximizeBox = false; 120 | this.Text = Resources.str_settingsFormTitle; 121 | this.Icon = Resources.ico_yellow32; 122 | this.Controls.Add(flPanelMain); 123 | this.Resize += new EventHandler(this.OnResize); 124 | this.HelpButton = true; 125 | this.HelpRequested += new HelpEventHandler(FormSettings_HelpRequested); 126 | 127 | this.ResumeLayout(); 128 | 129 | // now, we can resize it 130 | this.ClientSize = new System.Drawing.Size(maxXSize, flPanelMain.Height); 131 | this.MinimumSize = this.Size; 132 | } 133 | 134 | void FormSettings_HelpRequested(object sender, HelpEventArgs hlpevent) 135 | { 136 | Help.ShowHelp(this, Settings.Default.helpFilename, HelpNavigator.Topic, Settings.Default.helpNameApplicationSettings); 137 | } 138 | 139 | 140 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel) 141 | { 142 | return CreateSettingControl(settingsObject, labelText, out panel, 0, 0, null); 143 | } 144 | 145 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel, int minValue, int maxValue) 146 | { 147 | return CreateSettingControl(settingsObject, labelText, out panel, minValue, maxValue, null); 148 | } 149 | 150 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel, string[] optionValues) 151 | { 152 | return CreateSettingControl(settingsObject, labelText, out panel, 0, 0, optionValues); 153 | } 154 | 155 | private Control CreateSettingControl(Object settingsObject, String labelText, out Panel panel, int minValue, int maxValue, string[] optionValues) 156 | { 157 | // create the label 158 | Label label = new Label(); 159 | label.Text = labelText + ":"; 160 | label.Anchor = AnchorStyles.Left; 161 | label.Size = new System.Drawing.Size( 162 | TextRenderer.MeasureText(label.Text, label.Font).Width, 163 | TextRenderer.MeasureText(label.Text, label.Font).Height); 164 | 165 | // create the settings control 166 | Control control; 167 | if (optionValues != null) 168 | { 169 | // we face a list box 170 | control = new ComboBox(); 171 | (control as ComboBox).Items.AddRange(optionValues); 172 | (control as ComboBox).SelectedIndex = (int)settingsObject; 173 | (control as ComboBox).DropDownStyle = ComboBoxStyle.DropDownList; 174 | // measure largest text 175 | int maxWidth = 0; 176 | foreach (string option in optionValues) 177 | maxWidth = Math.Max(maxWidth, TextRenderer.MeasureText(option, control.Font).Width); 178 | control.Width = maxWidth+20; 179 | } 180 | else if (settingsObject.GetType() == typeof(int)) 181 | { 182 | control = new NumericTextBox(minValue, maxValue, labelText); 183 | control.Width = TextRenderer.MeasureText(maxValue.ToString(), control.Font).Width; 184 | control.Text = "" + settingsObject; 185 | } 186 | else if (settingsObject.GetType() == typeof(String)) 187 | { 188 | control = new TextBox(); 189 | control.Text = "" + settingsObject; 190 | control.Width = Math.Max( 191 | TextRenderer.MeasureText(control.Text, control.Font).Width, 192 | TextRenderer.MeasureText(Settings.Default.SettingsTextfieldSize, control.Font).Width); 193 | (control as TextBox).TextAlign = HorizontalAlignment.Right; 194 | } 195 | else if (settingsObject.GetType() == typeof(bool)) 196 | { 197 | control = new CheckBox(); 198 | ((CheckBox)control).Checked = (bool)settingsObject; 199 | } 200 | else if (settingsObject.GetType() == typeof(byte)) 201 | { 202 | control = new TrackBar(); 203 | ((TrackBar)control).Minimum = minValue; 204 | ((TrackBar)control).Maximum = maxValue; 205 | ((TrackBar)control).Value = (byte)settingsObject; 206 | } 207 | else 208 | throw new Exception("Internal error: Illegal settings data type"); 209 | 210 | control.Dock = DockStyle.Right; 211 | control.AutoSize = true; 212 | 213 | // create the panel 214 | panel = new Panel(); 215 | label.Location = new System.Drawing.Point(0, Math.Max((control.Height - label.Height) / 2, 0)); 216 | panel.Size = new System.Drawing.Size(label.Width + control.Width + 5, Math.Max(label.Height, control.Height)); 217 | panel.Anchor = AnchorStyles.Left | AnchorStyles.Right; 218 | panel.Controls.Add(label); 219 | panel.Controls.Add(control); 220 | 221 | return control; 222 | } 223 | 224 | 225 | private bool CheckData(out String errorMessage) 226 | { 227 | errorMessage = null; 228 | 229 | // check data ranges 230 | if (!(cntlBalloonTimespan as NumericTextBox).IsValueValid()) 231 | { 232 | errorMessage = (cntlBalloonTimespan as NumericTextBox).GetErrorMessage(); 233 | return false; 234 | } 235 | if (!(cntlDisplayIntervall as NumericTextBox).IsValueValid()) 236 | { 237 | errorMessage = (cntlDisplayIntervall as NumericTextBox).GetErrorMessage(); 238 | return false; 239 | } 240 | if (!(cntlHistoryDepth as NumericTextBox).IsValueValid()) 241 | { 242 | errorMessage = (cntlHistoryDepth as NumericTextBox).GetErrorMessage(); 243 | return false; 244 | } 245 | if (!(cntlRetrieveIntervall as NumericTextBox).IsValueValid()) 246 | { 247 | errorMessage = (cntlRetrieveIntervall as NumericTextBox).GetErrorMessage(); 248 | return false; 249 | } 250 | // no check for cntlConfigFilename and boolean variables 251 | 252 | // interdependencies 253 | if ( (cntlRetrieveIntervall as NumericTextBox).IntValue <= (cntlDisplayIntervall as NumericTextBox).IntValue) 254 | { 255 | errorMessage = Resources.str_settingsErrorRetrieveSmallerDisplay; 256 | return false; 257 | } 258 | 259 | return true; 260 | } 261 | 262 | 263 | private void GetData() 264 | { 265 | // get data 266 | Settings.Default.balloonTimespan = (cntlBalloonTimespan as NumericTextBox).IntValue; 267 | Settings.Default.channelAsTitle = (cntlChannelAsTitle as CheckBox).Checked; 268 | Settings.Default.displayIntervall = (cntlDisplayIntervall as NumericTextBox).IntValue; 269 | Settings.Default.historyDepth = (cntlHistoryDepth as NumericTextBox).IntValue; 270 | Settings.Default.retrieveIntervall = (cntlRetrieveIntervall as NumericTextBox).IntValue; 271 | Settings.Default.clickInfluence = (byte)(cntlClickInfluence as TrackBar).Value; 272 | Settings.Default.checkForUpdates = (cntlCheckForUpdates as CheckBox).Checked; 273 | Settings.Default.startPaused = (cntlStartPaused as CheckBox).Checked; 274 | Settings.Default.reportNetworkErrors = (cntlReportNetworkErrors as CheckBox).Checked; 275 | Settings.Default.doubleClickAction = (cntlDoubleClickAction as ComboBox).SelectedIndex; 276 | } 277 | 278 | 279 | private void OnResize(object sender, EventArgs e) 280 | { 281 | fillLabel.Size = new System.Drawing.Size(this.ClientSize.Width-5, 0); 282 | } 283 | 284 | private void OnOK(object sender, EventArgs e) 285 | { 286 | String errorMessage; 287 | 288 | // close window 289 | if (CheckData(out errorMessage) == false) 290 | { 291 | MessageBox.Show( 292 | errorMessage, 293 | Resources.str_settingsFormErrorHeader, 294 | MessageBoxButtons.OK, 295 | MessageBoxIcon.Error); 296 | } 297 | else 298 | { 299 | // transfer data from GUI into settings block 300 | GetData(); 301 | // save the settings file 302 | Settings.Default.Save(); 303 | // close window 304 | this.DialogResult = DialogResult.OK; 305 | Dispose(); 306 | } 307 | } 308 | 309 | private void OnCancel(object sender, EventArgs e) 310 | { 311 | // close window 312 | this.DialogResult = DialogResult.Cancel; 313 | Dispose(); 314 | } 315 | } 316 | } -------------------------------------------------------------------------------- /src/FormChannelSettings.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BalloonRSS - Simple RSS news aggregator using balloon tooltips 3 | Copyright (C) 2009 Roman Morawek 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | using System; 20 | using System.Windows.Forms; 21 | using BalloonRss.Properties; 22 | 23 | using System.Drawing; 24 | using System.Reflection; 25 | using System.IO; 26 | 27 | 28 | namespace BalloonRss 29 | { 30 | class FormChannelSettings : Form 31 | { 32 | private const int panelWidth = 480; 33 | private const int panelHeight = 145; 34 | private const int splitterBorder = 10; 35 | 36 | // GUI elements 37 | private ListView listView; 38 | private Button editButton; 39 | private Button deleteButton; 40 | 41 | // other class data 42 | private ChannelList channelList; 43 | 44 | 45 | public FormChannelSettings(String rssLink) 46 | { 47 | // initialise with current channel settings 48 | bool firstRun; 49 | channelList = new ChannelList(out firstRun); 50 | 51 | // setup GUI 52 | this.SuspendLayout(); 53 | InitializeComponent(); 54 | FillChannelList(); 55 | this.ResumeLayout(); 56 | 57 | if (rssLink != null) 58 | OnNew(rssLink, null); 59 | } 60 | 61 | 62 | private void InitializeComponent() 63 | { 64 | // list control 65 | this.listView = new ListView(); 66 | this.listView.Dock = DockStyle.Fill; 67 | this.listView.UseCompatibleStateImageBehavior = false; 68 | this.listView.View = View.Details; 69 | this.listView.AllowColumnReorder = true; 70 | this.listView.FullRowSelect = true; 71 | this.listView.DoubleClick += new EventHandler(OnEdit); 72 | this.listView.SelectedIndexChanged += new EventHandler(listView_SelectedIndexChanged); 73 | 74 | // button panel 75 | FlowLayoutPanel flPanel = new FlowLayoutPanel(); 76 | flPanel.FlowDirection = FlowDirection.TopDown; 77 | flPanel.Dock = DockStyle.Fill; 78 | // "new" button 79 | Button button = new Button(); 80 | button.Text = Resources.str_channelSettingsFormNewButton; 81 | button.Click += new EventHandler(this.OnNew); 82 | button.Anchor = AnchorStyles.Top; 83 | flPanel.Controls.Add(button); 84 | // "delete" button 85 | deleteButton = new Button(); 86 | deleteButton.Text = Resources.str_channelSettingsFormDeleteButton; 87 | deleteButton.Click += new EventHandler(this.OnDelete); 88 | deleteButton.Anchor = AnchorStyles.Top; 89 | deleteButton.Enabled = false; 90 | flPanel.Controls.Add(deleteButton); 91 | // "edit" button 92 | editButton = new Button(); 93 | editButton.Text = Resources.str_channelSettingsFormEditButton; 94 | editButton.Click += new EventHandler(this.OnEdit); 95 | editButton.Anchor = AnchorStyles.Top; 96 | editButton.Enabled = false; 97 | flPanel.Controls.Add(editButton); 98 | // "OK" button 99 | button = new Button(); 100 | button.Text = Resources.str_settingsFormOKButton; 101 | button.Click += new EventHandler(this.OnOK); 102 | this.AcceptButton = button; 103 | button.Anchor = AnchorStyles.Bottom; 104 | flPanel.Controls.Add(button); 105 | // "Cancel" button 106 | button = new Button(); 107 | button.Text = Resources.str_settingsFormCancelButton; 108 | button.Click += new EventHandler(this.OnCancel); 109 | this.CancelButton = button; 110 | button.Anchor = AnchorStyles.Bottom; 111 | flPanel.Controls.Add(button); 112 | 113 | // main split container 114 | SplitContainer mainContainer = new SplitContainer(); 115 | mainContainer.FixedPanel = FixedPanel.Panel2; 116 | mainContainer.Panel1.Controls.Add(listView); 117 | mainContainer.Panel2.Controls.Add(flPanel); 118 | mainContainer.Dock = DockStyle.Fill; 119 | mainContainer.IsSplitterFixed = true; 120 | mainContainer.SplitterDistance = mainContainer.Width - button.Width - splitterBorder; 121 | 122 | // 123 | // form settings 124 | // 125 | this.Controls.Add(mainContainer); 126 | this.ClientSize = new System.Drawing.Size(panelWidth, panelHeight); 127 | this.MinimizeBox = false; 128 | this.MaximizeBox = false; 129 | this.Text = Resources.str_channelSettingsFormTitle; 130 | this.Icon = Resources.ico_yellow32; 131 | this.HelpButton = true; 132 | this.HelpRequested += new HelpEventHandler(FormChannelSettings_HelpRequested); 133 | } 134 | 135 | void FormChannelSettings_HelpRequested(object sender, HelpEventArgs hlpevent) 136 | { 137 | Help.ShowHelp(this, Settings.Default.helpFilename, HelpNavigator.Topic, Settings.Default.helpNameChannelSettings); 138 | } 139 | 140 | 141 | private void FillChannelList() 142 | { 143 | // clear any old data 144 | listView.Clear(); 145 | 146 | // populate and set image list 147 | ImageList imageList = new ImageList(); 148 | imageList.Images.Add(Resources.img_unlocked); 149 | imageList.Images.Add(Resources.img_locked); 150 | listView.StateImageList = imageList; 151 | 152 | // check whether we have only non-global channels 153 | bool onlyUserChannels = true; 154 | foreach (ChannelInfo curChannel in channelList) 155 | { 156 | if (curChannel.globalChannel) 157 | onlyUserChannels = false; 158 | } 159 | 160 | // set the table headers 161 | // the locked image column has no header and is invisible if only user items exist 162 | listView.Columns.Add(null, onlyUserChannels ? 0 : -1, HorizontalAlignment.Left); 163 | listView.Columns.Add(Resources.str_historyHeaderId, 0, HorizontalAlignment.Left); // hide the ID column 164 | listView.Columns.Add(Resources.str_channelSettingsHeaderTitle, -2, HorizontalAlignment.Left); 165 | listView.Columns.Add(Resources.str_channelSettingsHeaderPriority, -2, HorizontalAlignment.Left); 166 | 167 | // create the list items 168 | ListViewItem[] listItems = new ListViewItem[channelList.Count]; 169 | for (int i = 0; i < listItems.Length; i++) 170 | { 171 | listItems[i] = new ListViewItem(); 172 | listItems[i].SubItems.Add(i.ToString()); 173 | listItems[i].SubItems.Add(channelList[i].link); 174 | listItems[i].SubItems.Add(channelList[i].priority.ToString()); 175 | listItems[i].StateImageIndex = Convert.ToInt16(channelList[i].globalChannel); 176 | } 177 | 178 | // fill the list 179 | listView.Items.AddRange(listItems); 180 | } 181 | 182 | 183 | void listView_SelectedIndexChanged(object sender, EventArgs e) 184 | { 185 | // get selected enty 186 | if (listView.SelectedItems.Count > 0) 187 | { 188 | foreach (ListViewItem curItem in listView.SelectedItems) 189 | { 190 | int selectedChannel = Int32.Parse(curItem.SubItems[1].Text); 191 | 192 | editButton.Enabled = !channelList[selectedChannel].globalChannel; 193 | deleteButton.Enabled = !channelList[selectedChannel].globalChannel; 194 | 195 | // we just use the first selection 196 | break; 197 | } 198 | } 199 | else 200 | { 201 | editButton.Enabled = false; 202 | deleteButton.Enabled = false; 203 | } 204 | } 205 | 206 | 207 | // open a child window to create a new channel 208 | private void OnNew(object sender, EventArgs e) 209 | { 210 | // create new enty 211 | ChannelInfo channelInfo = new ChannelInfo(); 212 | 213 | // set link if specified 214 | if (sender is String) 215 | channelInfo.link = sender as String; 216 | 217 | // diaplay edit box 218 | FormChannelSettingsEdit channelEdit = new FormChannelSettingsEdit(channelInfo, true); 219 | DialogResult dialogResult = channelEdit.ShowDialog(this); 220 | 221 | // if edit is confirmed, store the entry 222 | if (dialogResult == DialogResult.OK) 223 | { 224 | // check for duplicate channel 225 | if (channelList.IsNewChannel(channelInfo, null)) 226 | { 227 | // OK, let's add it 228 | channelList.Add(channelInfo); 229 | 230 | ListViewItem listItem = new ListViewItem(); 231 | listItem.SubItems.Add(listView.Items.Count.ToString()); 232 | listItem.SubItems.Add(channelInfo.link); 233 | listItem.SubItems.Add(channelInfo.priority.ToString()); 234 | listItem.StateImageIndex = Convert.ToInt16(channelInfo.globalChannel); 235 | listView.Items.Add(listItem); 236 | } 237 | else 238 | { 239 | MessageBox.Show( 240 | Resources.str_channelSettingsDuplicateLink, 241 | Resources.str_settingsFormErrorHeader, 242 | MessageBoxButtons.OK, 243 | MessageBoxIcon.Error); 244 | } 245 | } 246 | 247 | // we need to reselect an entry after this operation 248 | editButton.Enabled = false; 249 | deleteButton.Enabled = false; 250 | } 251 | 252 | // open child window to edit channel 253 | private void OnEdit(object sender, EventArgs e) 254 | { 255 | // get selected enty 256 | foreach (ListViewItem curItem in listView.SelectedItems) 257 | { 258 | int selectedChannel = Int32.Parse(curItem.SubItems[1].Text); 259 | 260 | // do not edit global items (this may happen at double click) 261 | if (channelList[selectedChannel].globalChannel) 262 | break; 263 | 264 | // diaplay edit box 265 | ChannelInfo channelInfo = new ChannelInfo(channelList[selectedChannel]); 266 | FormChannelSettingsEdit channelEdit = new FormChannelSettingsEdit(channelInfo, false); 267 | DialogResult dialogResult = channelEdit.ShowDialog(this); 268 | 269 | // update list view display in case of pressing OK 270 | if (dialogResult == DialogResult.OK) 271 | { 272 | // check for duplicate channel 273 | if (channelList.IsNewChannel(channelInfo, channelList[selectedChannel])) 274 | { 275 | // override the stored channel 276 | channelList[selectedChannel] = channelInfo; 277 | curItem.SubItems[2].Text = channelList[selectedChannel].link; 278 | curItem.SubItems[3].Text = channelList[selectedChannel].priority.ToString(); 279 | } 280 | else 281 | { 282 | MessageBox.Show( 283 | Resources.str_channelSettingsDuplicateLink, 284 | Resources.str_settingsFormErrorHeader, 285 | MessageBoxButtons.OK, 286 | MessageBoxIcon.Error); 287 | } 288 | } 289 | 290 | // we just edit the first selection and skip the remaining ones 291 | break; 292 | } 293 | 294 | // we need to reselect an entry after this operation 295 | editButton.Enabled = false; 296 | deleteButton.Enabled = false; 297 | } 298 | 299 | private void OnDelete(object sender, EventArgs e) 300 | { 301 | bool deleteConfirmed = false; 302 | 303 | // just delete the first selected entry 304 | foreach (ListViewItem curItem in listView.SelectedItems) 305 | { 306 | int selectedChannel = Int32.Parse(curItem.SubItems[1].Text); 307 | 308 | // ask for confirmation just once 309 | if (!deleteConfirmed) 310 | { 311 | DialogResult dialogResult = MessageBox.Show( 312 | Properties.Resources.str_channelSettingsConfirmDeleteText + channelList[selectedChannel].link + "?", 313 | Properties.Resources.str_channelSettingsConfirmDeleteTitel, 314 | MessageBoxButtons.YesNo, 315 | MessageBoxIcon.Question); 316 | 317 | if (dialogResult == DialogResult.Yes) 318 | deleteConfirmed = true; // also for all succeeding entries 319 | else 320 | break; // also for all succeeding entries 321 | } 322 | 323 | if (deleteConfirmed) 324 | { 325 | // OK, we really want to delete it 326 | channelList.RemoveAt(selectedChannel); 327 | // rebuild list view 328 | FillChannelList(); 329 | } 330 | 331 | // skip other selected entries 332 | break; // otherwise you need to take care on (*) index changes (*) confirm dialog text 333 | } 334 | 335 | // we need to reselect an entry after this operation 336 | editButton.Enabled = false; 337 | deleteButton.Enabled = false; 338 | } 339 | 340 | 341 | private void OnOK(object sender, EventArgs e) 342 | { 343 | // store data 344 | channelList.SaveToFile(); 345 | 346 | // close window 347 | this.DialogResult = DialogResult.OK; 348 | Dispose(); 349 | } 350 | 351 | private void OnCancel(object sender, EventArgs e) 352 | { 353 | // even if we press cancel we need to reload the channels if the user cleared the collected channel data 354 | this.DialogResult = DialogResult.Cancel; 355 | 356 | // close window 357 | Dispose(); 358 | } 359 | } 360 | } --------------------------------------------------------------------------------