Blog - Title

Spreadsheet KPart Simulation

Spreadsheet KPart Simulation

  • Comments 3

[Blog Map]  This blog is inactive.  New blog: EricWhite.com/blog

1          Overview

This example demonstrates how to use the elements and attributes for embedded, linked objects as defined in DIS 29500. It shows that the definition is more than adequate for configuring a KPart object that is embedded in a spreadsheet.

The C++ code reads Open XML for a spreadsheet and follows the appropriate rules for processing of SpreadsheetML. The sample spreadsheet includes a linked object in the same way that Microsoft Excel would specify an OLE object, but this code will show how a KPart can be instantiated for that purpose. The program reads the SpreadsheetML for data in the rows and cells and simulates the display of that data in a window. It also reads the definition for a linked object and uses those defined values to create a KPart object of the specified type and position. The C++ code was compiled using gcc on Linux to produce a working executable. The specification for the KPart comes entirely from the SpreadsheetML and can be used to instantiate a variety of different KPart objects without modification to the code.

The code is not intended to demonstrate the functionality of a spreadsheet program, so it has been simplified to read a maximum of ten rows and ten columns. The display of that data is in a simple, read-only grid without gridlines.

The linked object code shows how to instantiate a KPart, but does not fully implement every aspect of OLE processing that a commercial spreadsheet would. For example, a commercial spreadsheet would support the preference to show an image of the embedded object until the user wants to edit the embedded object, then the embedded object would be instantiated and activated for user interaction. This example does show how to use most of the elements including:

·         Using the externalReferences element in workbook.xml to retrieve the id of the external part.

·         Using the XML in container\xl\externalLinks\externalLink1.xml to specify the library (libkhtmlpart) and the part (KHTML).

·         Using the oleObjects and oleObject elements to configure the specific part and the shapeId.

·         Using the shape element in container\xl\drawings\vmlDrawing1.vml to position the embedded object.

The example also shows the accepted method for processing Open XML by retrieving all parts of the document using relationships. Parts are retrieved by their content type or by id as appropriate.

The KPart shown in this example is the HTML browser. The target file is named in the embedded object target. The object allows scrolling through the HTML page and following links from that page. Here is a sample image from the example:

 

The data for each cell is simply 111, 222, 333, and so on for a 3x3 set of rows and columns. As you can see in the following image, the window can be resized to show more of the spreadsheet, but the embedded object keeps its defined absolute location as specified in vmlDrawing1.vml file.

 

2          Implementation Notes

The example has several limitation and caveats as described below. These choices were made to keep the example as comprehensible as possible and to focus on the key elements for object embedding.

·         All of the separate parts of the spreadsheet would normally be contained in a single zipped document file. The example does not access the file in zipped format. Instead, it accesses the parts in their unzipped directory structure. The file name specified for the document is the top directory name (container). A commercial spreadsheet application would need to access the zipped document file directly.

·         If you wish to run the example yourself, you will need to change the absolute file name that appears in externalLink1.xml.res.  The use of an absolute file name in that element is normal for embedded objects.

·         Only the first sheet is processed from the workbook. However, it is processed as a separate Sheet object that could be expanded to handle other sheets.

·         Only one external link reference is processed in the example.

·         The example only demonstrates absolute positioning of the embedded object. The VML file has options for other types of positioning that would normally be implemented in a commercial spreadsheet application.

·         The example has been simplified to assume absolute positioning from the VML file.  Other forms of positioning are left as an exercise for the reader.

·         The example supports the use of UTF-8 characters in much of the XML processing, but may need to be expanded for full support of UTF-8 in its directory and file name manipulations.

3          Markup

This section shows the XML that configures the KPart.

3.1         workbook.xml

Shown below is the workbook, which contains the externalReferences element.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"

          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

    <fileVersion appName="xl"

                 lastEdited="4"

                 lowestEdited="4"

                 rupBuild="4505"/>

    <workbookPr defaultThemeVersion="124226"/>

    <bookViews>

        <workbookView xWindow="600"

                      yWindow="390"

                      windowWidth="19815"

                      windowHeight="11715"/>

    </bookViews>

    <sheets>

        <sheet name="Sheet1"

               sheetId="1"

               r:id="rId1"/>

        <sheet name="Sheet2"

               sheetId="2"

               r:id="rId2"/>

        <sheet name="Sheet3"

               sheetId="3"

               r:id="rId3"/>

    </sheets>

    <externalReferences>

        <externalReference r:id="rId4"/>

    </externalReferences>

    <calcPr calcId="125725"/>

</workbook>

 

3.2         externalLink1.xml

Shown below is the external link XML document, which configures the KPart:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<externalLink xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">

    <oleLink xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"

             r:id="rKp1"

             progId="libkhtmlpart">

        <oleItems>

            <oleItem name="KHTML"

                     advise="1"

                     preferPic="false"/>

        </oleItems>

    </oleLink>

</externalLink>

 

3.3         sheet1.xml

Shown below is sheet1.xml, which specifies the row and cell data.  It also contains the oleObjects and oleObject elements specifying that the embedded KPart is in this sheet.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"

           xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

    <dimension ref="A1"/>

    <sheetViews>

        <sheetView tabSelected="1"

                   workbookViewId="0">

            <selection activeCell="B18"

                       sqref="B18"/>

        </sheetView>

    </sheetViews>

    <sheetFormatPr defaultRowHeight="15"/>

    <sheetData>

        <row r="1"

             spans="1:3">

            <c r="A1">

                <v>111</v>

            </c>

            <c r="B1">

                <v>222</v>

            </c>

            <c r="C1">

                <v>333</v>

            </c>

        </row>

        <row r="2"

             spans="1:3">

            <c r="A2">

                <v>444</v>

            </c>

            <c r="B2">

                <v>555</v>

            </c>

            <c r="C2">

                <v>666</v>

            </c>

        </row>

        <row r="3"

             spans="1:3">

            <c r="A3">

                <v>777</v>

            </c>

            <c r="B3">

                <v>888</v>

            </c>

            <c r="C3">

                <v>999</v>

            </c>

        </row>

    </sheetData>

    <pageMargins left="0.7"

                 right="0.7"

                 top="0.75"

                 bottom="0.75"

                 header="0.3"

                 footer="0.3"/>

    <pageSetup orientation="portrait"

               r:id="rId1"/>

    <legacyDrawing r:id="rId2"/>

    <oleObjects>

        <oleObject progId="libkhtmlpart"

                   link="[1]!'KHTML'"

                   shapeId="1026"/>

    </oleObjects>

</worksheet>

 

3.4         vmlDrawing1.vml

Following is the vmlDrawing1.vml file, which contains the referenced shape element and the positioning information for the KPart.

<xml xmlns:v="urn:schemas-microsoft-com:vml"

     xmlns:o="urn:schemas-microsoft-com:office:office"

     xmlns:x="urn:schemas-microsoft-com:office:excel">

    <o:shapelayout v:ext="edit">

        <o:idmap v:ext="edit"

                 data="1"/>

    </o:shapelayout>

    <v:shapetype id="_x0000_t75"

                 coordsize="21600,21600"

                 o:spt="75"

                 o:preferrelative="t"

                 path="m@4@5l@4@11@9@11@9@5xe"

                 filled="f"

                 stroked="f">

        <v:stroke joinstyle="miter"/>

        <v:formulas>

            <v:f eqn="if lineDrawn pixelLineWidth 0"/>

            <v:f eqn="sum @0 1 0"/>

            <v:f eqn="sum 0 0 @1"/>

            <v:f eqn="prod @2 1 2"/>

            <v:f eqn="prod @3 21600 pixelWidth"/>

            <v:f eqn="prod @3 21600 pixelHeight"/>

            <v:f eqn="sum @0 0 1"/>

            <v:f eqn="prod @6 1 2"/>

            <v:f eqn="prod @7 21600 pixelWidth"/>

            <v:f eqn="sum @8 21600 0"/>

            <v:f eqn="prod @7 21600 pixelHeight"/>

            <v:f eqn="sum @10 21600 0"/>

        </v:formulas>

        <v:path o:extrusionok="f"

                gradientshapeok="t"

                o:connecttype="rect"/>

        <o:lock v:ext="edit"

                aspectratio="t"/>

    </v:shapetype>

    <v:shape id="_x0000_s1026"

             type="#_x0000_t75"

             style='position:absolute;

  margin-left:27pt;margin-top:48.75pt;width:336.75pt;height:150.75pt;z-index:1'

             filled="t"

             fillcolor="window [65]"

             stroked="t"

             strokecolor="windowText [64]"

             o:insetmode="auto">

        <v:fill color2="window [65]"/>

        <v:imagedata o:relid="rId1"

                     o:title=""/>

        <x:ClientData ObjectType="Pict">

            <x:SizeWithCells/>

            <x:Anchor>

                0, 36, 3, 5, 7, 37, 13, 6

            </x:Anchor>

            <x:CF>Pict</x:CF>

            <x:AutoPict/>

            <x:DDE/>

        </x:ClientData>

    </v:shape>

    <v:shape id="_x0000_s1027"

             type="#_x0000_t75"

             style='position:absolute;

  margin-left:48pt;margin-top:255pt;width:6pt;height:13.5pt;z-index:2'

             filled="t"

             fillcolor="window [65]"

             stroked="t"

             strokecolor="windowText [64]"

             o:insetmode="auto">

        <v:fill color2="window [65]"/>

        <v:imagedata o:relid="rId2"

                     o:title=""/>

        <x:ClientData ObjectType="Pict">

            <x:SizeWithCells/>

            <x:Anchor>

                1, 0, 17, 0, 1, 8, 17, 18

            </x:Anchor>

            <x:CF>Pict</x:CF>

            <x:AutoPict/>

            <x:DDE/>

        </x:ClientData>

    </v:shape>

</xml>

 

4          Source Code

This section shows the C++ source code for  the simulated spreadsheet.

4.1         ss_ole.h

Example header file:

 

 

#ifndef __ss_ole_h__

#define __ss_ole_h__

 

#include <libxml/parser.h>

 

#include <kparts/mainwindow.h>

 

typedef char* char_ptr;

typedef xmlChar* xmlCharPtr;

 

class ExternalLink

{

public:

       ExternalLink();

       ~ExternalLink();

      

       bool Load(char* filename);

       bool GetLinkInfo( xmlCharPtr& prog, xmlCharPtr& item, xmlCharPtr& target );

 

protected:

       xmlDocPtr m_doc;

       xmlDocPtr m_rels;

};

 

class Sheet

{

public:

       Sheet();

       ~Sheet();

      

       bool Load(char* filename);

       xmlChar* ShapeId();

       bool GetShapeInfo( xmlChar* shape_id, xmlCharPtr& style, xmlCharPtr& image );

      

       int GetRowCount();

       int GetColumnCount();

       xmlChar* GetCellValue(int row, int col);

      

protected:

       bool LoadSheetData();

      

       xmlDocPtr m_doc;

       xmlDocPtr m_rels;

       xmlDocPtr m_vml_doc;

       xmlDocPtr m_vml_rels;

      

       // Limit of 10 rows and 10 columns for this example

       int m_row_count;

       int m_col_count;

       xmlChar* m_cells[10][10];

};

 

// Used to access the cell data

inline int Sheet::GetRowCount()

{

       return m_row_count;

}

 

inline int Sheet::GetColumnCount()

{

       return m_col_count;

}

 

inline xmlChar* Sheet::GetCellValue(int row, int col)

{

       return m_cells[row][col];

}

 

class Workbook

{

public:

       Workbook();

       ~Workbook();

      

       bool Load( char* filename );

       xmlChar* SheetName();

       xmlChar* SheetId();

       xmlChar* ExternalLinkId();

      

       Sheet* GetSheet();

       ExternalLink* GetExternalLink();

 

protected:

       Sheet* m_sheet;

       ExternalLink* m_link;

       xmlDocPtr m_rels_top;

       xmlDocPtr m_doc;

       xmlDocPtr m_rels;

};

 

inline Sheet* Workbook::GetSheet()

{

       return m_sheet;

}

 

inline ExternalLink* Workbook::GetExternalLink()

{

       return m_link;

}

 

class SheetView : public KParts::MainWindow

{

       Q_OBJECT

public:

       SheetView();

       virtual ~SheetView();

      

       void Layout(Sheet* s, ExternalLink* l);

      

private:

       KParts::ReadOnlyPart* m_kpart;

};

 

#endif

 

4.2         ss_ole.cpp

Example source code:

 

#include "ss_ole.h"

#include <libxml/xmlmemory.h>

#include <string.h>

 

#include <kiconloader.h>

#include <kstandarddirs.h>

#include <kapplication.h>

#include <kaction.h>

#include <klocale.h>

#include <kfiledialog.h>

#include <kmessagebox.h>

#include <kcmdlineargs.h>

#include <klibloader.h>

 

#include <qwidget.h>

#include <qdir.h>

#include <qfile.h>

#include <qlabel.h>

#include <qlayout.h>

 

#include <ktrader.h>

 

#define XML_T_DOC "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"

#define XML_T_VML "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"

#define XML_NS_REL "http://schemas.openxmlformats.org/officeDocument/2006/relationships"

#define XML_NS_VML "urn:schemas-microsoft-com:vml"

#define XML_NS_OFFICE "urn:schemas-microsoft-com:office:office"

 

#define MAXPATH 256

 

// Find the target file name based on the relationship ID

static xmlChar* RelationshipTarget( xmlDocPtr doc, const xmlChar* prop, const xmlChar* value )

{

  if (doc == NULL)

   return NULL;

  xmlNodePtr root = xmlDocGetRootElement(doc);

  xmlNodePtr cur_node;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"Relationship") == 0 && xmlStrcmp(xmlGetProp(cur_node, prop), value) == 0 )

     return xmlGetProp(cur_node, (const xmlChar*)"Target");

  }

  return NULL;

}

 

// Initialize all data for the external link

ExternalLink::ExternalLink()

{

  m_doc = NULL;

  m_rels = NULL;

}

 

// Cleanup allocated objects

ExternalLink::~ExternalLink()

{

  if (m_doc != NULL)

   xmlFreeDoc( m_doc );

  if (m_rels != NULL)

   xmlFreeDoc( m_rels );

}

 

bool ExternalLink::Load(char* filename)

{

  char buffer[MAXPATH];

  char nameonly[MAXPATH];

 

  // Find external link document

  if ( !(m_doc = xmlParseFile(filename)) )

  {

   xmlFreeDoc( m_doc );

   m_doc = NULL;

   return false;

  }

 

  // Parse relationship file associated with external links

  strcpy(buffer, filename);

  char* ptr = strrchr( buffer, '/' );

  strcpy(nameonly, ptr + 1);

  strcpy(ptr + 1, "_rels/");

  strcat(buffer, nameonly);

  strcat(buffer, ".rels");

  if ( !(m_rels = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_rels );

   m_rels = NULL;

   return false;

  }

  return true;

}

 

// Get all the values needed to instantiate a linked object

// prog: The program or library. For KParts, this is the library name

// item: The name of the specific item that will be created

// target: The URL that will be opened by the linked object

bool ExternalLink::GetLinkInfo( xmlCharPtr& prog, xmlCharPtr& item, xmlCharPtr& target )

{

  if (m_doc == NULL || m_rels == NULL)

   return false;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  xmlChar* id;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"oleLink") == 0)

   {

     id = xmlGetNsProp(cur_node, (const xmlChar*)"id", (const xmlChar*)XML_NS_REL);

     prog = xmlGetProp(cur_node, (const xmlChar*)"progId");

     xmlNodePtr temp = cur_node->children;

     if (temp->type == XML_ELEMENT_NODE && xmlStrcmp(temp->name, (const xmlChar*)"oleItems") == 0 )

     {

       temp = temp->children;

       if (temp->type == XML_ELEMENT_NODE && xmlStrcmp(temp->name, (const xmlChar*)"oleItem") == 0 )

       {

         item = xmlGetProp(temp, (const xmlChar*)"name");

         target = RelationshipTarget(m_rels, (const xmlChar*)"Id", id);

         return true;

       }

     }

   }

  }

  return false;

}

 

// Initialize all data for the sheet

Sheet::Sheet()

{

  m_doc = NULL;

  m_rels = NULL;

  m_vml_doc = NULL;

  m_vml_rels = NULL;

  m_row_count = 0;

  m_col_count = 0;

  for (int row = 0; row < 5; row++)

   for (int col = 0; col < 5; col++)

     m_cells[row][col] = (xmlChar*)"";

}

 

// Cleanup allocated objects

Sheet::~Sheet()

{

  if (m_doc != NULL)

   xmlFreeDoc( m_doc );

  if (m_rels != NULL)

   xmlFreeDoc( m_rels );

  if (m_vml_doc != NULL)

   xmlFreeDoc( m_vml_doc );

  if (m_vml_rels != NULL)

   xmlFreeDoc( m_vml_rels );

}

 

bool Sheet::Load(char* filename)

{

  char buffer[MAXPATH];

  char nameonly[MAXPATH];

  char mainpath[MAXPATH];

 

  // Find external link document

  if ( !(m_doc = xmlParseFile(filename)) )

  {

   xmlFreeDoc( m_doc );

   m_doc = NULL;

   return false;

  }

 

  // Open relationship file associated with sheet

  strcpy(buffer, filename);

  char* ptr = strrchr( buffer, '/' );

  strcpy(nameonly, ptr + 1);

  ptr[1] = '\0';

  strcpy(mainpath, buffer);

  strcat( buffer, "_rels/" );     

  strcat( buffer, nameonly );

  strcat( buffer, ".rels" );

  if ( !(m_rels = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_rels );

   m_rels = NULL;

   return false;

  }

 

  // Open VML target from sheet relationships

  xmlChar* target = RelationshipTarget(m_rels, (xmlChar*)"Type", (xmlChar*)XML_T_VML);

  strcpy(buffer, mainpath);

  strcat(buffer, (char*)target);

  if ( !(m_vml_doc = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_vml_doc );

   m_vml_doc = NULL;

   return false;

  }

 

  // Open relationship file associated with VML

  ptr = strrchr( buffer, '/' );

  strcpy(nameonly, ptr + 1);

  strcpy(ptr + 1, "_rels/");

  strcat(buffer, nameonly);

  strcat(buffer, ".rels");

  if ( !(m_vml_rels = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_vml_rels );

   m_vml_rels = NULL;

   return false;

  }

 

  return LoadSheetData();

}

 

// Scan for oleObject and return the shapeId property value

xmlChar* Sheet::ShapeId()

{

  if (m_doc == NULL)

   return NULL;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"oleObjects") == 0)

   {

     for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next)

     {

       if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"oleObject") == 0)

         return xmlGetProp(cur_node, (const xmlChar*)"shapeId");

     }

   }

  }

  return NULL;

}

 

// Get all the VML drawing values needed, based on the specified id

// style: information about how to position the drawing/object

// image: Target for the picture that can be used instead of the linked object

bool Sheet::GetShapeInfo(xmlChar* shape_id, xmlCharPtr& style, xmlCharPtr& image)

{

  if (m_vml_doc == NULL || m_vml_rels == NULL)

   return false;

  xmlNodePtr root = xmlDocGetRootElement(m_vml_doc);

  xmlNodePtr cur_node;

  xmlChar* id;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"shape") == 0 && xmlStrcmp(cur_node->ns->href, (const xmlChar*)XML_NS_VML) == 0)

   {

     id = xmlGetProp(cur_node, (const xmlChar*)"id");

     // Match only the end of the shape id, since it has a prefix on it.

     if (xmlStrcmp(id + xmlStrlen(id) - xmlStrlen(shape_id), shape_id) == 0)

     {

       style = xmlGetProp(cur_node, (const xmlChar*)"style");

       for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next)

       {

         if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"imagedata") == 0 && xmlStrcmp(cur_node->ns->href, (const xmlChar*)XML_NS_VML) == 0 )

         {

          id = xmlGetNsProp(cur_node, (const xmlChar*)"relid", (const xmlChar*)XML_NS_OFFICE);

          image = RelationshipTarget(m_vml_rels, (xmlChar*)"Id", id);

          return true;

         }

       }

       return false;

     }

   }

  }

  return false;

}

 

// Scans through the sheet XML to find all the cell values for the spreadsheet.

// This example is limited to only 10 rows and 10 columns.

bool Sheet::LoadSheetData()

{

  if (m_doc == NULL)

   return false;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  xmlNodePtr row_node;

  xmlNodePtr col_node;

  xmlNodePtr val_node;

  m_row_count = 0;

  m_col_count = 0;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

    if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheetData") == 0 )

   {

     for (row_node = cur_node->children; row_node; row_node = row_node->next)

     {

       if (row_node->type == XML_ELEMENT_NODE && xmlStrcmp(row_node->name, (const xmlChar*)"row") == 0 )

       {

         for (col_node = row_node->children; col_node; col_node = col_node->next)

         {

          if (col_node->type == XML_ELEMENT_NODE && xmlStrcmp(col_node->name, (const xmlChar*)"c") == 0 )

          {

            xmlChar* cell = xmlGetProp(col_node, (const xmlChar*)"r");

            int column = (char)cell[0] - 'A';

            int row = (char)cell[1] - '1';

            if ( column >= 10 || row >= 10 )

              return false;

            if (col_node->children->type == XML_ELEMENT_NODE && xmlStrcmp(col_node->children->name, (const xmlChar*)"v") == 0)

            {

              m_cells[row][column] = col_node->children->children->content;

              if (row + 1 > m_row_count)

                     m_row_count = row + 1;

              if (column + 1 > m_col_count)

                     m_col_count = column + 1;

            }

          }

         }

       }

     }

     break;

   }

  }

  return true;

}

 

// Initialize all data for the workbook

Workbook::Workbook()

{

  m_rels_top = NULL;

  m_doc = NULL;

  m_rels = NULL;

}

 

// Cleanup allocated objects

Workbook::~Workbook()

{

  if (m_sheet != NULL)

   delete m_sheet;

  if (m_link != NULL)

   delete m_link;

  if (m_rels_top != NULL)

   xmlFreeDoc( m_rels_top );

  if (m_doc != NULL)

   xmlFreeDoc( m_doc );

  if (m_rels != NULL)

   xmlFreeDoc( m_rels );

}

 

// Read through all the connected files and load as DOC structures

// Actual "xlsx" files would be zipped instead of the directory

// structure used here, but the zip file has the same structure.

bool Workbook::Load( char* filename )

{

  char buffer[MAXPATH];

  char main_path[MAXPATH];

  char nameonly[MAXPATH];

 

  // Open top relationships

  strcpy( buffer, filename );

  strcat( buffer, "/_rels/.rels" );

  if ( !(m_rels_top = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_rels_top );

   m_rels_top = NULL;

   return false;

  }

 

  // Open workbook document

  xmlChar* target = RelationshipTarget( m_rels_top, (xmlChar*)"Type",  (xmlChar*)XML_T_DOC );

  strcpy( buffer, filename );

  strcat( buffer, "/" );

  strcat( buffer, (char*)target );

  if ( !(m_doc = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_doc );

   m_doc = NULL;

   return false;

  }

 

  // Open relationship file associated with workbook

  char* ptr = strrchr( buffer, '/' );

  strcpy(nameonly, ptr + 1);

  ptr[1] = '\0';

  strcpy(main_path, buffer);

  strcat( buffer, "_rels/" );     

  strcat( buffer, nameonly );

  strcat( buffer, ".rels" );

  if ( !(m_rels = xmlParseFile(buffer)) )

  {

   xmlFreeDoc( m_rels );

   m_rels = NULL;

   return false;

  }

 

  // Create ExternalLink object

  target = RelationshipTarget(m_rels, (xmlChar*)"Id", ExternalLinkId());

  strcpy( buffer, main_path );

  strcat( buffer, (char*)target );

  m_link = new ExternalLink();

  if (!m_link->Load(buffer))

   return false;

 

  // Open first sheet document

  target = RelationshipTarget(m_rels, (xmlChar*)"Id", SheetId());

  strcpy( buffer, main_path );

  strcat( buffer, (char*)target );

  m_sheet = new Sheet();

  if (!m_sheet->Load(buffer))

   return false;

  return true;

}

 

// Scans DOC model for the first specified sheet. Multiple sheets are not supported in this example.

xmlChar* Workbook::SheetName()

{

  if (m_doc == NULL)

   return NULL;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheets") == 0)

   {

     for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next)

     {

       if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheet") == 0)

         return xmlGetProp(cur_node, (const xmlChar*)"name");

     }

   }

  }

  return NULL;

}

 

// Scan for the relationship ID for the first sheet.

xmlChar* Workbook::SheetId()

{

  if (m_doc == NULL)

   return NULL;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheets") == 0)

   {

     for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next)

     {

       if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheet") == 0)

         return xmlGetNsProp(cur_node, (const xmlChar*)"id", (const xmlChar*)XML_NS_REL);

     }

   }

  }

  return NULL;

}

 

// Scan for the relationship ID of the first external link. Multiple links are not supported in this example.

xmlChar* Workbook::ExternalLinkId()

{

  if (m_doc == NULL)

   return NULL;

  xmlNodePtr root = xmlDocGetRootElement(m_doc);

  xmlNodePtr cur_node;

  for (cur_node = root->children; cur_node; cur_node = cur_node->next)

  {

   if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"externalReferences") == 0)

   {

     for (cur_node = cur_node->children; cur_node; cur_node = cur_node->next)

     {

       if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"externalReference") == 0)

         return xmlGetNsProp(cur_node, (const xmlChar*)"id", (const xmlChar*)XML_NS_REL);

     }

   }

  }

  return NULL;

}

 

// Set up the window with just a Quit action.

SheetView::SheetView()

{

  char dir[PATH_MAX + 20];

  getcwd(dir,PATH_MAX);

  strcat(dir, "/sheet_view.rc");

  setXMLFile( dir );

 

  KAction * paQuit = new KAction( "&Quit" , "exit", 0, this, SLOT( close() ), actionCollection(), "file_quit" );

}

 

// Cleanup KPart

SheetView::~SheetView()

{

  delete m_kpart;

}

 

// Use the values from the Workbook object to simulate the appearance of a spreadsheet.

// If there is a linked object, it will replace the bottom-right cell.

void SheetView::Layout(Sheet* s, ExternalLink* l)

{

  QFrame* frame = new QFrame(this);

  QGridLayout* layout = new QGridLayout( frame, s->GetRowCount(), s->GetColumnCount() );

 

  for ( int row = s->GetRowCount() - 1; row >= 0; row-- )

   for ( int col = s->GetColumnCount() - 1; col >= 0; col-- )

   {

     QLabel* label = new QLabel( (char*)s->GetCellValue(row, col), frame );

     label->setAlignment( Qt::AlignRight );

     label->setMinimumSize( label->sizeHint() );

     layout->addWidget( label, row, col );

   }

 

  xmlChar* progname;

  xmlChar* itemname;

  xmlChar* target;

  xmlChar* style;

  xmlChar* image;

  if (s->GetShapeInfo(s->ShapeId(), style, image) && l->GetLinkInfo( progname, itemname, target ))

  {

   // Just for reference, here is the image file name to use if showing just

   // the picture instead of the embedded object

   printf("VML image file is: %s\n", image);

  

   // Find position and size from the style string

   // In this example, we do not check for "position:absolute" since it

   // is the only option supported.

   // The suffix "pt" is also assumed since only conversion from points

   // to pixels is performed.

   int x = 0;

   int y = 0;

   int w = 100;

   int h = 100;

   char* cur_token = strtok((char*)style, " ;\t");

   while (cur_token != NULL)

   {

     if (strncmp(cur_token, "margin-left:", 12) == 0)

     {

       x = (int)(atof(cur_token + 12) * 96 / 72 + 0.5);

     }

     else if (strncmp(cur_token, "margin-top:", 11) == 0)

     {

       y = (int)(atof(cur_token + 11) * 96 / 72 + 0.5);

     }

     else if (strncmp(cur_token, "width:", 6) == 0)

     {

       w = (int)(atof(cur_token + 6) * 96 / 72 + 0.5);

     }

     else if (strncmp(cur_token, "height:", 7) == 0)

     {

       h = (int)(atof(cur_token + 7) * 96 / 72 + 0.5);

     }

     cur_token = strtok(NULL, " ;\t");

   }

   KLibFactory* factory = KLibLoader::self()->factory( (char*)progname );

   if ( factory )

   {

     m_kpart = (KParts::ReadOnlyPart*)factory->create(frame, (char*)itemname, "KParts::ReadOnlyPart");

     if ( m_kpart != NULL )

     {

       m_kpart->widget()->setGeometry(x, y, w, h);

       createGUI( m_kpart );

       m_kpart->openURL( (char*)target );

     }

   }

 

  }

  layout->activate();

  setCentralWidget( frame );

  resize(400,300);

}

 

// Loads a workbook and sets up the window that will display a sheet in that workbook.

int main( int argc, char** argv )

{

  KCmdLineArgs::init(argc, argv, "ss_ole", "Object Linking example", "v1.1");

  Workbook* w = new Workbook();

  if (!w->Load( "container" ))

   return -1;

  KApplication appl;

  SheetView* view = new SheetView();

  view->Layout(w->GetSheet(), w->GetExternalLink());

  view->show();

  return appl.exec();

}

 

#include "ss_ole.moc"

 

 

4.3         ssole.moc

This file is created directly from ss_ole.h using the moc program.

4.5         RELEASE-NOTES.en.html

Of course, the example can be run with any HTML file. The sample file comes from the SUSE release notes.

 

Leave a Comment
  • Please add 8 and 7 and type the answer here:
  • Post
Page 1 of 1 (3 items)