How can I programmatically detect complex scipt using OOXML? - ms-word

We are using Windward to generate reports in Microsoft Word.
Due to some update, Unicode Characters are no longer displaying properly.
While the vendor is still looking for a fix, we're looking for a work around.
One Symptom that I've noticed is that the "Normal" style does not appear in the "Styles Gallery" on the Ribbon.
I can find it in the "styles.xml" part of the file. I noticed that the style does not have a RSID associated with it, the way a normal MS Word file would.
GOOD FILE "Normal" style appears in Gallery
<w:style w:type="paragraph" w:styleId="Normal" w:default="1">
<w:name w:val="Normal" />
<w:qFormat />
<w:rsid w:val="003C4F1E" />
</w:style>
BAD FILE "Normal" style does NOT appear in Gallery
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
</w:style>
Modifying the the Styles.xml file so that the "Normal" style would have rsid as well as qFormat xml tags fixed the issue of getting the "Normal" style to appear in the Gallery.
What I noticed was that once I had the "Normal" reappear and I clicked it without first having to select any text in the document, the Unicode Characters would display correctly.
When I checked document.xml I noticed that the following xml was added before the run:
<w:rPr>
<w:rFonts w:ascii="Mangal" w:hAnsi="Mangal" w:cs="Mangal"/>
</w:rPr>
How did MS Word know to select those values for the runPoperty?
How can I use ooxml to detect Complex script and then make the appropriate font selection?
SAMPLE XML USING COMPLEX SCRIPT
<w:r>
<w:rPr>
<w:rFonts w:ascii="Mangal" w:hAnsi="Mangal" w:cs="Mangal"/>
</w:rPr>
<w:t>एनडीटीवी</w:t>
</w:r>
What I have so far.
static bool GetRunText()
{
bool bStylesFound = false;
using (WordprocessingDocument doc = WordprocessingDocument.Open(_path, false))
{
// Get a reference to the main document part.
var docPart = doc.MainDocumentPart;
// Get the first paragraph.
Paragraph p = docPart.Document.Body.Descendants<Paragraph>().ElementAtOrDefault(0);
if (p == null)
{
Console.WriteLine("No paragraphs found.");
}
else
{
Run run = p.Descendants<Run>().ElementAtOrDefault(1);
RunProperties rp = run.RunProperties;
//Console.WriteLine(rp.RunFonts.);
bStylesFound = true;
}
return bStylesFound;
}
}

Related

How can I add text to a document footer using OpenXML?

I have a document template that I want to append some text to the footer. I've seen ways of deleting the footer to replace it, and ways to replace text in the footer, but I want to keep the footer as is from the template and just add to it. I have code to add text to the main doc., but unfortunately, main doc. parts are not setup the same way as footer parts. This is easily accomplished in Interop by a range.InsertAfter(text), but end users need this to work sans Word.
FooterPart footer = _doc.MainDocumentPart.FooterParts.ElementAtOrDefault(0);
string rid = _doc.MainDocumentPart.GetIdOfPart(footer);
footer = _doc.MainDocumentPart.AddNewPart<FooterPart>(rid);
Paragraph para = footer.AddPart(new Paragraph(), rid);
Run run = para.AppendChild(new Run());
// get the last footer of the document
FooterPart footerPart = _doc.MainDocumentPart.FooterParts.LastOrDefault();
// create your paragraph. i created simple, but you will need to add style properties to the run or text class
Paragraph pr = new Paragraph(new Run(new Text("hello")));
// Insert the Paragraph to the end of the footer in footerPart.Footer
footerPart.Footer.AppendChild(pr);
Other way as you said would be putting a text to replace like "txttoreplace" and then you will find it and replace
IEnumerable<FooterPart> footerPartsList = Documento.MainDocumentPart.FooterParts.ToList();
foreach (FooterPart hp in footerPartsList)
foreach (Text text in hp.RootElement.Descendants<Text>())
{
if (text.Text.Contains("txttoreplace"))
{
text.Text = text.Text.Replace("txttoreplace", "new text");
}
}
And another way and the hardest would be, you inser the whole footer, with open xml productivity tools you get the c# code of the footer.xml, and then you delete the footer of the document and you insert.

iText(Sharp) - how to avoid creating a blank page?

I'm generating a PDF document using iTextSharp version 5.5.7, using their "streaming" mode - by which I mean I'm not specifying the location of every piece of text, I'm just adding Paragraphs to the Document and letting iTextSharp figure out where to draw them. The text I'm outputting is the result of a report generator, so it is different every time.
The problem I'm running into is this: imagine that, given the page size and the selected font, I can fit 40 lines of text on a page. I output 40 Paragraphs, then I output a blank Paragraph (contents=" "), then an image that fills an entire page. iTextSharp does exactly what I tell it - I end up with one page full of text, a blank page, and then a page containing my image.
But now my document looks funny - there is this unexpectedly blank page in the middle of everything.
I can't just say "don't output any blank lines" because of course that blank line might show up after only 20 lines of text, in which case it has to be there. I need some way to either tell iTextSharp "include this paragraph only if it's not the only thing on a page" or else somehow detect that the page is blank in OnEndPage() and suppress its output (without screwing up my page numbers).
Any suggestions on how I can do this?
ADDED LATER
Output from the report generator:
<html>
<p>Information header</p>
<p>Detail</p>
<p>Detail</p>
<p>Detail</p>
<p></p> <!-- Blank line inserted by report generator for clarity -->
<p>Information header</p>
<p>Detail</p>
<p>Detail</p>
<p>Detail</p>
...
<p>Detail</p> <!-- just by random happenstance this is the last line that will fit on the first page -->
<p></p> <!-- This line happens to be blank, I have no control over it -->
<img src="blah blah"></image>
My (pseudo) code:
foreach (HtmlNode node in htmlFromReportGenerator)
{
if (node is text)
pdfDoc.Add(new Paragraph(node.text));
else if (node is image)
pdfDoc.Add(new Image(node.image));
}
Following Bruno's suggestion, my (pseudo)code now looks like this:
Paragraph lastParagraph = null;
foreach (HtmlNode node in htmlFromReportGenerator)
{
if (node is text)
{
Paragraph parg = new Paragraph(node.text);
if ( (lastParagraph != null) && (text.Trim().Length == 0) )
lastParagraph.SpacingAfter += parg.Leading;
else
{
pdfDoc.Add(parg);
lastParagraph = parg;
}
}
else if (node is image)
{
pdfDoc.Add(new Image(node.image));
lastParagraph = null;
}
}

Titanium Alloy ListView XML Uncaught TypeError: Object #<UI> has no method 'createTemplates'

I am new to Titanium, so excuse my lack of understanding.
Even though I am using sdk version 3.2 (have sdk-version: 3.2.0.v20130801162445 in my tiapp.xml) when I try and have a view that uses the xml above I get this error:
[ERROR][V8Exception( 615)] Exception occurred at alloy/controllers/feed.js:22: Uncaught TypeError: Object # has no method 'createTemplates'
I cut down all my code so that the feed.js file is just:
function loadMoreBtnClicked(_event) {
alert('not implemented yet');
}
function createListView(_data) {
// this is pretty straight forward, assigning the values to the specific
// properties in the template we defined above
var items = [];
for (var i in _data) {
// add items to an array
items.push({
template : "template1", // set the template
textLabel : {
text : _data[i].name // assign the values from the data
},
pic : {
image : _data[i].pic_square // assign the values from the data
}
});
}
// add the array, items, to the section defined in the feed.xml file
$.section.setItems(items);
}
alert('feed loaded');
The XML is in feed.xml and looks like this:
<Alloy>
<Window class="container" formFactor="handheld">
<ListView id="list" defaultItemTemplate="template1">
<Templates>
<ItemTemplate name="buttonItem" height="Ti.UI.SIZE">
<!-- will use this in the next blog post -->
<Button id="loadMoreBtn" onClick="loadMoreBtnClicked">Load More</Button>
</ItemTemplate>
<!-- main template for displaying the list items -->
<ItemTemplate id="template1" name="template1" class="template1">
<ImageView id="pic" bindId="pic" class="imageThumb"/>
<View id="textContainer">
<Label id="textLabel" bindId="textLabel" class="title"/>
</View>
</ItemTemplate>
</Templates>
<!-- we only have one section and the items are contstucted using template1 -->
<ListSection id="section" >
<ListItem template="template1" />
</ListSection>
</ListView>
</Window>
</Alloy>
I still get the error (just using the XML with no actual controller code other than the alert running). If I pull the ListView XML out of the feed.xml file the alert fires, when I put the ListView XML back in I get the Error above.
I am trying to use code from this example:
https://gist.github.com/aaronksaunders/5896390
but cant really tell what I am missing?
Thanks!
-James
found out what the issue was, my problem had to do with not having the updated version of alloy that is needed to support the ListView Templates in XML. I needed to run this at the command line in Windows: "npm install -g alloy#1.2.0-alpha" (without quotes). After that I was able to use ListView templates in XML as shown above.

OpenXml - How to identify whether the paragraph extends to next page

From aspx page, I dynamically add paragraphs to a word document using OpenXml SDK. In this case, a page break within a paragraph is not allowed. So in case a paragraph starts in middle of page 1 and extends to page2 then it should actually start in Page2. However, if it ends in the same page it is okay.
How to achieve this? Is there a way to set in th document that page break is not allowed within a paragraph? Any input is highly appreciated.
In general you can not use the open xml sdk to determine where in a page an element will be displayed, since open xml has no concepts of pages.
Pages are determined by the client application consuming the open xml document. You can however specify that a paragraph's lines are kept together.
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:pPr>
<w:keepLines />
</w:pPr>
<w:bookmarkStart w:name="_GoBack" w:id="0" />
<w:r>
<w:lastRenderedPageBreak />
<w:t>Most controls offer a choice of using the look from the current theme or using a format that you specify directly. To change the overall look of your document, choose new your document.</w:t>
</w:r>
<w:bookmarkEnd w:id="0" />
</w:p>
w:keepLines in the above examples paragraph properties is the key to making sure a paragraph is not split up between pages, below is the open xml required to generate the above paragrpah:
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
namespace GeneratedCode
{
public class GeneratedClass
{
// Creates an Paragraph instance and adds its children.
public Paragraph GenerateParagraph()
{
Paragraph paragraph1 = new Paragraph();
ParagraphProperties paragraphProperties1 = new ParagraphProperties();
KeepLines keepLines1 = new KeepLines();
paragraphProperties1.Append(keepLines1);
BookmarkStart bookmarkStart1 = new BookmarkStart(){ Name = "_GoBack", Id = "0" };
Run run1 = new Run();
LastRenderedPageBreak lastRenderedPageBreak1 = new LastRenderedPageBreak();
Text text1 = new Text();
text1.Text = "Most controls offer a choice of using the look from the current theme or using.";
run1.Append(lastRenderedPageBreak1);
run1.Append(text1);
BookmarkEnd bookmarkEnd1 = new BookmarkEnd(){ Id = "0" };
paragraph1.Append(paragraphProperties1);
paragraph1.Append(bookmarkStart1);
paragraph1.Append(run1);
paragraph1.Append(bookmarkEnd1);
return paragraph1;
}
}
}

How to set different localized string in different visual states in WP7 using Blend?

How do I set different localized strings in different visual states in WP7 using Blend without any code behind?
I can set different non-localized strings in different visual states (although it flickers). That works, but how about localized strings?
If I change the string using data binding in Blend, Blend just overrides the data binding in Base state and not the actual state where I'm recording.
EDIT:
This is how I localize my strings:
I have a resources file named AppPresources.resx. Then I would do this in code:
// setting localized button title
mainButton.Content = AppResources.MainButtonText;
Then I have a GlobalViewModelLocator from MVVM Light Toolkit with the following Property for Databinding.
private static AppResources _localizedStrings;
public AppResources LocalizedStrings
{
get
{
if (_localizedStrings == null)
{
_localizedStrings = new AppResources();
}
return _localizedStrings;
}
}
And in xaml file:
<Button x:Name="mainButton" Content="{Binding LocalizedStrings.MainButtonText, Mode=OneWay, Source={StaticResource Locator}}" ... />
What you need to do, is very close to what you're already doing. First, define a class named Resources.cs with following content
public class Resources
{
private static AppResources resources = new AppResources();
public AppResources LocalizedStrings
{
get
{
return resources;
}
}
}
This allows us to create a instance of your Resource File in XAML. To do this, open App.xaml and add following
<Application.Resources>
<local:Resources x:Key="Resources" />
</Application.Resources>
Now when you need to do bindings in your XAML, you do it like this:
<Button Content="{Binding LocalizedStrings.MainButtonText,
Source={StaticResource Resources}}" />
What you'll notice is that it doesn't work in Blend, yet. To make it work in Expression Blend,
add the following file: DesignTimeResources.xaml in the Properties Folder, and add following content
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNameSpace">
<local:Resources x:Key="Resources" />
</ResourceDictionary>
Now, you press F6 in Visual Studio to recompile, and voila, your localized strings are available in Expression Blend!
A real-world example from one of my projects:
AppResources.cs
DesignTimeResources.xaml
App.xaml