KDE Development PART 10

From LXF Wiki

USING KDEVELOP

In the penultimate part of this hacking series, Jono Bacon moves onto the more complicated subjects of file management and network programming…

Welcome to another gripping installment in our KDE development series. So far in our quest for KDE hacking karma, we’ve explored a number of different topics and areas. Alas, this is the penultimate episode in this guide and we’ll be drawing the series to a close next month. Before you start to well up and have to resort to the tissues and a bottle of wine, pull yourself together and fasten your seatbelt for another dose of hacking.

Today we’re going to kill one and a half birds with a single stone. The two major areas that are still chalked on the list of things to do for this series are file management and network programming. Although we could explore these two topics in individual tutorials, instead we’re going to code a single feature and use both file management and network programming concepts together.

To achieve this, we’re going to roll our sleeves up and begin coding support for a web-based photo gallery. These galleries aren’t a new concept and our implementation isn’t going to involve anything drastically different. Our main aim is to cover the details behind creating a simple photo gallery and you can then set out with a spring in your step to develop a more advanced and flexible gallery.

In this issue’s tutorial, we’re going to explore the file generation part of our web gallery. If you split the concept of creating a photo gallery into simple parts, we need to follow these processes:

  • Load an album full of pictures
  • Store the list of picture file names in a list that we can use to generate the photo gallery
  • Generate the boilerplate code that sets up an HTML file. This can include a line of text saying something and opening the HTML table in which we’ll add the pictures
  • Read in each picture from our list of filenames and add each picture as a small thumbnail to the page
  • Add the final piece of HTML code that closes the table
  • Save the file

With this set of targets in mind, we’re essentially creating an initial piece of an HTML page, adding each picture one by one and then finally bolting on the remaining piece of HTML. All of this can be handled by a custom-written slot located inside one of our classes.

Table of contents

Creating the framework

Before we get into the nitty gritty of coding our main slot to generate the photo gallery, we first need to add the boilerplate code that will add a menu entry to generate a web photo album. To do this, you should edit the lxfgalleryui.rc file and add the following XML:

<!DOCTYPE kpartgui SYSTEM “kpartgui.dtd”>
<kpartgui name=“lxfgallery” version=“2”>
<MenuBar>
<Menu name=“file”>
<Action name=“create_html” />
</Menu>
</MenuBar>
</kpartgui>

In KDE, menu items are added to this .rc file and they’re merged into the application when it runs. Here we’re creating a new Action called create_html that’s merged into the File menu. The next step is to create the main action within our setupActions() slot inside lxfgallery.cpp:

KAction *createHtmlAct = new KAction(i18n(“&Create html
page”), “view_icon”, CTRL+Key_H , this,
SLOT(slotCreateHtml()), actionCollection(), “create_html”);

Although this looks like a long and confusing line, it’s actually fairly simple. Firstly, we use the KAction class to create a new action called createHtmlAct and set the text to “Create html page”. This text will then appear on the menu entry. The i18n() function that’s wrapped around this text is used so KDE can translate the string where required. Although not essential in small programs, use of i18n() is vital in larger projects. Next, we specify the view_icon icon set and indicate the shortcut as Ctrl+H. After this, we specify the slot as slotCreateHtml(), add this action to the actionCollection() and finally refer to the action XML name in the lxfgalleryui.rc file.

To see the menu entry, you’ll need to not only make the project, but also ‘make install’ it. This is very important to ensure that the .rc file is installed correctly. You can see the menu option in the image on the right.

Creating a list of photos

The next step is for us to create a list of filenames that can be used later to generate the HTML file. In our current code, we’re simply loading the photos one by one when we add them to the thumbnail view. Although keeping a list of filenames wasn’t required before, it’s needed now because we have to start with one filename and then go through each one and add them to the HTML page in an <img> tag. To create this list, Qt includes a special container called a QStringList. First, add this as a declaration to selectionbarcode.h:

QStringList pathList;

When you’re writing any kind of code, it’s generally good practice to initialise all variable or data structures to zero before you use them. You may have seen this elsewhere when people create an integer and set its value to 0. We’ll do the same with our new pathList structure, so add the following code after QFileInfo *fileinc in the loadThumbs() function:

pathList=““;

To fill pathList with the filenames, you can use the append() method to add each filename, obtained by using the fileName() method on fileinc. Add the following code after QImage img(fileinc->absFilePath().latin1()) a few lines down:

pathList.append(fileinc->fileName());

Creating the slot

The real action in the HTML photo gallery feature happens in the slotCreateHtml() slot that we referred to earlier. Before we begin to code the main slot, remember to add a declaration of the slot in lxfgallery.h:

void slotCreateHtml();

With the slot declared, it’s time to begin writing the main code that will create the HTML page of our gallery. First, add the outer shell of the slot:

void LXFGallery::slotCreateHtml()
{

Earlier, when we created the string list, we initialised it to zero, which is good programming practice. In LXFGallery, there are going to be some situations when somebody may click on the menu option to create the HTML page when they haven’t loaded an album. Although we should really grey out the option until an album is loaded, we’ll add some code in this slot to check that an album is loaded anyway. To do this, use the exists() method to check whether the QDir dir variable has some data inside it (if there’s no ‘dir’, no album is loaded). If this doesn’t exist, we simply ‘return’ out of the slot and hence the rest of the code in the slot is ignored:

if (!selectionBar->dir.exists())
return;

At this point in the code, we know that an album is currently loaded, and we now need to ask the user what filename they would like to call the webpage. We can ask the user this by using the standard Save dialog box in KDE. A nice feature within the KDE programming framework is how you can call these pre-built dialog boxes and get specific details back from the user. In the following line of code, we’re using the getSaveURL() function to do three things: set the preselected directory in the dialog to the path of the current album, then set the filter as *.html (so we only see HTML files listed in the dialog box), and finally set the caption of the save box to “Save As”:

const KURL url = KFileDialog::getSaveURL( selectionBar->dir.
path(), i18n( “*.html” ), this, i18n( “Save As” ) );

When this line of code is executed, the selected file or filename entered is stored in the url variable. We need to check this variable to see if it’s empty, which is often the case when people don’t enter a filename or don’t select a file:

if(!url.isEmpty())
{

If it turns out that the file isn’t empty and the user selects an existing file, it would be nice for us to ask the user if he or she is sure that they want to overwrite the file:

if( KIO::NetAccess::exists(url,false,this ) && KMessageBox::
warningContinueCancel( this, i18n( “A file named \”%1\”
already exists. Are you sure you want to continue and
overwrite this file?” ).arg(url.url() ), i18n( “Overwrite File?” ),
KGuiItem( i18n( “&Overwrite” ) ) ) != KMessageBox::Continue
) return;
}

In this long line, we check to see if the file exists by using the exists() function within the NetAccess KIOSlave. Although it may seem a little odd to use something to check if a network resource is available, this cements the potential for accessing remote files in our code. The other check inside the ‘if’ statement is if you click on Overwrite in the KMessageBox, which asks you if you’re happy to overwrite the file. You can see our dialog in the image above.

The next step is for us to set the current path for the QDir object to the path stored in dir. This will give us a specific path from which we get the pictures to add to our HTML page:

QDir::setCurrent( selectionBar->dir.path() );

Now we need to obtain the filename obtained from the Save box earlier in the slot and create a new file with the same name. To do this, we use the special QFile class to create a new QFile object called myFile. We then use the open() method to take this object and create a new file in Write Only mode. This is specified with the IO_WriteOnly argument that’s passed to the open() method. There are a number of different arguments that can be passed to open a file with different permissions, and if the file does exist and you pass it IO_WriteOnly, a new file will be created:

QString myString = url.fileName(true);
QFile myFile(myString);

myFile.open(IO_WriteOnly);

With the file created, we can now get down to actually generating the page. To do this, we’re going to use a special class called QTextStream that can be used to essentially stream textual data into the file. First of all, create a new QTextStream object with the QFile object:

QTextStream ts( &myFile);

We can now use the << operator to feed data into the QTextStream object. Those of you familiar with streams in C++ will recognise this format, and you can add a number of lines to stream each chunk of text into the file. Inside these lines, the ‘\n’ symbol is used to add line breaks in the output. Although not essential, these are added to keep those people who do look at the source code of web pages happy. We begin by adding a number of lines for the boilerplate HTML code that creates a new page and opens the table that contains the pictures:

 ts << “<html>\n<head>\n\t<title>“;
 ts << “My Web Gallery”;
 ts << “</title>\n</head>\n<body>\n”; 
 ts << “<center><h1>My gallery</h1></center>\n”;
 ts << “<table cellspacing=\”10\”>\n”;

The next step is to actually add the pictures to the file. To do this, we’re going to add a series of thumbnail pictures to the HTML page, making each picture a link so the user can click on it and see the full-size picture. As this is an introduction to coding the web photo gallery, our solution is fairly simple. Each thumbnail is simply the original image that uses the width and height attributes in the <img> tag to be displayed as a smaller thumbnail image. Our aim with this is to create a line of code for each image that’s along the lines of the following code.

Don’t add it to your slot yet, though!

<a href=“dog.jpg”><img src=“dog.jpg” border=“0”
width=“200” height=“150”></a>

Here we’re creating an <a> link to the original picture called dog.jpg, and we’re setting the link to the same image that has been given a width of 200 pixels and a height of 150 pixels. Most of this code is the same for each picture, but the key part that changes is the name of the picture.

Another consideration we need to make is how we’re displaying the pictures. I’ve decided to present the pictures in two columns with a number of rows. We’ll need to display two pictures, then move to a new row, display another two and so on. Although this will work fine, we may also need to display another single picture at the end if the number of photos can’t be easily divisible by two. The first step is to get a total of how many pictures we’re dealing with. We can use the count() method to get this:

int total = selectionBar->pathList.count();

To display the photos, we’ll embed a ‘for’ loop inside another ‘for’ loop. The way this works is that the outer for loop will loop through the number of rows, while the inner for loop will loop through each individual row and display the two pictures. The first (outer) loop loops from the start of our list of pictures and increments in jumps of two each time (jumps of two ensures we only loop the rows):

for (int i=1; i< total-2; i=i+2) {

While inside this loop, we now create the table row:

ts << “<tr>\n\t”;

The next step is to create another loop inside this one so that we can loop twice to display each picture in the row. We do this with the following code:

for (int j=i; j<i+2; j++)
{

Inside this loop, we add the code to add the table cell and then add the code to create the image link and the name of the image. To extract the name of the image we use a bit of Qt magic and a method called args(). Within this line, we use the ‘j’ loop counter to refer to the number of the entry in the path list. If you look at the line, we code the HTML and place a %1 and a %2 symbol inside it. These symbols are replaced later in the line by selectionBar->pathList[j]:

 ts<< “<td align=\”center\” width=\”25%\”>“;
 ts << QString(“<a href=\”%1\”><IMG SRC=\”%2\””).
 arg(selectionBar->pathList[j]).arg(selectionBar->pathList[j]);
 

After this is complete, we close the rest of the tag down by adding the width and height of the thumbnail. We also close the table cell:

ts << “ border=\”0\” width=\”200\” height=\”150\”>\n\n</
a>“;
ts<<“</td>\n”;

We now simply need to add the closing bracket and the inner loop is complete:

}

At this point, both images on each line are reproduced in the inner loop. We now need to close off the row in the outer loop, and the two loops together will create all of the images in the page:

 ts << “</tr>\n”;
 }
 

If you were to run this code now with an odd number of photos, you may see that a picture is left off the end. The reason for this is that we’re basing our logic around the number 2, and this number is obviously even.

To solve this, we’ll perform a simple check to see if we have an odd number of photos and, if so, add the remaining picture. To do this, we first see if the remainder of ‘total’ divided by two is equal to zero. To check for this, we can use the Modulo operator (%):

if (total%2 ==0) {

If this is the case, we then add the remaining text to the text stream and use total-1 to refer to the relevant image:

 ts << “<tr>\n\t<td align=\”center\” width=\”25%\”>“;
 ts << QString(“<a href=\”%1\”><IMG SRC=\”%2\””).
 arg(selectionBar->pathList[total-1]).arg(selectionBar-
 >pathList[total-1]);
 ts << “ border=\”0\” width=\”200\” height=\”150\”>“;
 ts<<“</td>\n</tr>\n”;
 }
 

Finally, close the slot by writing the finishing bits of HTML code and closing the file with the close() method:

ts << “</table>“;
ts << “\n</body>\n</html>“;
myFile.close();
}

With those final lines added, your code is now complete. If you run the program and all the code has been entered correctly, you should be able to generate a fully functioning HTML photo gallery. You can see an example of this above. ((Image caption: Our super-snazzy online photo gallery page))


Wrapping up

In this issue we’ve explored a fairly technical process. Getting used to a new technology or feature of that technology is never an easy path to follow, and the slot we covered earlier in this article was quite expansive. If you’ve managed to understand how the entire process works, you now have the knowledge to generate any kind of text file. These text files can contain random text or specific structures that mean something, such as the HTML structure in our project today. Whatever kind of textual content you’re writing to the file, the same basic process applies – open/create a file, stream text in and then close it.

Next month we’ll bring our series to a close and write the code to upload our web gallery to the Internet. In addition to this, we’ll work on implementing a few other features here and there to make LXFGallery more complete.

Don’t forget to send your comments and suggestions to jono@jonobacon.org, and we’ll see you next month!

The role of freedesktop.org

At this point in this series, you’ve learned the core skills to create comprehensive and interesting programs. With this knowledge, you can move forward and being exploring other technologies to use in your projects. This could include thirdparty libraries, special algorithms and other additional content.

One particularly interesting project you should be familiar with is that of freedesktop.org. The aim of freedesktop.org is to provide a range of desktop-independent technologies that major desktops and other window managers can make use of to facilitate interoperability. This has included standardised trashcans, recent files paths, hardware abstraction layers, interprocess communication and other features. Many of these tools and libraries have been developed from the outset by developers from Gnome, KDE and a variety of other projects. This has created an environment where no single desktop has dominated how a particular technology has been developed.

You can find more information about freedesktop.org at the official website: http://www.freedesktop.org.