| Days | |
| Hours | |
| Minutes | |
| Seconds |
One of the things I love the most about Debian is apt. It’s a great and speedy package manager. Being able to apt-get install from the command line and not have to wait for a heavy UI to come up is a major plus for me. Thats why I was frustrated with OpenSuSE, which we use at work.
First thing first, I think that the OpenSuSE package system is a pig. Yast is a pig. Zypper is a pig. I did, however, find the fastest route to installing via the command line, which I’ll share here.
Unless you happen to know the exact name of the package you want to install, you’ll need to look it up. The fastest way I’ve found is using Webpin, a nice online package searcher. Be careful that you are reading from the right repo though. For example, a search on “magick++” returns many packages, including “libMagick++-devel (6.3.5.10)” which, to my Debian eye, looks like the perfect package. It is from an odd repo though, “Results from http://download.opensuse.org/repositories/home:/dipe/openSUSE_10.2″ and the one I really want, and have access to mind you, is “ImageMagick-Magick++-devel (6.3.0.0)” which is in the main repo “Results from http://download.opensuse.org/distribution/10.2/repo/oss/suse”. It’s already too complicated, but we soldier on.
With my new, exact, package name in hand, I open up a root command line. The syntax for a zypper install is zypper install [package name] so I do zypper install ImageMagick-Magick++-devel and let it rip. After a ridiculous amount of parsing, it figures out the dependencies and asks me to continue, which I do. You have to babysit it for key managing, I havent figured out how to force “yes” on it. And that is how you use zypper to install on OpenSuSE.
root:~$ zypper install ImageMagick-Magick++-devel Restoring system sources... Parsing metadata for 20070918-142944... Parsing metadata for 20070927-100843... Parsing metadata for 20070927-100709... Parsing metadata for 20070918-055437... Parsing metadata for SUSE-Linux-10.2-Updates... Parsing RPM database... Summary: <install> [S3:0][package]libxml2-devel-2.6.26-27.pm.1.i586 <install> [S4:1][package]liblcms-devel-1.15-30.i586 <install> [S4:1][package]libwmf-gnome-0.2.8.4-24.i586 <install> [S4:1][package]libwmf-devel-0.2.8.4-24.i586 <install> [S4:1][package]readline-devel-5.1-55.i586 <install> [S5:0][package]ImageMagick-Magick++-devel-6.3.0.0-27.6.i586 <install> [S5:0][package]ImageMagick-devel-6.3.0.0-27.6.i586 Continue? [y/n] y Downloading: [S4:1][package]liblcms-devel-1.15-30.i586, 141.5 K(490.1 K unpacked) Installing: [S4:1][package]liblcms-devel-1.15-30.i586 Downloading: [S4:1][package]libwmf-gnome-0.2.8.4-24.i586, 7.7 K(9.6 K unpacked) Installing: [S4:1][package]libwmf-gnome-0.2.8.4-24.i586 Downloading: [S4:1][package]readline-devel-5.1-55.i586, 137.2 K(376.7 K unpacked) Installing: [S4:1][package]readline-devel-5.1-55.i586 Downloading: [S4:1][package]libwmf-devel-0.2.8.4-24.i586, 414.1 K(2.7 M unpacked) Installing: [S4:1][package]libwmf-devel-0.2.8.4-24.i586 Downloading: [S3:0][package]libxml2-devel-2.6.26-27.pm.1.i586, 2.5 M(11.6 M unpacked) Installing: [S3:0][package]libxml2-devel-2.6.26-27.pm.1.i586 Downloading: [S5:0][package]ImageMagick-devel-6.3.0.0-27.6.i586, 1.5 M(5.6 M unpacked) Installing: [S5:0][package]ImageMagick-devel-6.3.0.0-27.6.i586 Downloading: [S5:0][package]ImageMagick-Magick++-devel-6.3.0.0-27.6.i586, 193.2 K(939.8 K unpacked) Installing: [S5:0][package]ImageMagick-Magick++-devel-6.3.0.0-27.6.i586 root:~$
Here’s a non-obvious (or to me at least) trick to get tooltips onto a Gtk::Notebook tab. It took some searching, but essentially, you just add the Gtk::Label to a Gtk::EventBox and add that to the tab instead. Then you attach the tool tip to the Gtk::EventBox instead of the Gtk::Label.
Here’s an example. I couldn’t get my example to compile, the linker was going crazy, but I’m 99% sure that it’s fine. I’m probably just not seeing one glaring error. Let me know if you find it. The important stuff is all there, even if it won’t build.
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <gtkmm/main.h> #include "nbtt.h" using namespace std; int main (int argc, char *argv[]) { Gtk::Main kit (argc, argv); Nbtt notebookWindow; Gtk::Main::run(notebookWindow); return 0; } |
nbtt.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <gtkmm/window.h> #include "nbtt.h" using namespace std; Nbtt::Nbtt() { set_title("Notebook Tabs With Labels!"); set_border_width(10); set_default_size(400, 200); lblTabOne.set_text("Tab 1"); lblTabTwo.set_text("Tab 2"); lblTabThree.set_text("Tab 3"); ebTabOne.add(lblTabOne); ebTabTwo.add(lblTabTwo); ebTabThree.add(lblTabThree); toolTips.set_tip(ebTabOne,"Tab to page one."); toolTips.set_tip(ebTabTwo,"Tab to page two."); toolTips.set_tip(ebTabThree,"Tab to page three."); exNotebook.append_page(pageOne, ebTabOne); exNotebook.append_page(pageTwo, "Second"); show_all(); } |
nbtt.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #ifndef NBTT_H #define NBTT_H #include <gtkmm/window.h> #include <gtkmm/notebook.h> #include <gtkmm/eventbox.h> #include <gtkmm/label.h> #include <gtkmm/tooltips.h> using namespace std; class Nbtt; class Nbtt : public Gtk::Window { public: Nbtt(); private: Gtk::Notebook exNotebook; Gtk::EventBox ebTabOne; Gtk::EventBox ebTabTwo; Gtk::EventBox ebTabThree; Gtk::Label lblTabOne; Gtk::Label lblTabTwo; Gtk::Label lblTabThree; Gtk::Tooltips toolTips; Gtk::Label pageOne; Gtk::Label pageTwo; Gtk::Label pageThree; }; #endif // NBTT_H |
I found this trick in the gnome-list@gnome.org history. The thread starts here if you want to read the exchange.
Posted August 22nd, 2007 - PermalinkI was looking to get rid of using some environment variables in the app I do at work for several reasons. One, you can’t grab fresh environment variables on the fly (or at least I can’t) so if anything needs to be changed, you have to do a hard kill and restart the program. Two is that requiring some obscure, application specific environment variables seems a little silly to me, it’s excessive and adds bothersome configuration.
What I really needed was a way to open a config file that always resides in the same directory as the application. To do that I had to take the execution path (e.g. argv[0]) and chop it up a bit so that I can always get to that directory. I’m sure there is a better way to do this, and it wouldn’t work if you had the application in your $PATH, because then argv[0] would just be the executable name. Regardless of the caveats, it works nicely for me and makes me feel better about myself now that I can frag the environment variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <iostream> #include <fstream> #include <string> using namespace std; int main (int argc, char* argv[]) { cout << "File: " << argv[0] << endl; size_t found; string str = argv[0]; found=str.rfind("/"); if (found!=string::npos) str.replace(found,str.length(),"/"); cout << "Trimmed: " << str << endl; fstream filestr; str += "test.conf"; cout << "To Conf: " << str << endl; filestr.open (str.c_str(), fstream::in); string temp; getline(filestr,temp); cout << temp << endl; filestr.close(); return 0; } |
I was at work today and had the hardest time trying to find a function that could strip out whitespace from a string. There isn’t one built into C++, and I can’t just add on libraries (e.g. boost) just for this sort of one-time use item. I couldn’t find an easy drop in on the web either, so I wrote my own based on a templating system I had made.
1 2 3 4 5 6 7 8 9 10 11 12 13 | string trimstring (string toTrim) { size_t found; found = toTrim.find(" "); while(toTrim.length() != 0 && found != string::npos) { toTrim.erase(found,1); found = toTrim.find(" "); } return toTrim; } |
Very brute-force, but easy to understand right?
Posted August 6th, 2007 - PermalinkWhoa! Post 100 for this little blog. Although at times it’s been a little weak on content, I think there have been enough good ones to outweigh them. Besides, this site is more for me than for anyone else.
As this is post 100, I’m required by a dubious interpretation of a little known Norwegian law to list my favorite posts so far. So here they are, slightly categorized.
Mildly Useful
http://www.velvetcache.org/2006/09/28/usb-apps/
http://www.velvetcache.org/2006/09/17/firefox-plugins/
http://www.velvetcache.org/2006/10/02/simple-php-caching/
http://www.velvetcache.org/2007/01/19/cleaning-up-e-books/
http://www.velvetcache.org/2007/01/08/renaming-your-the-folders/
http://www.velvetcache.org/2007/01/08/pop-can-bookmarkers/
Wordy And Thoughtful
http://www.velvetcache.org/2006/09/15/i-cant-be-your-john-cusack/
http://www.velvetcache.org/2006/11/01/rediscovery/
http://www.velvetcache.org/2006/09/19/complexity-vs-redundancy/
http://www.velvetcache.org/2006/09/20/linux-on-the-desktop/
http://www.velvetcache.org/2006/09/07/facebook-apis/
http://www.velvetcache.org/2006/10/03/moniker-junkie/
Now to the meat of this post!
When I was first hired at UNO I was given the transfer articulation site as a project. What they basically do is keep track from year to year what each class at a number of schools is equivalent to here at UNO. I wrote it pretty quick, and they’ve been slowly adding data by hand for a few months now.
It’s a lot of data to enter too. So far they only have one year of one school done. The old system was a series of static HTML pages, so they didn’t think they could load it into the new system. I didn’t agree fully, because although the pages were poorly written and differed from year to year, they had a standard table layout on each one. I got to work on the idea of extracting the old data and loading it into the new database.
The first thing to do was create a syntactically correct file, here’s a sample of part of one of the files:
...
<TD>
<CENTER>
Max.<br/>
Transfer Hours<br/>
Allowed
</CENTER>
<TD>
<P>
<CENTER>
Comments
</CENTER>
<TR>
<TD height="33">
<P>ARCH1300
<TD>
<P>Architectural Desktop I
...Nasty, all-caps and they didn’t even close the tags. Ugly, ugly.
Luckily I knew of a secret weapon, HTML Tidy!
When run through with the appropriate flags I got this lovely version of the code:
... <td> <div class="c2"> Comments </div> </td> </tr> <tr> <td height="33"> <p>ARCH1300</p> </td> <td> <p>Architectural Desktop I</p> </td> ....
Okay, so running the tidy command on every file one at a time would be crazy, so I wrote up a short batch file to hit every single .html file with the tidy love. Please excuse the nasty one-lined-ness of it.
FOR %%f IN ("*.html") DO tidy %%f --char-encoding utf8 --clean yes --doctype strict --escape-cdata yes --indent auto --indent-attributes no --join-classes yes --output-xhtml yes --show-errors 99 --tidy-mark no --wrap 0 -m "%%f"
Okay, so now that we’ve got that beautified file, we need to parse it. To make life easier I stripped all the other tags out except for the table tags with PHP’s strip_tags(). I then regexed out anything that wasn’t inside the <table> tags and created my SimpleXML object with what was left over.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $filename = $_REQUEST['dir'].'/'.$_REQUEST['file']; // Remove the space in fopen, it's a Wordpress thing. :( $handle = f open($filename, "r"); $contents = fread($handle, filesize($filename)); fclose($handle); $contents = strip_tags($contents,'<table><tr><td>'); if(preg_match('/<table.*>([.\r\n]*)<\/table>/si', $contents, $matches)) { print 'Will attempt to load. '; $contents = $matches[0]; $xml = new SimpleXMLElement($contents); if(!$xml) { print 'Error! XML Didn\'t read right.'; exit(); } print 'Load complete. Checking for expected structure. '; if(trim($xml->tr[0]->td[0]) != 'Course') { print 'Error! Structure not as expected. Dumping.<br/>'; var_dump($xml); exit(); } } |
A few loops and a whole lot of boring processing later and it’s all in the DB. But that’s the gist of the system and it’s frickin tight.
Posted January 23rd, 2007 - Permalink