Blog Map
[Blog Map] This blog is inactive. New blog: EricWhite.com/blog
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.
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.
This section shows the XML that configures the KPart.
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>
Shown below is the external link XML document, which configures the KPart:
<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>
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.
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
<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 r="C1">
<v>333</v>
</row>
<row r="2"
<c r="A2">
<v>444</v>
<c r="B2">
<v>555</v>
<c r="C2">
<v>666</v>
<row r="3"
<c r="A3">
<v>777</v>
<c r="B3">
<v>888</v>
<c r="C3">
<v>999</v>
</sheetData>
<pageMargins left="0.7"
right="0.7"
top="0.75"
bottom="0.75"
header="0.3"
footer="0.3"/>
<pageSetup orientation="portrait"
<legacyDrawing r:id="rId2"/>
<oleObjects>
<oleObject progId="libkhtmlpart"
link="[1]!'KHTML'"
shapeId="1026"/>
</oleObjects>
</worksheet>
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"
margin-left:48pt;margin-top:255pt;width:6pt;height:13.5pt;z-index:2'
<v:imagedata o:relid="rId2"
1, 0, 17, 0, 1, 8, 17, 18
</xml>
This section shows the C++ source code for the simulated spreadsheet.
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
Sheet();
~Sheet();
xmlChar* ShapeId();
bool GetShapeInfo( xmlChar* shape_id, xmlCharPtr& style, xmlCharPtr& image );
int GetRowCount();
int GetColumnCount();
xmlChar* GetCellValue(int row, int col);
bool LoadSheetData();
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
Workbook();
~Workbook();
bool Load( char* filename );
xmlChar* SheetName();
xmlChar* SheetId();
xmlChar* ExternalLinkId();
Sheet* GetSheet();
ExternalLink* GetExternalLink();
Sheet* m_sheet;
ExternalLink* m_link;
xmlDocPtr m_rels_top;
inline Sheet* Workbook::GetSheet()
return m_sheet;
inline ExternalLink* Workbook::GetExternalLink()
return m_link;
class SheetView : public KParts::MainWindow
Q_OBJECT
SheetView();
virtual ~SheetView();
void Layout(Sheet* s, ExternalLink* l);
private:
KParts::ReadOnlyPart* m_kpart;
#endif
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");
// 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)) )
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)) )
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)
xmlNodePtr root = xmlDocGetRootElement(m_doc);
xmlChar* id;
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);
// Initialize all data for the sheet
Sheet::Sheet()
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*)"";
Sheet::~Sheet()
if (m_vml_doc != NULL)
xmlFreeDoc( m_vml_doc );
if (m_vml_rels != NULL)
xmlFreeDoc( m_vml_rels );
bool Sheet::Load(char* filename)
char mainpath[MAXPATH];
// Open relationship file associated with sheet
ptr[1] = '\0';
strcpy(mainpath, buffer);
strcat( buffer, "_rels/" );
strcat( buffer, nameonly );
strcat( buffer, ".rels" );
// 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)) )
// Open relationship file associated with VML
ptr = strrchr( buffer, '/' );
if ( !(m_vml_rels = xmlParseFile(buffer)) )
return LoadSheetData();
// Scan for oleObject and return the shapeId property value
xmlChar* Sheet::ShapeId()
if (m_doc == NULL)
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");
// 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)
xmlNodePtr root = xmlDocGetRootElement(m_vml_doc);
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");
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);
// 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()
xmlNodePtr row_node;
xmlNodePtr col_node;
xmlNodePtr val_node;
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 )
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;
// Initialize all data for the workbook
Workbook::Workbook()
m_rels_top = NULL;
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 );
// 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 main_path[MAXPATH];
// Open top relationships
strcpy( buffer, filename );
strcat( buffer, "/_rels/.rels" );
if ( !(m_rels_top = xmlParseFile(buffer)) )
// Open workbook document
xmlChar* target = RelationshipTarget( m_rels_top, (xmlChar*)"Type", (xmlChar*)XML_T_DOC );
strcat( buffer, "/" );
strcat( buffer, (char*)target );
if ( !(m_doc = xmlParseFile(buffer)) )
// Open relationship file associated with workbook
strcpy(main_path, buffer);
// Create ExternalLink object
target = RelationshipTarget(m_rels, (xmlChar*)"Id", ExternalLinkId());
strcpy( buffer, main_path );
m_link = new ExternalLink();
if (!m_link->Load(buffer))
// Open first sheet document
target = RelationshipTarget(m_rels, (xmlChar*)"Id", SheetId());
m_sheet = new Sheet();
if (!m_sheet->Load(buffer))
// Scans DOC model for the first specified sheet. Multiple sheets are not supported in this example.
xmlChar* Workbook::SheetName()
if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheets") == 0)
if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"sheet") == 0)
return xmlGetProp(cur_node, (const xmlChar*)"name");
// Scan for the relationship ID for the first sheet.
xmlChar* Workbook::SheetId()
return xmlGetNsProp(cur_node, (const xmlChar*)"id", (const xmlChar*)XML_NS_REL);
// Scan for the relationship ID of the first external link. Multiple links are not supported in this example.
xmlChar* Workbook::ExternalLinkId()
if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"externalReferences") == 0)
if (cur_node->type == XML_ELEMENT_NODE && xmlStrcmp(cur_node->name, (const xmlChar*)"externalReference") == 0)
// 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"
This file is created directly from ss_ole.h using the moc program.
Of course, the example can be run with any HTML file. The sample file comes from the SUSE release notes.
The myth that Open XML's object embedding model is not compatible with KParts is much like the reanimated
Can you please post the entire document?
I am having problems recreating it from these instructions.
Thank you
The entire source code is posted.
Here are the links for a tutorial on developing a KPart:
http://developer.kde.org/documentation/books/kde-2.0-development/index.html
http://developer.kde.org/documentation/books/kde-2.0-development/ch12.html
These are KDE 2.0 and the example is 3.0. I never found a comparable document for 3.0, but I did find a website that had the source for the same tutorial example for KDE 3.0. It would take me some time to locate that site again, but I think it was one of the main developer sites for KDE.