Monday, July 30, 2007

Connecting NetBeans 6 to a CVS repository on a shared drive

I'm sure there are others out there who've done this before but I wanted to make sure it was documented for myself. So, here's what you need:
  • NetBeans 6 M10 - older and new versions will probably work with this as well
  • cygwin - standard install plus cvs
Here are the steps:
  1. After NetBeans and cygwin are installed correctly, add the following environment variables:
    • CVS_EXE - <cygwin-install>\bin\cvs.exe
    • CVS_SERVER - <cygwin-install>\bin\cvs.exe
    • add <cygwin-install>\bin to your path
  2. Add a place in your cygwin virtual filesystem to set up the mount points, I created a /projects/projecname for each.
  3. Set up the mount points in cygwin (note that this is done from the windows command shell and not the cygwin bash shell):
    • >mount z:\shared\drive\path\to\cvs\repo /projects/projectname
    You'll have to do this for each repo you need to connect to.
  4. Now here's the really weird part. In the CVSROOT directory of your repo, there's a file named config. You need to edit this file and remove all the new-lines. This is very important as you won't be able to connect otherwise.
  5. All you need to do now is open up NetBeans and do a CVS checkout. The path will be something like :local:/projects/projectname
YMMV

Wednesday, July 25, 2007

No more .NET...Ever!

Just started a new job. Much better pay but more importantly not having to do .NET development. I can be happy again.

Why I won't be using Guice

Why won't I be using Guice? Because if I need help, the only good place to go is the mailing list which is hosted at Google Groups. This obviously isn't a problem at home where nothing is blocked, but at work it's a no-go. At the last three companies I've worked for Google Groups is blocked since it's considered chat. Now I could probably get some kind of allowance for the Guice group but who wants to go through the hassle. So for the time being I'll be sticking with Spring.

Friday, July 06, 2007

Code Monkey

Monday, June 18, 2007

New space heater from Azul

Just read about this on the Register. Should keep you toes warm on those cold winter days...

...and it runs Java too!

http://www.azulsystems.com/products/compute_appliance.htm

A .NET short-list

Since I've been working on the MS side of the fence for about 6 months now I thought I'd share some of the things I've seen.

MVC is pretty foreign to about 99% of .NET developers which I find rather insane. Good thing there are smart people like and Hammett, Ayende and JP. Of course there are good people working at MS. But to make this type of stuff work they have to create these huge frameworks and tools (Web Client Software Factory - it's open source though :).

Oh, and don't get me started with Visual Studio...

Not that anybody is listening, but I hope to blog a bit more often.

Thursday, June 15, 2006

Dynamic, selectable table with Behaviour and Dojo

At work I'm working on rewriting a desktop app into a web app and of course it has to use Ajax to keep the feel. This app has several screens that contain data tables that can be filtered using a separate form field.

I first started building these tables by using the DOM completely, but that gets to be a little slooooow in IE, even on my 2gb dual-core laptop. To make things quicker, I would only load the data a page at a time and append new data if the user scrolled to the bottom. But that too was slow.

So I decided to start over. If you've taken a look at the LiveGrid widget from Rico you know what I want to do. Problem with the LiveGrid is that the table isn't selectable.

To start things off, you create the table (It's just a basic HTML table, I didn't have a week to figure out the CSS :).

<div>
<table id="datatable">
<thead>
  <tr><th>col1</th><th>col2</th></tr>
</thead>
<tbody>
  <tr tabindex="0"><td id="row0col0">col1</td><td id="row0col1">col2</td></tr>
  ...
  <tr tabindex="0"><td id="rowNcol0">col1</td><td id="rowNcol1">col2</td></tr>
  </tbody>
</table>
<div id="scrollbar">
<div id="dataHeight"></div>
</div>
</div>

That's the basic table. The sample has only two columns to save space. Of note is the scrollbar and dataHeight divs. This is the scrollbar that will drive the table.

Here's some CSS for style:

div, table, tr, td, th, tbody, thead {
 padding: 0px;
 margin: 0px;
 border: none;
}
table {
 width: 500px;
 float: left;
 border-collapse: collapse;
 border-width: 1px 0px 0px 1px;
 border-style: solid;
}
th {
 background-color: #ddd;
 border-width: 0px 1px 1px 0px;
 border-style: solid;
}
td {
 border-width: 0px 1px 1px 0px;
 border-style: solid;
}
#scrollbar {
 width: 20px;
 overflow: auto;
 position: relative;
 left: -4px;
}
#dataHeight {
 width: 1px;
 height: 100000px;
}
.datarow {
}
.datarowfocus {
 background-color: highlight;
 color: highlighttext;
}

Ok, no big deal so far. To make this table work, you need to have a couple of javascript libraries, Dojo and Behaviour. The code was built using Dojo 0.2.2 so I'm only going to assume it will work 0.3.1.

Here's the code:

var tableRules = {
 '#scrollbar' : function(element) {
  element.onscroll = function() {
   // TODO make an ajax call to get new data for table
   generateContent(Math.round(element.scrollTop/20));
  }
 },
 '#datatable tr' : function(element) {
  element.onfocus = function() {
   dojo.html.setClass(element, "datarowfocus");
   var index = 0;
   var counter = 0;
   for (var i = 0; i < element.parentNode.childNodes.length; i++) {
    // have to check the nodeType - firefox sees text nodes between
    // table elements (tr, td, etc.), ie does not
    if (element.parentNode.childNodes[i].nodeType == dojo.dom.ELEMENT_NODE) {
     if (element == element.parentNode.childNodes[i]) {
      index = counter;
     }
     counter++;
    }
   }
   selectedIndex = index;
  },
  element.onblur = function() {
   dojo.html.setClass(element, "datarow");
  },
  element.onkeydown = function(event) {
   if (!event) var event = window.event; // IE
   var scrollBar = dojo.byId("scrollbar");
   var singleRowSize = dojo.style.getContentBoxHeight(element);
   var pageSize = singleRowSize * 13;
   if (event.keyCode == 38) {
    if (selectedIndex == 0) {
     scrollBar.scrollTop -= singleRowSize;
    } else {
     dojo.dom.prevElement(element).focus();
    }
   } else if (event.keyCode == 40) {
    if (selectedIndex == 14) {
     scrollBar.scrollTop += singleRowSize;
    } else {
     dojo.dom.nextElement(element).focus();
    }
   } else if (event.keyCode == 33) { // pgUp
    scrollBar.scrollTop -= pageSize;
   } else if (event.keyCode == 34) { // pgDown
    scrollBar.scrollTop += pageSize;
   }
  }
 },
 '#datatable td' : function(element) {
  element.onfocus = function() {
   element.parentNode.focus();
  }
 }
}
Behaviour.register(tableRules);

var selectedIndex = -1;

function generateContent(row) {
 // this section takes the result of the ajax call and fills the table
 for (var rows = 0; rows < 15; rows++) {
  for (var cols = 0; cols < 2; cols++) {
   var element = dojo.byId("row" + rows + "col" + cols);
   element.innerHTML = "row" + (rows + row) + "col" + cols;
   // TODO implement empty rows when no data found
  }
 }

 // this is needed for ie because the table row will lose focus when you
 // click on the scrollbar to scroll - firefox keeps the focus on the table row
 if (dojo.render.html.ie && (selectedIndex >= 0)) {
  dojo.byId("datatable").childNodes[1].childNodes[selectedIndex].focus();
 }
}

dojo.addOnLoad(function() {
 // load data
 generateContent(0);

 // set the scrollbar div to the same height as the table
 var scrollbarHeight = dojo.style.getMarginBoxHeight(dojo.byId("datatable"));
 dojo.style.setMarginBoxHeight(dojo.byId("scrollbar"), scrollbarHeight);
});

There wasn't anything special about the javascript code that you couldn't replace Dojo or Behaviour with your favorite javascript library. You may have noticed that there's isn't any Ajax calls in the code, but hopefully with the comments you can see where it could be implemented.

Here's the complete file.

Enjoy!