Search This Blog

Monday, September 26, 2011

Top Caller Log for Android

Top Caller Log for Android is call log viewer application. It is different from the default call log viewer in that the call log is shown ordered by the total call durations for each unique number. This way it is possible to see where your call minutes are spent the most. It also helps easily call or text message each number from the main screen based on the idea that  you are most probable to interact again with the contact that you already mostly interacted with based on the call duration. This can be accomplished by tapping on respective buttons in a particular row or by tapping and holding on a particular row to bring up a context menu with options.

Tapping on a particular number on the first screen takes you to the second screen where all call details for the particular number is shown ordered based on call duration. It is possible to initiate a call or text message from the second screen also by tapping on the respective buttons at the top or by tap and hold on the screen to bring up a context menu with options.

Shown below are the screen shots of for the Version 1.0 of the application. Please use this blog to report bugs/problems if any.

 

device-2011-09-26-212125       device-2011-09-26-212158

Top Caller Log

Thursday, January 28, 2010

Generating Scrum Task Cards in PDF

Often times teams depend on scrum task cards on a board to track the progress of a project. When the tasks are in Team Foundation Server, Ade Miller describes a method in his blog whereby you could export the query results to excel and use the mail merge feature of Microsoft Word to print out address labels with VSTS work items. That’s a cool trick. But recently I came across the PDFSharp in CodePlex and thought about programmatically generating a PDF file which can be printed and cut into scrum task cards for a project. A bit of programming and I was able to quickly come up with a console application which will do just that!

Code for the console application is given below, when you create the console application project in VS2008 for this code, you will have to download and add reference to PDFSharp assembly. You will also have to add reference to Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.WorkItemTracking.Client.dll.

The console application takes as input a .wiq file containing the query for the tasks and generates a PDF file. By modifying the code as appropriate you can even generate color coded scrum task cards. Have fun!

 

using System;



using System.Collections;



using System.Collections.Generic;



using System.Drawing;



using System.IO;



using System.Linq;



using System.Text;



using System.Xml;



using Microsoft.TeamFoundation.Client;



using Microsoft.TeamFoundation.WorkItemTracking.Client;



using Microsoft.TeamFoundation.WorkItemTracking.Common;



using PdfSharp;



using PdfSharp.Drawing;



using PdfSharp.Drawing.Layout;



using PdfSharp.Pdf;



 



namespace ScrumTaskCardGen



{



    class Program



    {



        static void Main(string[] args)



        {



            if (args.Length < 1)



            {



                Console.WriteLine("Please specify the .wiq file name!");



                return;



            }



 



            FileInfo fileInfo = new FileInfo(args[0]);



 



            if (false == fileInfo.Exists)



            {



                Console.WriteLine("The specified file does not exist!");



                return;



            }



 



            if (false == fileInfo.Extension.Equals(".wiq"))



            {



                Console.WriteLine("Please specify a .wiq file as input!");



                return;



            }



 



            try



            {



                XmlReader reader = XmlReader.Create(fileInfo.FullName);



 



                reader.ReadToFollowing("TeamFoundationServer");



 



                string connection = reader.ReadString();



 



                reader.ReadToFollowing("TeamProject");



 



                string project = reader.ReadString();



 



                reader.ReadToFollowing("Wiql");



 



                string query = reader.ReadString();



 



                GeneratePDF(connection, project, query, fileInfo);



 



            }



            catch (Exception ex)



            {



                Console.WriteLine(ex.ToString());



            }



        }



 



        private static void GeneratePDF(string connection, string project, string dtsQuery, FileInfo wiqlFile)



        {



            TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(connection);



 



            WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));



 



            Hashtable context = new Hashtable();



 



            context.Add("project", project);



 



            WorkItemCollection result = store.Query(dtsQuery, context);



 



            PdfDocument doc = new PdfDocument();



            PdfPage page = doc.AddPage();



            XGraphics grafix = XGraphics.FromPdfPage(page);



            XTextFormatter textFormatter = new XTextFormatter(grafix);



            textFormatter.Alignment = XParagraphAlignment.Center;



 



            int x = 0,



                y = 0;



 



            XBrush blackBrush = XBrushes.Black;



            XPen blackPen = XPens.Black;



 



            XFont font = new XFont("Verdana", 10, XFontStyle.Bold);



 



            for (int i = 0; i < result.Count; i++)



            {



                Point origin = new Point(x, y);



 



                Size size = new Size(Convert.ToInt32(Math.Round(page.Width / 3)), Convert.ToInt32(Math.Round(page.Height / 4)));



 



                Rectangle rect = new Rectangle(origin, size);



 



                float layoutWidth = (float)0.0,



                      layoutHeight = (float)0.0;



 



                layoutWidth = (float)page.Width.Value / 3;



                layoutHeight = (float)page.Height.Value / 4;



 



                RectangleF rectl = new RectangleF((float)x, (float)y+50, layoutWidth, 0);



 



                textFormatter.LayoutRectangle = new XRect((double)x + 10, (double)y + 10, (double)layoutWidth, (double)layoutHeight);



 



                grafix.DrawRectangle(blackPen, rect);



 



                string title = result[i].Title;



 



                if (title.Length > 30)



                {



                    if (title.Length > 60)



                    {



                        title = title.Remove(57);



                        title = title + "...";



                    }



                    title = title.Insert(30, "\r\n");



                }



                



                textFormatter.DrawString(



                    "TaskId = " + result[i].Id + "\r\n\r\n" +



                    title + "\r\n\r\n" +



                    "~ " + result[i].Fields["Assigned To"].Value.ToString().Split(new char[] { ' ' })[0] + " ~",



                    font, blackBrush, rectl, XStringFormats.TopLeft);



 



                x += Convert.ToInt32(Math.Round(page.Width / 3));



 



                if (x >= Convert.ToInt32(Math.Round(page.Width)))



                {



                    x = 0;



 



                    y += Convert.ToInt32(Math.Round(page.Height / 4));



 



                    if (y >= Convert.ToInt32(Math.Round(page.Height)))



                    {



                        y = 0;



                        page = doc.AddPage();



                        grafix = XGraphics.FromPdfPage(page);



                        textFormatter = new XTextFormatter(grafix);



                        textFormatter.Alignment = XParagraphAlignment.Center;



                    }



                }



            }



 



            string[] inputFileNameParts = wiqlFile.Name.Split(new char[] { '.' });



            string outputFileName = inputFileNameParts[0];



            string outputFile = wiqlFile.Directory + "\\" + outputFileName + ".pdf";



 



            doc.Save(outputFile);



            doc.Close();



 



            Console.WriteLine("Generated file " + outputFile);



        }



    }



}


Tuesday, December 22, 2009

Demystifying the Visual Studio trx files

I have been lately working a bit with with the Visual Studio unit testing framework and mstest.exe. One thing about it that confused me is the largely complex trx file format. Looking at the results file of a test run without using Visual Studio or without publishing the results to TFS can be pretty cumbersome. I came across some XSLT files online which can help visualize the test results to a friendly form - which is one way to do it.

I thought it would be better if I could programmatically parse the trx files and generate reports in any form I want. It was fairly easy, since the trx file schema is available with Visual Studio installation. It is named vstst.xsd and can be found under your Visual Studio installation directory. You can easily run the xsd.exe tool on this schema and generate the C# classes to parse the trx files.

Given below is some code for a console application that utilizes the classes generated by the xsd.exe tool to parse all trx files in a given folder and generate a pretty looking excel report.

Be sure to add a reference to Microsoft.Office.Interop.Excel in your project for the below code to work.

   1: class Program



   2: {



   3:     static void Main(string[] args)



   4:     {



   5:         string fileName;



   6:  



   7:         int aborted = 0,



   8:             passed = 0,



   9:             failed = 0,



  10:             notexecuted = 0;



  11:  



  12:         if (args.Length < 1)



  13:         {



  14:             return;



  15:         }



  16:  



  17:         try



  18:         {



  19:             // Construct DirectoryInfo for the folder path passed in as an argument



  20:             DirectoryInfo di = new DirectoryInfo(args[0]);



  21:  



  22:             Excel.Application oXL = null;



  23:             Excel.Workbook oWB;



  24:             Excel.Worksheet oSheet;



  25:      



  26:             // Get a refrence to Excel



  27:             oXL = new Excel.Application();



  28:  



  29:             // Create a workbook and add sheet



  30:             oWB = (Excel.Workbook)oXL.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);



  31:             oSheet = (Excel.Worksheet)oWB.ActiveSheet;



  32:             oSheet.Name = "trx";



  33:             oXL.Visible = true;



  34:             oXL.UserControl = true;



  35:             



  36:             // Write the column names to the work sheet



  37:             oSheet.Cells[1, 1] = "Processed File Name";



  38:             oSheet.Cells[1, 2] = "Test ID";



  39:             oSheet.Cells[1, 3] = "Test Name";



  40:             oSheet.Cells[1, 4] = "Test Outcome";



  41:  



  42:             int row = 2;



  43:  



  44:             // For each .trx file in the given folder process it



  45:             foreach (FileInfo file in di.GetFiles("*.trx"))



  46:             {



  47:  



  48:                 fileName = file.Name;



  49:  



  50:                 // Deserialize TestRunType object from the trx file



  51:                 StreamReader fileStreamReader = new StreamReader(file.FullName);



  52:  



  53:                 XmlSerializer xmlSer = new XmlSerializer(typeof(TestRunType));



  54:  



  55:                 TestRunType testRunType = (TestRunType)xmlSer.Deserialize(fileStreamReader);



  56:  



  57:                 // Navigate to UnitTestResultType object and update the sheet with test result information



  58:                 foreach (object itob1 in testRunType.Items)



  59:                 {



  60:                     ResultsType resultsType = itob1 as ResultsType;



  61:  



  62:                     if (resultsType != null)



  63:                     {



  64:                         foreach (object itob2 in resultsType.Items)



  65:                         {



  66:                             UnitTestResultType unitTestResultType = itob2 as UnitTestResultType;



  67:  



  68:                             if (unitTestResultType != null)



  69:                             {



  70:                                 oSheet.Cells[row, 1] = fileName;



  71:                                 oSheet.Cells[row, 2] = unitTestResultType.testId;



  72:                                 oSheet.Cells[row, 3] = unitTestResultType.testName;



  73:                                 oSheet.Cells[row, 4] = unitTestResultType.outcome;



  74:  



  75:                                 if (0 == unitTestResultType.outcome.CompareTo("Aborted"))



  76:                                 {



  77:                                     oSheet.Rows.get_Range("A" + row.ToString(), "D" + row.ToString()).Interior.Color = System.Drawing.ColorTranslator.ToWin32(Color.Yellow);



  78:                                     aborted++;



  79:                                 }



  80:                                 else if (0 == unitTestResultType.outcome.CompareTo("Passed"))



  81:                                 {



  82:                                     oSheet.Rows.get_Range("A" + row.ToString(), "D" + row.ToString()).Interior.Color = System.Drawing.ColorTranslator.ToWin32(Color.Green);



  83:                                     passed++;



  84:                                 }



  85:                                 else if (0 == unitTestResultType.outcome.CompareTo("Failed"))



  86:                                 {



  87:                                     oSheet.Rows.get_Range("A" + row.ToString(), "D" + row.ToString()).Interior.Color = System.Drawing.ColorTranslator.ToWin32(Color.Red);



  88:                                     failed++;



  89:                                 }



  90:                                 else if (0 == unitTestResultType.outcome.CompareTo("NotExecuted"))



  91:                                 {



  92:                                     oSheet.Rows.get_Range("A" + row.ToString(), "D" + row.ToString()).Interior.Color = System.Drawing.ColorTranslator.ToWin32(Color.SlateGray);



  93:                                     notexecuted++;



  94:                                 }



  95:                                 row++;



  96:                             }



  97:                         }



  98:                     }



  99:                 }



 100:             }



 101:  



 102:             row += 2;



 103:  



 104:             // Add summmary



 105:             oSheet.Cells[row++, 1] = "Testcases Passed = " + passed.ToString();



 106:             oSheet.Cells[row++, 1] = "Testcases Failed = " + failed.ToString();



 107:             oSheet.Cells[row++, 1] = "Testcases Aborted = " + aborted.ToString();



 108:             oSheet.Cells[row++, 1] = "Testcases NotExecuted = " + notexecuted.ToString();



 109:  



 110:             // Autoformat the sheet



 111:             oSheet.Rows.get_Range("A1","D"+row.ToString()).AutoFormat(Excel.XlRangeAutoFormat.xlRangeAutoFormatClassic1,false, false, false, true, false, true);



 112:  



 113:         }



 114:         catch (Exception ex)



 115:         {



 116:             Console.WriteLine(ex.ToString());



 117:         }



 118:     }



 119: }