I Got Code #5: Downloading linked images

There was actually a question that got me thinking – how would I implement a program that downloads pictures from a web page, that are pointed by some links?

Here is a sample console application I came up with:


using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.IO;
using System.Text.RegularExpressions;
using System.Drawing;

namespace ConsoleApplication
{
    class Program
    {
        static int totalFiles = 0;
        static int currentFiles = 0;

        static void Main(string[] args)
        {
            GetImages("<a href="http://www.textureking.com/index.php/category/all-textures%22);">http://www.textureking.com/index.php/category/all-textures");</a>
        }

        static void GetImages(string url)
        {
            string responseString;
            HttpWebRequest initialRequest = (HttpWebRequest)WebRequest.Create(url);
            using (HttpWebResponse initialResponse = (HttpWebResponse)initialRequest.GetResponse())
            {
                using (StreamReader reader = new StreamReader(initialResponse.GetResponseStream()))
                {
                    responseString = reader.ReadToEnd();
                }
            }

            List<string> imageset = new List<string>();
            Regex regex = new Regex(@"f=""[^""]*jpg|bmp|tif|gif|png",RegexOptions.IgnoreCase);
            foreach (Match m in regex.Matches(responseString))
            {
                if (!imageset.Contains(m.Value))
                    imageset.Add(m.Value);
            }

            for (int i = 0; i < imageset.Count; i++)
                imageset[i] = imageset[i].Remove(0, 3);

            totalFiles = imageset.Count;
            currentFiles = totalFiles;

            Console.WriteLine(totalFiles.ToString() + " images will be downloaded.");

            foreach (string f in imageset)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadImage), f);
            }

            Console.Read();
        }

        static void DownloadImage(object path)
        {
            currentFiles--;
            Console.WriteLine("Downloading " + Path.GetFileName(path.ToString()) + "... (" + (totalFiles - currentFiles).ToString() + "/" + totalFiles + ")");
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path.ToString());
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                Image image = Image.FromStream(response.GetResponseStream());
                image.Save(@"D:\Temporary\" + Path.GetFileName(path.ToString()));
            }
            Console.WriteLine(Path.GetFileName(path.ToString()) + " downloaded.");
        }
    }

}

The sample URL provided in the method call is used to download several textures linked on the webpage.

I am using regex to actually find the URLs. The case is ignored since I am not sure whether the file extensions are written with in caps or not. Since there is a chance for the same URL to be mentioned twice on the same page, I am making sure that there are no duplicates, so before adding the regex match to the List, I am checking if that already contains an entry for the match.

The final saving path also can be modified, but I decided to leave it hardcoded like this for testing purposes. In case you want to make the path dynamic, you can pass a generic collection or an array as the parameter for the DownloadImage method and then explicitly convert it and read the needed values (identified by an index, for example).

NOTE: I am using ThreadPool here so all threads are automatically set as background – if the application is closed, the download process will be canceled. To avoid this and wait for all downloads to complete (which is probably not a good idea but still a possibility), the Thread class should be used with IsBackground set to false.

I Got Code #4: WPF TextBox with rounded corners. What and how?

What is the first idea that comes to mind when someone mentions rounded corners and WPF? Probably Border. That is the right thing to think about, but how to apply it to a TextBox control?

There are two ways to achieve what you want.

Way A:

The most obvious thing would be creating a border around the control itself. Something like this:


<Border CornerRadius="5" BorderThickness="1" BorderBrush="Black" Margin="91,192,150,79">
<TextBox Background=”Transparent” BorderThickness="0" Height="35" Name="txtContents" Width="254" />
</Border>

That should do the initial trick – the TextBox control has no border around it (the BorderThickness property is set to 0) while the Border that contains it sets the correct rounding, color and thickness.

The rendered output will look like this:

image

Looking good, but the fun part comes around when you decide that this specific TextBox shouldn’t be enabled, so you set the IsEnabled property to False. What do you get? This:

image

What’s up with the rest of the white space between the border and the writing area? Doesn’t look like we want it to behave like this. And that’s where the second way to create rounded corners saves the day.

Way B:

It is a bit more complicated, but it gives a better result. What it does is it overrides the default control template for the TextBox. But how do I know how the default template looks like?

Since it is not possible to modify only one part of the template, the whole template should be overridden. To avoid functionality loss, I am going to get the default template and use it with small modifications.

To get the default style (that embeds the control template) for a TextBox control I am using the GetStyle method:


string GetStyle(Type t)
{
FrameworkElement element = (FrameworkElement)Activator.CreateInstance(t);
object styleName = element.GetValue(FrameworkElement.DefaultStyleKeyProperty);

Style style = Application.Current.TryFindResource(styleName) as Style;

StringWriter stringContainer = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(stringContainer);
xmlWriter.Formatting = Formatting.Indented;

System.Windows.Markup.XamlWriter.Save(style, xmlWriter);

return stringContainer.ToString();
}

Since I am using the default control, without any custom styles attached, I can simply create an instance of TextBox and use its type as a parameter for the GetStyle method:


TextBox t = new TextBox();
Debug.Print(GetStyle(t.GetType()));

The output should look like this:


<Style TargetType="TextBox" xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;">http://schemas.microsoft.com/winfx/2006/xaml/presentation"</a> xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml&quot;">http://schemas.microsoft.com/winfx/2006/xaml"</a> xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<Style.BasedOn>
<Style TargetType="TextBoxBase">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="Panel.Background">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.WindowBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,20" MappingMode="Absolute">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#FFABADB3" Offset="0.05" />
<GradientStop Color="#FFE2E3EA" Offset="0.07" />
<GradientStop Color="#FFE3E9EF" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderThickness">
<Setter.Value>
<Thickness>1,1,1,1</Thickness>
</Setter.Value>
</Setter>
<Setter Property="Control.Padding">
<Setter.Value>
<Thickness>1,1,1,1</Thickness>
</Setter.Value>
</Setter>
<Setter Property="UIElement.AllowDrop">
<Setter.Value>
<s:Boolean>True</s:Boolean>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.FocusVisualStyle">
<Setter.Value>
<x:Null />
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.PanningMode">
<Setter.Value>
<x:Static Member="PanningMode.VerticalFirst" />
</Setter.Value>
</Setter>
<Setter Property="Stylus.IsFlicksEnabled">
<Setter.Value>
<s:Boolean>False</s:Boolean>
</Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="TextBoxBase">
<mwt:ListBoxChrome Background="{TemplateBinding Panel.Background}" BorderBrush="{TemplateBinding Border.BorderBrush}" BorderThickness="{TemplateBinding Border.BorderThickness}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</mwt:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.BasedOn>
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
</Style>

That is a lot of XAML markup right there, but all we need is the control template:


<ControlTemplate TargetType="TextBoxBase">
<mwt:ListBoxChrome Background="{TemplateBinding Panel.Background}" BorderBrush="{TemplateBinding Border.BorderBrush}" BorderThickness="{TemplateBinding Border.BorderThickness}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</mwt:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Now, the ListBoxChrome wrapper should be removed and Border used instead, with the CornerRadius property assigned. The modified template looks like this:


<ControlTemplate TargetType="TextBoxBase" x:Key="txt">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Black" x:Name="Bd" Background="{TemplateBinding Panel.Background}">
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Additionaly, I added x:Key to the template header so I can identify it in my application. Now, this template can be inserted in the Resources section for a WPF application. Since I am testing this on a windowed WPF application, I will insert this template inside Windows.Resources.

The reference to the s namespace should be added as well (used for the IsEnabled trigger):


xmlns:s="clr-namespace:System;assembly=mscorlib"

Now I am able to reference the template for a TextBox inside the window:


<TextBox Template="{StaticResource txt}" Background="Transparent" BorderThickness="0" Height="35" Name="textBox1" Width="254" />

And now the rendered output looks like this:

image

Hey, but this one looks just like the one when I first tried using the border! True, but try disabling the TextBox now and see what it looks like now:

image

Just the way it should be. In case you do not need to change the look of the control when it is disabled, you can simply remove the IsEnabled trigger from the template so all you will have is this:


<ControlTemplate TargetType="TextBoxBase" x:Key="txt">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Black" x:Name="Bd" Background="{TemplateBinding Panel.Background}">
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
</ControlTemplate>

It will correctly render the border, but there won’t be a grayed-out background and modified foreground when the control is explicitly set as inactive.

WeatherBar SDK – now public

A while ago I decided to make WeatherBar extensible. I know that for some people it could be a bit frustrating when they cannot find a specific location in WeatherBar because Google Weather API cannot locate weather data for it.

Therefore, starting with the next release of WeatherBar, the application will no longer be tied to a single weather service. By default, I will still ship the Google Weather plugin (it is already developed and ready for distribution), but there will also be alternative web services available.

To develop a plugin for WeatherBar, all that is needed is the WeatherBar Dev Kit. It can be downloaded here.

It includes:

  • The SDK documentation
  • Sample plugin (Google Weather API)
  • WeatherBar Extension Test Tool 1.0 Beta

The WeatherBar Extension Test Tool can be used to test the plugin compatibility with WeatherBar 3.0. And although at this moment there is no official relase for the 3.0 build, this tool will ensure that the plugin works correctly and is able to expose the correct information.

I will be glad to bundle more extensions in the next release (for weather services other than Google Weather), so if you – the developer, created one, drop me a line. Once I make sure that your plugin works correctly and is using the correct format, I will be able to pack it in the final release. Of course, developers get the credit for their plugins.

Installing CouchDB on a VM

“The time to relax is when you don’t have time for it.”image  - Sydney J. Harris

After CouchDB hit its official 1.0 release, I decided to try it out and compare it to existing RDBMS, although this is probably not the right thing to do since CouchDB is based on a completely different paradigm. Anyway, I gave it a shot.

First of all, I decided that I will try it out inside a VM (Virtual Machine) and there are a few reasons for that. Back in the day, when having the opportunity to run a virtual machine on your computer was more of a privilege since resources were limited and the performance wasn’t even close compared to an actual install, doing something inside a guest system would at least earn you some weird looks – why run something inside a box when you can do the same on the host system?

But now times changed and virtual machines evolved. I can fine-tune the performance of my VM and considering the performance of the base machine (the actual hardware) I can simultaneously run two operating systems without seeing any significant performance loss for both of them (well, it still depends on what you are doing).

I use to experiment a lot with a wide variety of development tools and if I would install everything on my host system (Windows 7 Ultimate x64, if anyone interested). it will become cluttered in a matter of days and will practically be unusable. A VM provides a sandbox environment where I can do anything I want – in case something goes wrong, I can simply install a new VM instance and start from scratch. And of course, I am not risking my data on the base system.

The configuration for the VM I used is the following:

  • CPU: 1 instance
  • RAM: 512MB
  • Video memory: 12MB
  • Hard drive: 30GB
  • Guest system: Ubuntu 10.04

My first thought was using Synaptic and install CouchDB from an existing official repository. But it wasn’t the case – there is CouchDB listed over there, but it was version 0.11.0 – I wanted to install 1.0.0. Therefore, there could be only one solution – compiling from source. Although this might seem a quite complicated process, in fact once you do it two or three times, you pretty much get used to the procedure and all you have to do is make sure the proper dependencies are present.

So I went ahead and downloaded the source for the 1.0.0 release. This can simply be done via the terminal (the wget command) but you can also use the web browser – depends on personal preferences. I followed the instructions on the official wiki page (Installing CouchDB on Ubuntu) and it all went smooth – dependencies installed, the main package is ready – until the point when ./configure threw me an error – it could not find the needed JS libraries. Since libmozjs-dev is clearly not available in Ubuntu 10.04, I was sure that I installed xulrunner-dev instead. But I did not specify this for ./configure, so I restarted the process, but already used the correct library references:

./configure –prefix= –with-js-lib=/usr/lib/xulrunner-devel-1.9.2.6/lib –with-js-include=/usr/lib/xulrunner-devel-1.9.2.6/include

It all went fine, but the story isn’t over yet. It was time to compile and install the server. Simple:

sudo make && make install

But not so fast – when it almost reached the ending stage, several errors were thrown notifying me that access to several locations was denied. Since I already used chmod and chown, I was a bit confused on what might be the issue. The solution was simple – I switched to my root account for the installation (and yes, I do know that this is not a good practice – but for the purpose of properly installing CouchDB it made sense). The command went through just fine and the CouchDB server was finally installed. I tried to start the service and the message that it was successfully launched was shown. However, when I tried to use curl to see the response, an error was thrown – it could not connect to the server.

The first thought that came to my mind in this situation was restarting the VM. But it didn’t help. Looking for possible solutions, I encountered this article. I tried running this command:

sudo –u couchdb couchdb

And indeed there was a problem – the user wasn’t able to access the main couchdb folder. I was thinking in the context of user permissions, but it didn’t really apply here, so I thought about folder permissions – I probably didn’t chmod something correctly. I tried doing it again by following the instructions but no positive results with that. And then I stumbled across another article that used the correct chmod values. Worked like a charm – I restarted the service ad was able to access the Futon web UI.

nosql2

The installation wasn’t much of a “relax” at first, but the end result is worth it. Time for me to work more with it to see where I can use it and how.

The high-school part is over

34871_1338348540987_1299347609_30815797_7662377_n Got my baccalaureate exam grades and my graduation diploma and I am now officially a high-school graduate. Can’t say that I am not happy about it – these were some interesting 12 years. And as it always happens – I met the most awesome people at the end of my senior year (Bee, Alexandrina, Pufa, Grushka, Maria Cretu & Dvininov, Dima (running) – just to name a few). But I am extremely excited for college. I will be pursuing an Associate’s Degree in Computer Science at Independence Community College in Kansas – a pretty cool place, I must say – I attended it for a semester during my junior year in high-school and really enjoyed the campus as well as the way classes are held. From what I know it is still the same now.

Why computer science? Most likely because I am a computer geek (a silent doh! comes to mind at the moment). I hope to get into some programming (although at ICC I probably won’t be doing much C# – I expect there to be a lot of C++ and Java) over there and hopefully get involved in some software development contests (ImagineCup and Google Summer of Code have the priority in this case but I am open for anything). I will be still working with Microsoft tools on my own – that’s something I really enjoy and not going to give up.

And I hope to finally take more pictures of the place I will live in (Independence, KS) – missed this one in 2008. So for now, I am getting ready to board the plane and come to Independence, Kansas.

Photo courtesy of Alexandrina Muntean.