/****************************************************************************** |* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF |* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO |* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A |* PARTICULAR PURPOSE. |* |* Copyright 1995-2005 Nero AG. All Rights Reserved. |*----------------------------------------------------------------------------- |* NeroSDK / NVAPIExample |* |* PROGRAM: PageFirst.cpp |* |* PURPOSE: Implementation of the first page. ******************************************************************************/ #include "stdafx.h" #include "NVAPIExample.h" #include "PageFirst.h" #include "PageData.h" #include "Sheet.h" #include "NVAPIExampleDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // This is our custom message. // #define UM_QUIT_WITH_DELAY (WM_APP + 1) CPageFirst::CPageFirst(CSheet * pParent) : CPage(CPageFirst::IDD, pParent) , m_iVideoItemSequence (1) , m_iSlideshowItemSequence (1) , m_iVideoStreamSequence (1) , m_bLoadAndBurn (false) { //{{AFX_DATA_INIT(CPageFirst) m_iProjectType = 0; m_iEncodingType = 0; //}}AFX_DATA_INIT } void CPageFirst::DoDataExchange(CDataExchange* pDX) { CPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CPageFirst) DDX_Control(pDX, IDC_INSERT_AUDIOSTREAM, c_InsertAudioStream); DDX_Control(pDX, IDC_INSERT_VIDEOSTREAM, c_InsertVideoStream); DDX_Control(pDX, IDC_ENCODING_TYPE, c_EncodingType); DDX_Control(pDX, IDC_REMOVEALL, c_RemoveAll); DDX_Control(pDX, IDC_EXPORT, c_Export); DDX_Control(pDX, IDC_PREVIEW, c_Preview); DDX_Control(pDX, IDC_INSERT_AUDIO, c_InsertAudio); DDX_Control(pDX, IDC_SAVE, c_Save); DDX_Control(pDX, IDC_REMOVE, c_Remove); DDX_Control(pDX, IDC_PROJECT_TYPE, c_ProjectType); DDX_Control(pDX, IDC_LOAD, c_Load); DDX_Control(pDX, IDC_INSERT_VIDEO, c_InsertVideo); DDX_Control(pDX, IDC_INSERT_SLIDE, c_InsertSlide); DDX_Control(pDX, IDC_INSERT_IMAGE, c_InsertImage); DDX_Control(pDX, IDC_TRANSITION_TYPE, c_TransitionType); DDX_Control(pDX, IDC_CONTENT, c_Content); DDX_CBIndex(pDX, IDC_PROJECT_TYPE, m_iProjectType); DDX_CBIndex(pDX, IDC_ENCODING_TYPE, m_iEncodingType); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CPageFirst, CPage) //{{AFX_MSG_MAP(CPageFirst) ON_BN_CLICKED(IDC_LOAD, OnLoad) ON_BN_CLICKED(IDC_SAVE, OnSave) ON_BN_CLICKED(IDC_INSERT_VIDEO, OnInsertVideo) ON_BN_CLICKED(IDC_REMOVE, OnRemove) ON_BN_CLICKED(IDC_INSERT_SLIDE, OnInsertSlide) ON_NOTIFY(TVN_SELCHANGED, IDC_CONTENT, OnSelchangedContent) ON_CBN_SELCHANGE(IDC_TRANSITION_TYPE, OnSelchangeTransitionType) ON_BN_CLICKED(IDC_INSERT_IMAGE, OnInsertImage) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_CONTENT, OnBeginlabeleditContent) ON_BN_CLICKED(IDC_INSERT_AUDIO, OnInsertAudio) ON_BN_CLICKED(IDC_LOAD_AND_BURN, OnLoadAndBurn) ON_WM_DESTROY() ON_BN_CLICKED(IDC_PREVIEW, OnPreview) ON_BN_CLICKED(IDC_EXPORT, OnExport) ON_BN_CLICKED(IDC_REMOVEALL, OnRemoveall) ON_BN_CLICKED(IDC_INSERT_VIDEOSTREAM, OnInsertVideoStream) ON_BN_CLICKED(IDC_INSERT_AUDIOSTREAM, OnInsertAudioStream) //}}AFX_MSG_MAP ON_MESSAGE(UM_QUIT_WITH_DELAY, OnQuitWithDelay) END_MESSAGE_MAP() BOOL CPageFirst::OnInitDialog() { CPage::OnInitDialog(); if (m_ilIcons.Create (16, 16, ILC_COLOR|ILC_MASK, 3, 1)) { const static UINT uIconIDs[] = { IDI_IMAGE, IDI_SOUND, IDI_VIDEO, IDI_MAIN, }; for (int i = 0; i < sizeof (uIconIDs)/sizeof (uIconIDs[0]); i ++) { HICON hIcon = (HICON) ::LoadImage (AfxGetInstanceHandle (), MAKEINTRESOURCE (uIconIDs[i]), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); m_ilIcons.Add (hIcon); DestroyIcon (hIcon); } c_Content.SetImageList (&m_ilIcons, TVSIL_NORMAL); } // enum transition effects and fillin effect combobox NeroVisionAPI::IEffectEnumeratorPtr efEnum; { if (FAILED(efEnum.CreateInstance(__uuidof(NeroVisionAPI::EffectEnumerator)))) { MessageBox("IEffectEnumeratorPtr CreateInstance failed"); return TRUE; } int index = c_TransitionType.AddString(""); c_TransitionType.SetItemData(index, (DWORD)ST_NONEEFFECT); for (int i = 0; i < efEnum->GetNumEffects(); i++) { BSTR typeID, displayName; NeroVisionAPI::EffectCategory category; if (efEnum->GetEffectBaseInfo(i, &typeID, &displayName, &category)) { if (category == NeroVisionAPI::EffectCategory_Transition) { _bstr_t* id = new _bstr_t(typeID, false); _bstr_t name(displayName, false); int index = c_TransitionType.AddString(name); c_TransitionType.SetItemData(index, (DWORD)id); } } } } // On the first update, set the proper state of controls. // UpdateControls (); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CPageFirst::OnDestroy() { for (int i = 0; i < c_TransitionType.GetCount(); i++) { _bstr_t* id = (_bstr_t*)c_TransitionType.GetItemData(i); if (id) { delete id; } } CPage::OnDestroy(); } bool CPageFirst::Create (void) { // This is a CPage virtual function. Just create the dialog and return // success. // return CDialog::Create (m_lpszTemplateName, m_pParentWnd) != FALSE; } bool CPageFirst::OnNext (void) { if (m_bLoadAndBurn) { return false; } else { // This method will be called whenever a main window's Next button is // clicked. We can use it to override the default behavior by returning // true. // IXMLDOMDocumentPtr pDocument = BuildXML (); if (pDocument != NULL) { // If XML was built successfully, set it to the common page // data and let the default behavior of the button switch // to the next page. // USES_CONVERSION; GetPageData ()->m_sXML = W2CA (pDocument->xml); return false; } else { // If there was an error building XML, report it and don't // switch to the next page. // AfxMessageBox (IDS_ERROR_BUILDING_XML); return true; } } } void CPageFirst::OnChangeState (bool bActivate, bool bForward) { if (bActivate && bForward) { // If we are activated in the forward direction (normally only // once at the beginning), check if project object was // successfully created. If not, fail miserably as we can't // proceed without it. We will actually post a message to ourselves // to delay the quitting and to allow the main window to be // displayed. // if (GetPageData ()->m_pProject == NULL) { PostMessage (UM_QUIT_WITH_DELAY); } } } LRESULT CPageFirst::OnQuitWithDelay (WPARAM wParam, LPARAM lParam) { // This handler will be called if NeroVisionAPI's Project object // could not have been created. We can't do anything but quit. // AfxMessageBox (IDS_ERROR_INITIALIZING_NERO_VISION_API); PostQuitMessage (0); return 0; } void CPageFirst::OnLoad() { // This is a Load handler. Ask for a file to load. // CString sFilter; sFilter.LoadString (IDS_XML_FILES_FILTER); CFileDialog dlg (TRUE, "xml", NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { // If ok was clicked, create an instance of XML document and // load the document. If loaded successfully, parse the XML file // and fill the dialog controls accordingly. // try { try { IXMLDOMDocumentPtr pDocument; // Create object instance... Try MSXML 4.0 first, if not // then 3.0. Version independent PROGID loads 3.0 even if // 4.0 is installed. We want 4.0 because it supports schema // validation. // if (FAILED (pDocument.CreateInstance ("Msxml2.DOMDocument.4.0"))) { EVAL_HR (pDocument.CreateInstance ("Msxml2.DOMDocument.3.0")); } // Load the document... // VARIANT_BOOL bSuccess; bSuccess = pDocument->load ((LPCSTR) dlg.GetPathName ()); if (bSuccess) { // Parse the document... // ParseXMLDocument (pDocument); } else { IXMLDOMParseErrorPtr pParseError = pDocument->parseError; CString str, sFormat; USES_CONVERSION; VERIFY (sFormat.LoadString (IDS_XML_PARSE_ERROR)); str.Format (sFormat, pParseError->errorCode, pParseError->line, pParseError->linepos, W2CA (pParseError->reason), W2CA (pParseError->srcText)); AfxMessageBox (str); } } catch (HRESULT hr) { throw _com_error (hr); } } catch (_com_error e) { c_Content.DeleteAllItems (); CString str; VERIFY (str.LoadString (IDS_ERROR_LOADING_XML)); CString sMessage; sMessage.Format ("%s (%s)", str, e.ErrorMessage ()); AfxMessageBox (sMessage); } catch (...) { // If an error occurs, delete everything and display an error. // c_Content.DeleteAllItems (); AfxMessageBox (IDS_ERROR_LOADING_XML); } // No matter if the document is loaded successfully or not, // update the controls to reflect the new state. // UpdateControls (); } } void CPageFirst::OnSave() { // This is the save XML handler. // IXMLDOMDocumentPtr pDocument; // Build the XML from the project settings. // pDocument = BuildXML (); if (pDocument == NULL) { // If ther is an error, notify the user. // AfxMessageBox (IDS_ERROR_BUILDING_XML); } else { // If no error, ask the user for a filename to save the XML to. // CString sFilter; sFilter.LoadString (IDS_XML_FILES_FILTER); CFileDialog dlg (FALSE, "xml", NULL, OFN_HIDEREADONLY|OFN_EXPLORER|OFN_OVERWRITEPROMPT, sFilter, this); if (IDOK == dlg.DoModal ()) { // If filename is given, use the document's save method to save // the XML to a file. // try { EVAL_HR (pDocument->save ((LPCSTR) dlg.GetPathName ())); } catch (...) { // Display a message on error. // AfxMessageBox (IDS_ERROR_SAVING_XML); } } } } void CPageFirst::OnInsertVideo() { // This is a handler to insert video to project. Ask for a video // filename. // CString sFilter; sFilter.LoadString (IDS_VIDEO_FILES_FILTER); CFileDialog dlg (TRUE, NULL, NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { // If video file is selected insert it into project. // CString sFormat; CString sVideoItemName; sFormat.LoadString (IDS_VIDEO_TITLE_FORMAT); sVideoItemName.Format (sFormat, m_iVideoItemSequence++); InsertVideo (sVideoItemName, dlg.GetPathName ()); // After insertion, update the controls. // UpdateControls (); } } HTREEITEM CPageFirst::InsertVideo (LPCSTR psVideoItemName, LPCSTR psPath) { // This method inserts the video into the project (tree ctrl). // HTREEITEM hVideoItem = c_Content.InsertItem (psVideoItemName, 3, 3); if (hVideoItem != NULL) { c_Content.SetItemData (hVideoItem, CONTENTTYPE::VIDEOTITLE); HTREEITEM hVideoSubItem; hVideoSubItem = c_Content.InsertItem (psPath, 2, 2, hVideoItem); if (hVideoSubItem != NULL) { c_Content.SetItemData (hVideoSubItem, SUBITEMTYPE::ST_VIDEOPATH); } c_Content.Expand (hVideoItem, TVE_EXPAND); } return hVideoItem; } void CPageFirst::InsertAudio (HTREEITEM hVideoItem, LPCSTR psAudioPath) { HTREEITEM hPathName = c_Content.InsertItem (psAudioPath, 1, 1, hVideoItem); if (hPathName != NULL) { c_Content.SetItemData (hPathName, SUBITEMTYPE::ST_AUDIOPATH); } } void CPageFirst::OnRemove() { // This is a remove handler. First find the selected tree item. // HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); // If there is one... // if (hSelectedItem != NULL) { // Find the root item of the selected item. // for (HTREEITEM hParentItem = hSelectedItem; hParentItem != NULL; hSelectedItem = hParentItem, hParentItem = c_Content.GetParentItem (hSelectedItem)) ; // Now remove it... // c_Content.DeleteItem (hSelectedItem); UpdateControls (); } } void CPageFirst::OnInsertSlide() { // This method inserts an image into the project (tree ctrl) along // with the two transitions (one before and one after the image). // CString sFilter; sFilter.LoadString (IDS_IMAGE_FILES_FILTER); CFileDialog dlg (TRUE, NULL, NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { CString sFormat; CString sSlideshowItemName; sFormat.LoadString (IDS_SLIDE_SHOW_FORMAT); sSlideshowItemName.Format (sFormat, m_iSlideshowItemSequence++); HTREEITEM hSlideItem = InsertSlideshow (sSlideshowItemName); // Insert an "empty" transition before and after the image. // InsertTransition (hSlideItem); InsertImage (hSlideItem, dlg.GetPathName ()); InsertTransition (hSlideItem); c_Content.Expand (hSlideItem, TVE_EXPAND); UpdateControls (); } } HTREEITEM CPageFirst::InsertSlideshow (LPCSTR psSlideshowName) { // This is a helper method for inserting a slide show image. // HTREEITEM hSlideItem = c_Content.InsertItem (psSlideshowName, 3, 3); c_Content.SetItemData (hSlideItem, CONTENTTYPE::SLIDESHOW); return hSlideItem; } void CPageFirst::InsertTransition (HTREEITEM hSlideItem, const int transitionIndex) { // This is a helper method for inserting a transition. // // transition also be insert before audio HTREEITEM childItem = c_Content.GetChildItem(hSlideItem); if (childItem != NULL) { HTREEITEM nextchildItem = c_Content.GetNextSiblingItem(childItem); while (nextchildItem != NULL) { if (c_Content.GetItemData(nextchildItem) == ST_AUDIOSTREAM || c_Content.GetItemData(nextchildItem) == ST_AUDIOPATH) { HTREEITEM hTransition = c_Content.InsertItem ("", 0, 0, hSlideItem, childItem); ChangeTransition (hTransition, transitionIndex); break; } childItem = nextchildItem; nextchildItem = c_Content.GetNextSiblingItem(childItem); } if (nextchildItem == NULL) { HTREEITEM hTransition = c_Content.InsertItem ("", 0, 0, hSlideItem); ChangeTransition (hTransition, transitionIndex); } } else { HTREEITEM hTransition = c_Content.InsertItem ("", 0, 0, hSlideItem); ChangeTransition (hTransition, transitionIndex); } } void CPageFirst::OnInsertVideoStream() { // video stream is created by VideoProvider // created in pagedata.h // function in ContentProvider.cpp CString sVideoStreamName; sVideoStreamName.Format(IDS_VIDEOSTREAM_FORMAT, m_iVideoStreamSequence++); CString sVideoStreamContent = "Test counter"; InsertVideoStream (sVideoStreamName, "Test counter"); UpdateControls (); } HTREEITEM CPageFirst::InsertVideoStream (LPCSTR psVideoStreamName, LPCSTR psVideoStreamContent) { // This method inserts the video into the project (tree ctrl). // HTREEITEM hVideoStreamItem = c_Content.InsertItem (psVideoStreamName, 3, 3); if (hVideoStreamItem != NULL) { c_Content.SetItemData (hVideoStreamItem, CONTENTTYPE::VIDEOTITLE); HTREEITEM hVideoStreamSubItem; hVideoStreamSubItem = c_Content.InsertItem (psVideoStreamContent, 2, 2, hVideoStreamItem); if (hVideoStreamSubItem != NULL) { c_Content.SetItemData (hVideoStreamSubItem, SUBITEMTYPE::ST_VIDEOSTREAM); } c_Content.Expand (hVideoStreamItem, TVE_EXPAND); } return hVideoStreamItem; } void CPageFirst::OnInsertAudioStream() { // audio stream is created by VideoProvider // created in pagedata.h // function in ContentProvider.cpp HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); if (hSelectedItem != NULL) { HTREEITEM hParentItem = c_Content.GetParentItem (hSelectedItem); if (hParentItem == NULL) { hParentItem = hSelectedItem; } InsertAudioStream(hParentItem, "Morse Message"); } UpdateControls (); } void CPageFirst::InsertAudioStream (HTREEITEM hVideoItem, LPCSTR psAudioStreamName) { HTREEITEM hPathName = c_Content.InsertItem (psAudioStreamName, 1, 1, hVideoItem); if (hPathName != NULL) { c_Content.SetItemData (hPathName, SUBITEMTYPE::ST_AUDIOSTREAM); } } void CPageFirst::InsertImage (HTREEITEM hSlideItem, LPCSTR psImagePath) { // This is a helper method for inserting an image after an initial // image has been inserted into a slideshow with InsertSlideshow. // // image has to be insert before audio HTREEITEM childItem = c_Content.GetChildItem(hSlideItem); if (childItem != NULL) { HTREEITEM nextchildItem = c_Content.GetNextSiblingItem(childItem); while (nextchildItem != NULL) { if (c_Content.GetItemData(nextchildItem) == ST_AUDIOSTREAM || c_Content.GetItemData(nextchildItem) == ST_AUDIOPATH) { c_Content.InsertItem (psImagePath, 0, 0, hSlideItem, childItem); c_Content.SetItemData (hSlideItem, SUBITEMTYPE::ST_IMAGEPATH); break; } childItem = nextchildItem; nextchildItem = c_Content.GetNextSiblingItem(childItem); } if (nextchildItem == NULL) { HTREEITEM hPathName = c_Content.InsertItem (psImagePath, 0, 0, hSlideItem); c_Content.SetItemData (hPathName, SUBITEMTYPE::ST_IMAGEPATH); } } else { HTREEITEM hPathName = c_Content.InsertItem (psImagePath, 0, 0, hSlideItem); c_Content.SetItemData (hPathName, SUBITEMTYPE::ST_IMAGEPATH); } } void CPageFirst::ChangeTransition (HTREEITEM hItem, const int transitionIndex) { // This method is used for changing the transition type in the project. // First make sure the transition is valid. // ASSERT (0 <= transitionIndex && transitionIndex <= c_TransitionType.GetCount()); CString str; CString sFormat; CString sTransitionName; // Get the actual transition name from the combobox. The strings should // be in the same order as the TRANSITION enums. // c_TransitionType.GetLBText (transitionIndex, sTransitionName); // Get the transition formatting string from the string table and // create the final string that we are going to set to this item. // sFormat.LoadString (IDS_TRANSITION_FORMAT); str.Format (sFormat, sTransitionName); c_Content.SetItemText (hItem, str); c_Content.SetItemData (hItem, transitionIndex); } void CPageFirst::OnSelchangedContent(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; // Every time the selection of tree ctrl changes, update the controls' // states. // UpdateControls (); *pResult = 0; } void CPageFirst::UpdateControls (void) { // This method updates the controls' states according to the state // of the project. // HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); // Save button should be enabled if there is at least one item in // the project tree ctrl (if there is something worth saving). // Remove button should be enbled if something is selected. // BOOL enable = c_Content.GetFirstVisibleItem () != NULL; c_Save.EnableWindow (enable); c_Preview.EnableWindow (enable); c_RemoveAll.EnableWindow (enable); c_Remove.EnableWindow (hSelectedItem != NULL); // we can export only one title at one time c_Export.EnableWindow (hSelectedItem != NULL); bool bEnableTransitionType = false; bool bEnableInsertImage = false; bool bEnableInsertAudio = false; HTREEITEM hItemTopLevel = c_Content.GetParentItem (hSelectedItem); if (hItemTopLevel != NULL) { // This is the second level of items. See if the parent is a // slideshow item. // if (c_Content.GetItemData (hItemTopLevel) == CONTENTTYPE::SLIDESHOW) { // Yes it is a slideshow. Now check to see if the particular // item is a transition item. // int transition = (SUBITEMTYPE) c_Content.GetItemData (hSelectedItem); bEnableTransitionType = IsTransition (transition); if (bEnableTransitionType) { // Set the transition of the currently selected item. // c_TransitionType.SetCurSel ((int) transition); } bEnableInsertImage = true; } } else { bEnableInsertImage = hSelectedItem != NULL && c_Content.GetItemData (hSelectedItem) == CONTENTTYPE::SLIDESHOW; hItemTopLevel = hSelectedItem; } if (hItemTopLevel != NULL) { // Look if an audio item is already present among the child items. // If not, we will enable the insert button. // HTREEITEM hChildItem = c_Content.GetChildItem (hItemTopLevel); bEnableInsertAudio = true; while (hChildItem != NULL) { DWORD dwAudioType = c_Content.GetItemData (hChildItem); if (dwAudioType == ST_AUDIOSTREAM || dwAudioType == ST_AUDIOPATH) { bEnableInsertAudio = false; break; } hChildItem = c_Content.GetNextSiblingItem (hChildItem); } } // Enable transition type combobox and insert image button according // to the conditions evaluated previously. // c_TransitionType.EnableWindow (bEnableTransitionType); c_InsertImage.EnableWindow (bEnableInsertImage); c_InsertAudio.EnableWindow (bEnableInsertAudio); c_InsertAudioStream.EnableWindow (bEnableInsertAudio); } void CPageFirst::OnSelchangeTransitionType() { // When selection changes in the transition type combo box, update the // transition type of the item in the treectrl. // HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); if (hSelectedItem != NULL) { HTREEITEM hItemParent = c_Content.GetParentItem (hSelectedItem); if (hItemParent != NULL) { if (c_Content.GetItemData (hItemParent) == CONTENTTYPE::SLIDESHOW) { ChangeTransition (hSelectedItem, c_TransitionType.GetCurSel ()); } } } } void CPageFirst::OnInsertImage() { // This method inserts an image into the project (tree ctrl) after an // initial slideshow has been created with InsertSlideshow. // HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); if (hSelectedItem != NULL) { HTREEITEM hParentItem = c_Content.GetParentItem (hSelectedItem); if (c_Content.GetItemData (hParentItem != NULL? hParentItem: hSelectedItem) == CONTENTTYPE::SLIDESHOW) { CString sFilter; sFilter.LoadString (IDS_IMAGE_FILES_FILTER); CFileDialog dlg (TRUE, NULL, NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { // If an image filename has been chosen, insert it at the // end of an existing slideshow. // HTREEITEM hSlideItem = hParentItem != NULL? hParentItem: hSelectedItem; InsertImage (hSlideItem, dlg.GetPathName ()); InsertTransition (hSlideItem); c_Content.Expand (hSlideItem, TVE_EXPAND); UpdateControls (); } } } } _bstr_t CPageFirst::PrettyFormatXML (/*[in]*/ BSTR bstrInputXML) { // This method is used for pretty printing the XML file. // try { ISAXXMLReaderPtr pSAXXReader; IMXWriterPtr pMXWriter; EVAL_HR (pSAXXReader.CreateInstance ("MSXML2.SAXXMLReader.3.0")); EVAL_HR (pMXWriter.CreateInstance ("MSXML2.MXXMLWriter.3.0")); pMXWriter->indent = VARIANT_TRUE; pMXWriter->standalone = VARIANT_TRUE; ISAXContentHandlerPtr pSAXContentHandler (pMXWriter); EVAL_HR (pSAXXReader->putContentHandler (pSAXContentHandler)); EVAL_HR (pSAXXReader->parse (bstrInputXML)); _variant_t varOutput = pMXWriter->output; EVAL_HR (varOutput.vt == VT_BSTR? S_OK: E_INVALIDARG); _bstr_t bstrRet (varOutput.bstrVal); return bstrRet; } catch (...) { return ""; } } IXMLDOMDocumentPtr CPageFirst::BuildXML (void) { // This method is used to build an XML from the project. // IXMLDOMDocumentPtr pDocument; try { EVAL_HR (pDocument.CreateInstance ("Msxml2.DOMDocument")); _bstr_t bstrTarget ("xml"); _bstr_t bstrData ("version='1.0' encoding='ISO-8859-1'"); IXMLDOMProcessingInstructionPtr pPI; pPI = pDocument->createProcessingInstruction (bstrTarget, bstrData); pDocument->appendChild (pPI); IXMLDOMElementPtr pNeroProjectElement; pNeroProjectElement = pDocument->createElement ("nerovision-project"); pNeroProjectElement->setAttribute ("version", 1L); pNeroProjectElement->setAttribute ("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); pNeroProjectElement->setAttribute ("xsi:noNamespaceSchemaLocation", _variant_t ("NeroVisionAPI.xsd")); pDocument->appendChild (pNeroProjectElement); // Get the project type string directly from the project type // combobox. // int iProjectTypeCurSel = c_ProjectType.GetCurSel (); ASSERT (iProjectTypeCurSel != -1); CString sProjectType; c_ProjectType.GetLBText (iProjectTypeCurSel, sProjectType); // Insert a project type tag with a fixed PAL encoding. // IXMLDOMElementPtr pProjectType; pProjectType = pDocument->createElement ((LPCSTR) sProjectType); int iEncodingTypeCurSel = c_EncodingType.GetCurSel(); ASSERT(iEncodingTypeCurSel != -1); CString sEncodingType; c_EncodingType.GetLBText (iEncodingTypeCurSel, sEncodingType); pProjectType->setAttribute ("encoding", (LPCSTR)sEncodingType); pNeroProjectElement->appendChild (pProjectType); // Insert a hardcoded label. // IXMLDOMElementPtr pLabel; pLabel = pDocument->createElement ("label"); pLabel->put_text (_bstr_t ("This is a label!")); pProjectType->appendChild (pLabel); // Start the content tag... // IXMLDOMElementPtr pContent; pContent = pDocument->createElement ("content"); pProjectType->appendChild (pContent); int ITitleItemID = 1; for (HTREEITEM hTitle = c_Content.GetChildItem (NULL); hTitle != NULL; hTitle = c_Content.GetNextSiblingItem (hTitle)) { IXMLDOMElementPtr pTitle; switch (c_Content.GetItemData (hTitle)) { case CONTENTTYPE::VIDEOTITLE: // This is a video. Add videotitle tag with a name attribute // whose value is the tree item caption. // { pTitle = pDocument->createElement ("videotitle"); pTitle->setAttribute ("name", (LPCSTR) c_Content.GetItemText (hTitle)); CString sID; sID.Format ("t%d", ITitleItemID++); pTitle->setAttribute ("id", (LPCSTR) sID); pContent->appendChild (pTitle); break; } case CONTENTTYPE::SLIDESHOW: { // This is a slide show. Add a slideshow tag with a name // attribute whose value is the tree item caption. // pTitle = pDocument->createElement ("slideshow"); pTitle->setAttribute ("name", (LPCSTR) c_Content.GetItemText (hTitle)); CString sID; sID.Format ("t%d", ITitleItemID++); pTitle->setAttribute ("id", (LPCSTR) sID); pContent->appendChild (pTitle); break; } } // Now, iterate the children and add transitions and images. // for (HTREEITEM hChild = c_Content.GetChildItem (hTitle); hChild != NULL; hChild = c_Content.GetNextSiblingItem (hChild)) { SUBITEMTYPE vt = (SUBITEMTYPE) c_Content.GetItemData (hChild); switch (vt) { case SUBITEMTYPE::ST_VIDEOPATH: { IXMLDOMElementPtr pVideo; pVideo = pDocument->createElement ("video"); pVideo->setAttribute ("src", (LPCSTR) c_Content.GetItemText (hChild)); pTitle->appendChild (pVideo); break; } case SUBITEMTYPE::ST_AUDIOPATH: { IXMLDOMElementPtr pAudio; pAudio = pDocument->createElement ("audio"); pAudio->setAttribute ("src", (LPCSTR) c_Content.GetItemText (hChild)); pTitle->appendChild (pAudio); break; } case SUBITEMTYPE::ST_VIDEOSTREAM: { // This is a video stream. Add a video stream tag with a name // attribute whose value is the tree item caption. IXMLDOMElementPtr pVideoStream; pVideoStream = pDocument->createElement ("video"); CString videoStreamName; videoStreamName.Format("content-id:V:%s", c_Content.GetItemText (hChild)); pVideoStream->setAttribute ("src", (LPCSTR) videoStreamName); pVideoStream->setAttribute ("start", "0"); pVideoStream->setAttribute ("duration", "10"); CString sVideoID; sVideoID.Format("v%d", ITitleItemID); pVideoStream->setAttribute ("id", (LPCSTR) sVideoID); pTitle->appendChild (pVideoStream); break; } case SUBITEMTYPE::ST_AUDIOSTREAM: { IXMLDOMElementPtr pAudioStream; pAudioStream = pDocument->createElement ("audio"); CString sAudioStreamName; sAudioStreamName.Format("content-id:A:%s", c_Content.GetItemText (hChild)); pAudioStream->setAttribute ("src", (LPCSTR) sAudioStreamName); pAudioStream->setAttribute ("start", "0"); pAudioStream->setAttribute ("duration", "10"); CString sAudioID; sAudioID.Format("a%d", ITitleItemID); pAudioStream->setAttribute ("id", (LPCSTR) sAudioID); pTitle->appendChild (pAudioStream); break; } case SUBITEMTYPE::ST_IMAGEPATH: { // This is an image path. // IXMLDOMElementPtr pImage; pImage = pDocument->createElement ("image"); pImage->setAttribute ("src", (LPCSTR) c_Content.GetItemText (hChild)); pImage->setAttribute ("duration", "5"); pTitle->appendChild (pImage); break; } default: { if (IsTransition (vt) && vt != SUBITEMTYPE::ST_NONEEFFECT) { _bstr_t* sTransitionName = (_bstr_t*)c_TransitionType.GetItemData(vt); IXMLDOMElementPtr pTransition; pTransition = pDocument->createElement ("transition"); pTransition->setAttribute ("type", (LPCSTR) *sTransitionName); pTitle->appendChild (pTransition); } break; } } } } IXMLDOMElementPtr pMenu; pMenu = pDocument->createElement ("menu"); pMenu->setAttribute ("default-thumbnail", "FirstNonEmptyFrame"); pProjectType->appendChild (pMenu); IXMLDOMElementPtr pDefaultTemplate; pDefaultTemplate = pDocument->createElement ("default-template"); pDefaultTemplate->setAttribute ("id", "templ1"); pDefaultTemplate->setAttribute ("name", "Island"); pMenu->appendChild (pDefaultTemplate); IXMLDOMElementPtr pMainMenu; pMainMenu = pDocument->createElement ("main-menu"); pMenu->appendChild (pMainMenu); for (int i = 1; i < ITitleItemID; i ++) { IXMLDOMElementPtr pChapterMenu; pChapterMenu = pDocument->createElement ("chapter-menu"); CString sID; sID.Format ("t%d", i); pChapterMenu->setAttribute ("title-id", (LPCSTR) sID); pMenu->appendChild (pChapterMenu); } } catch (...) { // If an exception is caught, release the unfinished document. // pDocument = NULL; } return pDocument; } void CPageFirst::OnBeginlabeleditContent(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; // Allow label editing on the first level only! This means editing is // allowed for video and slideshow item names only. Return TRUE to // disable editing. // *pResult = c_Content.GetParentItem (pTVDispInfo->item.hItem) != NULL; } void CPageFirst::ParseXMLDocument (const IXMLDOMDocumentPtr pDocument) { // First, clear the treectrl. // c_Content.DeleteAllItems (); // Loop through all the nodes, look for elements. // for (IXMLDOMNodePtr pNode = pDocument->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); // If node is an element, the interface pointer will be non-NULL. // if (pElement != NULL) { // Check to see if the tag name is what we are looking for. // if (0 == wcscmp ((BSTR) pElement->tagName, L"nerovision-project")) { ParseNeroVisionProject (pElement); // Once the project tag is parsed, we need parse no more. // break; } } } } void CPageFirst::ParseNeroVisionProject (const IXMLDOMElementPtr pProject) { // Ok, we are now looking for the project type (vcd, svcd or dvd). // for (IXMLDOMNodePtr pNode = pProject->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); if (pElement != NULL) { USES_CONVERSION; _bstr_t tagName = pElement->tagName; LPCSTR psTagName = W2CA (tagName); // Instead of hardcoding the strings, we will now see if the // tag name matches any of the strings in the project type // combobox. We could use CComboBox::FindString but this // method uses case insensitive search and we need it to be // case sensitive. // for (int i = c_ProjectType.GetCount () - 1; i >= 0; i --) { CString sProjectType; c_ProjectType.GetLBText (i, sProjectType); if (0 == strcmp (psTagName, sProjectType)) { c_ProjectType.SetCurSel (i); break; } } // Make sure the appropriate project type was found! // EVAL_HR (i >= 0? S_OK: E_FAIL); // match the encoding type string in the combobox IXMLDOMAttributePtr pAttribute = pElement->getAttributeNode ("encoding"); _bstr_t attribute = pAttribute->value; LPCSTR sEncodingType = W2CA (attribute); for (i = c_EncodingType.GetCount () - 1; i >= 0; i --) { CString sEncodingType; c_EncodingType.GetLBText (i, sEncodingType); if (0 == strcmp (attribute, sEncodingType)) { c_EncodingType.SetCurSel (i); break; } } // Make sure the appropriate encoding type was found! // EVAL_HR (i >= 0? S_OK: E_FAIL); // If the subproject tag was found, parse its inner tags. // ParseSubproject (pElement); // Then break as only one subproject is supported. // break; } } } void CPageFirst::ParseSubproject (const IXMLDOMElementPtr pSubProject) { // Now we are looking for the label and content tags. Actually, we // don't care about the label as we don't have facility to neither // display nor modify it. So, content tag is all we want. We also // don't care about the encoding attribute as we don't use it. It is // always PAL. // for (IXMLDOMNodePtr pNode = pSubProject->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); if (pElement != NULL) { if (0 == wcscmp ((BSTR) pElement->tagName, L"content")) { // Once the content tag is found, parse it, then break as // only one content tag is allowed. // ParseContent (pElement); break; } } } } void CPageFirst::ParseContent (const IXMLDOMElementPtr pContent) { // Here we want videotitle and slideshow tags. Any number of these // can appear in any order. // for (IXMLDOMNodePtr pNode = pContent->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); if (pElement != NULL) { if (0 == wcscmp ((BSTR) pElement->tagName, L"videotitle")) { ParseVideotitle (pElement); } else if (0 == wcscmp ((BSTR) pElement->tagName, L"slideshow")) { ParseSlideshow (pElement); } } } } void CPageFirst::ParseVideotitle (const IXMLDOMElementPtr pVideotitle) { // Videotitle has a mandatory attribute "name". That is what we are // after. A sub-tag "video" is also of interest to us. // IXMLDOMAttributePtr pNameAttr = pVideotitle->attributes->getNamedItem ("name"); if (pNameAttr != NULL) { HTREEITEM hVideoItem = NULL; // Look for video tag. // for (IXMLDOMNodePtr pNode = pVideotitle->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); if (pElement != NULL) { if (0 == wcscmp ((BSTR) pElement->tagName, L"video")) { if (hVideoItem != NULL) { // There can be only one video tag per videotitle. // throw E_FAIL; } // Video tag is found. Take its "src" attribute. // IXMLDOMAttributePtr pSrcAttr = pElement->attributes->getNamedItem ("src"); if (pSrcAttr != NULL) { // Once we have both name and src attributes, // insert the video to the project. // USES_CONVERSION; _bstr_t bstrName (pNameAttr->value); _bstr_t bstrPath (pSrcAttr->value); CString sName = pSrcAttr->value.bstrVal; CString matchString = "content-id:V:"; if (sName.Left(matchString.GetLength()) == matchString) { sName = sName.Right(sName.GetLength() - matchString.GetLength()); hVideoItem = InsertVideoStream (W2CA (bstrName), sName); } else { hVideoItem = InsertVideo (W2CA (bstrName), W2CA (bstrPath)); } } } else if (0 == wcscmp ((BSTR) pElement->tagName, L"audio")) { if (hVideoItem == NULL) { // There must be a video tag before audio. // throw E_FAIL; } // Audio tag is found. Take its "src" attribute. // IXMLDOMAttributePtr pSrcAttr = pElement->attributes->getNamedItem ("src"); if (pSrcAttr != NULL) { // Once we have both name and src attributes, // insert the video to the project. // USES_CONVERSION; _bstr_t bstrPath (pSrcAttr->value); CString sName = pSrcAttr->value.bstrVal; CString matchString = "content-id:A:"; if (IsAudioStream(sName)) { sName = sName.Right(sName.GetLength() - matchString.GetLength()); InsertAudioStream (hVideoItem, sName); } else { InsertAudio (hVideoItem, W2CA (bstrPath)); } // Nothing more should follow after an audio tag // (if any) so we can break here. // break; } } } } } } void CPageFirst::ParseSlideshow (const IXMLDOMElementPtr pSlideshow) { // Slideshow has a mandatory attribute "name". // IXMLDOMAttributePtr pNameAttr = pSlideshow->attributes->getNamedItem ("name"); if (pNameAttr != NULL) { // If "name" attribute is found, let's insert a slideshow into the/ // project. // USES_CONVERSION; _bstr_t bstrName = pNameAttr->value; HTREEITEM hSlideItem = InsertSlideshow (W2CA (bstrName)); // Look for transition and image tags. // for (IXMLDOMNodePtr pNode = pSlideshow->firstChild; pNode != NULL; pNode = pNode->nextSibling) { IXMLDOMElementPtr pElement (pNode); if (pElement != NULL) { if (0 == wcscmp ((BSTR) pElement->tagName, L"transition")) { // A transition tag must have a "type" attribute. // IXMLDOMAttributePtr pTypeAttr = pElement->attributes->getNamedItem ("type"); if (pTypeAttr != NULL) { _bstr_t bstrTransitionType (pTypeAttr->value); // Instead of hardcoding the strings, we will now see if the // type attribute matches any of the strings in the transition type // combobox. // for (int i = c_TransitionType.GetCount () - 1; i >= 0; i --) { _bstr_t* sTransitionName = (_bstr_t*)c_TransitionType.GetItemData(i); if (0 == strcmp (bstrTransitionType, *sTransitionName)) { // Once the transition type was found in // the combobox, insert it into the // project. // InsertTransition (hSlideItem, i); break; } } // Make sure the appropriate transition type was // found! // EVAL_HR (i >= 0? S_OK: E_FAIL); } } else if (0 == wcscmp ((BSTR) pElement->tagName, L"image")) { // When image tag is found, look for its "src" // attribute. // IXMLDOMAttributePtr pSrcAttr = pElement->attributes->getNamedItem ("src"); if (pSrcAttr != NULL) { // When found, insert the image into the project. // _bstr_t bstrImagePath (pSrcAttr->value); InsertImage (hSlideItem, W2CA (bstrImagePath)); } } else if (0 == wcscmp ((BSTR) pElement->tagName, L"audio")) { // Audio tag is found. Take its "src" attribute. // IXMLDOMAttributePtr pSrcAttr = pElement->attributes->getNamedItem ("src"); if (pSrcAttr != NULL) { // Once we have both name and src attributes, // insert the video to the project. // USES_CONVERSION; _bstr_t bstrPath (pSrcAttr->value); CString sName = W2CA(bstrPath); CString matchString = "content-id:A:"; if (IsAudioStream(sName)) { sName = sName.Right(sName.GetLength() - matchString.GetLength()); InsertAudioStream (hSlideItem, sName); } else InsertAudio (hSlideItem, W2CA (bstrPath)); // Nothing more should follow after an audio tag // (if any) so we can break here. // break; } } } } // When all is parsed, expand the tree item. // c_Content.Expand (hSlideItem, TVE_EXPAND); } } void CPageFirst::OnInsertAudio() { // This is a handler to insert an audio file to project. // HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); if (hSelectedItem != NULL) { CString sFilter; sFilter.LoadString (IDS_AUDIO_FILES_FILTER); CFileDialog dlg (TRUE, NULL, NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { // Find the root item of the selected item. // HTREEITEM hParentItem = c_Content.GetParentItem (hSelectedItem); if (hParentItem == NULL) { hParentItem = hSelectedItem; } InsertAudio (hParentItem, dlg.GetPathName ()); // After insertion, update the controls. // UpdateControls (); } } } void CPageFirst::OnLoadAndBurn() { // This is a Load handler. Ask for a file to load. // CString sFilter; sFilter.LoadString (IDS_XML_FILES_FILTER); CFileDialog dlg (TRUE, "xml", NULL, OFN_EXPLORER|OFN_HIDEREADONLY, sFilter, this); if (IDOK == dlg.DoModal ()) { // If ok was clicked, create an instance of XML document and // load the document. If loaded successfully go directly to // burning. // try { try { IXMLDOMDocumentPtr pDocument; // Create object instance... Try MSXML 4.0 first, if not // then 3.0. Version independent PROGID loads 3.0 even if // 4.0 is installed. We want 4.0 because it supports schema // validation. // if (FAILED (pDocument.CreateInstance ("Msxml2.DOMDocument.4.0"))) { EVAL_HR (pDocument.CreateInstance ("Msxml2.DOMDocument.3.0")); } // Load the document... // VARIANT_BOOL bSuccess; bSuccess = pDocument->load ((LPCSTR) dlg.GetPathName ()); if (bSuccess) { USES_CONVERSION; GetPageData ()->m_sXML = W2CA (pDocument->xml); m_bLoadAndBurn = true; GetParent ()->SendMessage (WM_COMMAND, IDOK); m_bLoadAndBurn = false; } else { IXMLDOMParseErrorPtr pParseError = pDocument->parseError; CString str, sFormat; USES_CONVERSION; VERIFY (sFormat.LoadString (IDS_XML_PARSE_ERROR)); str.Format (sFormat, pParseError->errorCode, pParseError->line, pParseError->linepos, W2CA (pParseError->reason), W2CA (pParseError->srcText)); AfxMessageBox (str); } } catch (HRESULT hr) { throw _com_error (hr); } } catch (_com_error e) { CString str; VERIFY (str.LoadString (IDS_ERROR_LOADING_XML)); CString sMessage; sMessage.Format ("%s (%s)", str, e.ErrorMessage ()); AfxMessageBox (sMessage); } catch (...) { // If an error occurs, delete everything and display an error. // AfxMessageBox (IDS_ERROR_LOADING_XML); } } } void CPageFirst::OnPreview() { // build XML before preview, so any change user made will be show on preview page IXMLDOMDocumentPtr pDocument = BuildXML (); USES_CONVERSION; GetPageData ()->m_sXML = W2CA (pDocument->xml); // go to preview page CNVAPIExampleDlg * pParentSheet = (CNVAPIExampleDlg *) GetParent(); if (pParentSheet) pParentSheet->SwitchPage(3); } void CPageFirst::OnExport() { // make sure one title is selected for export HTREEITEM hSelectedItem = c_Content.GetSelectedItem (); if (hSelectedItem != NULL) // Find the root item of the selected item. { for (HTREEITEM hParentItem = hSelectedItem; hParentItem != NULL; hSelectedItem = hParentItem, hParentItem = c_Content.GetParentItem (hSelectedItem)); int index = 0; for (HTREEITEM hChild = c_Content.GetChildItem (NULL) ; hChild != NULL; hChild = c_Content.GetNextSiblingItem (hChild), ++index) { if (hSelectedItem == hChild) { GetPageData ()->m_selectedItemIndex = index; break; } } // build XML before export IXMLDOMDocumentPtr pDocument = BuildXML (); USES_CONVERSION; GetPageData ()->m_sXML = W2CA (pDocument->xml); // go to export page CNVAPIExampleDlg * pParentSheet = (CNVAPIExampleDlg *) GetParent(); if (pParentSheet) pParentSheet->SwitchPage(4); } } void CPageFirst::OnRemoveall() { // for fast restart a project c_Content.DeleteAllItems (); UpdateControls (); } bool CPageFirst::IsAudioStream(LPCSTR psAudioPath) { CString sName = psAudioPath; CString matchString = "content-id:A:"; return (sName.Left(matchString.GetLength()) == matchString); } bool IsVideoStream(LPCSTR psVideoPath) { bool bResult = false; return bResult; }