void UniversalUpdates::PerformUniversalUpdates( bool resources_already_loaded, const QList< Resource* > &resources, const QHash< QString, QString > &updates ) { QHash< QString, QString > html_updates; QHash< QString, QString > css_updates; QHash< QString, QString > xml_updates; tie( html_updates, css_updates, xml_updates ) = SeparateHtmlCssXmlUpdates( updates ); QList< HTMLResource* > html_resources; QList< CSSResource* > css_resources; OPFResource *opf_resource = NULL; NCXResource *ncx_resource = NULL; int num_files = resources.count(); for ( int i = 0; i < num_files; ++i ) { Resource *resource = resources.at( i ); if ( resource->Type() == Resource::HTMLResourceType ) html_resources.append( qobject_cast< HTMLResource* >( resource ) ); else if ( resource->Type() == Resource::CSSResourceType ) css_resources.append( qobject_cast< CSSResource* >( resource ) ); else if ( resource->Type() == Resource::OPFResourceType ) opf_resource = qobject_cast< OPFResource* >( resource ); else if ( resource->Type() == Resource::NCXResourceType ) ncx_resource = qobject_cast< NCXResource* >( resource ); } QFutureSynchronizer<void> sync; if ( resources_already_loaded ) { sync.addFuture( QtConcurrent::map( html_resources, boost::bind( UpdateOneHTMLFile, _1, html_updates, css_updates ) ) ); sync.addFuture( QtConcurrent::map( css_resources, boost::bind( UpdateOneCSSFile, _1, css_updates ) ) ); } else { sync.addFuture( QtConcurrent::map( html_resources, boost::bind( LoadAndUpdateOneHTMLFile, _1, html_updates, css_updates ) ) ); sync.addFuture( QtConcurrent::map( css_resources, boost::bind( LoadAndUpdateOneCSSFile, _1, css_updates ) ) ); } // We can't schedule these with QtConcurrent because they // will (indirectly) call QTextDocument::setPlainText, and if // a tab is open for the ncx/opf, then an event needs to be sent // to the tab widget. Events can't cross threads, and we crash. UpdateNCXFile( ncx_resource, xml_updates ); UpdateOPFFile( opf_resource, xml_updates ); sync.waitForFinished(); }
void ImportHTML::UpdateFiles(HTMLResource &html_resource, QString & source, const QHash<QString, QString> &updates) { Q_ASSERT(&html_resource != NULL); QHash<QString, QString> html_updates; QHash<QString, QString> css_updates; QString newsource = source; QString currentpath = html_resource.GetCurrentBookRelPath(); std::tie(html_updates, css_updates, std::ignore) = UniversalUpdates::SeparateHtmlCssXmlUpdates(updates); QList<Resource *> all_files = m_Book->GetFolderKeeper().GetResourceList(); int num_files = all_files.count(); QList<CSSResource *> css_resources; for (int i = 0; i < num_files; ++i) { Resource *resource = all_files.at(i); if (resource->Type() == Resource::CSSResourceType) { css_resources.append(qobject_cast<CSSResource *>(resource)); } } QFutureSynchronizer<void> sync; sync.addFuture(QtConcurrent::map(css_resources, std::bind(UniversalUpdates::LoadAndUpdateOneCSSFile, std::placeholders::_1, css_updates))); html_resource.SetText(PerformHTMLUpdates(newsource, html_updates, css_updates, currentpath)()); html_resource.SetCurrentBookRelPath(""); sync.waitForFinished(); }
QStringList UniversalUpdates::PerformUniversalUpdates(bool resources_already_loaded, const QList<Resource *> &resources, const QHash<QString, QString> &updates, const QList<XMLResource *> &non_well_formed) { QStringList updatekeys = updates.keys(); QHash<QString, QString> html_updates; QHash<QString, QString> css_updates; QHash<QString, QString> xml_updates; std::tie(html_updates, css_updates, xml_updates) = SeparateHtmlCssXmlUpdates(updates); QList<HTMLResource *> html_resources; QList<CSSResource *> css_resources; OPFResource *opf_resource = NULL; NCXResource *ncx_resource = NULL; int num_files = resources.count(); for (int i = 0; i < num_files; ++i) { Resource *resource = resources.at(i); if (resource->Type() == Resource::HTMLResourceType) { html_resources.append(qobject_cast<HTMLResource *>(resource)); } else if (resource->Type() == Resource::CSSResourceType) { css_resources.append(qobject_cast<CSSResource *>(resource)); } else if (resource->Type() == Resource::OPFResourceType) { opf_resource = qobject_cast<OPFResource *>(resource); } else if (resource->Type() == Resource::NCXResourceType) { ncx_resource = qobject_cast<NCXResource *>(resource); } } QFutureSynchronizer<void> sync; QFuture<QString> html_future; QFuture<void> css_future; if (resources_already_loaded) { html_future = QtConcurrent::mapped(html_resources, std::bind(UpdateOneHTMLFile, std::placeholders::_1, html_updates, css_updates)); css_future = QtConcurrent::map(css_resources, std::bind(UpdateOneCSSFile, std::placeholders::_1, css_updates)); } else { html_future = QtConcurrent::mapped(html_resources, std::bind(LoadAndUpdateOneHTMLFile, std::placeholders::_1, html_updates, css_updates, non_well_formed)); css_future = QtConcurrent::map(css_resources, std::bind(LoadAndUpdateOneCSSFile, std::placeholders::_1, css_updates)); } sync.addFuture(html_future); sync.addFuture(css_future); // We can't schedule these with QtConcurrent because they // will (indirectly) call QTextDocument::setPlainText, and if // a tab is open for the ncx/opf, then an event needs to be sent // to the tab widget. Events can't cross threads, and we crash. const QString ncx_result = UpdateNCXFile(ncx_resource, xml_updates); const QString opf_result = UpdateOPFFile(opf_resource, xml_updates); sync.waitForFinished(); // Now assemble our list of errors if any. QStringList load_update_errors; for (int i = 0; i < html_future.results().count(); i++) { const QString html_error = html_future.resultAt(i); if (!html_error.isEmpty()) { load_update_errors.append(html_error); } } if (!ncx_result.isEmpty()) { load_update_errors.append(ncx_result); } if (!opf_result.isEmpty()) { load_update_errors.append(opf_result); } return load_update_errors; }