Problem:
My project... printing a sequence of pages... created based on certain templates and database info...
The sequence of pages to be printed can be, in certain situations, of different sizes.
I have been trying to print to real printer, producing multiple pages
if (m_printer->newPage()) { ... }
and on a physical printer, if I try to change the page size, it either doesn't work or puts the printer in an error state.
So there is not much choice, it seems, but to make each page a separate job. Minor disadvantages - possibly on a network. Oh well.
On pdf or any type of file printing, though, it makes a huge difference, whether the sequence is contained in a single document on multiple pages, or if it creates hundreds of different documents of one page each.
So, I found this Is it possible to make a pdf with different page size in Qt?
it seems to be exactly what I need, if I print to a pdf - while for real printer I will make each page a separate job.
The only problem:
How can I tell if I am creating a pdf file, or if I am sending a job to a real printer ?
I looked in QPrinter and QPrinterInfo, I did not see anything that can help.
Pdf printing is probably enabled because of Adobe Acrobat.
I am implementing this currently in Windows.
Edit: why getting the outputFormat (Naidu's answer below) doesn't work:
qprinter.cpp:
void QPrinterPrivate::initEngines(QPrinter::OutputFormat format, const QPrinterInfo &printer)
{
..
// Only set NativeFormat if we have a valid plugin and printer to use
if (format == QPrinter::NativeFormat) { //////// which of course has to be, we have to support any printer
ps = QPlatformPrinterSupportPlugin::get();
QPrinterInfo printerToUse = findValidPrinter(printer);
if (ps && !printerToUse.isNull()) { //////// both valid since the PDF writer is valid
outputFormat = QPrinter::NativeFormat;
printerName = printerToUse.printerName();
}
}
...
}
I would like to have something to check, other than the fact that "pdf" may be contained in the name. If needed, I am willing to use the awful DEVMODE, I just don't know what to look for.
Use the public function
QPrinter::outputFormat()
it returns an enum type enum QPrinter::OutputFormat.
And check if it is QPrinter::PdfFormat
http://doc.qt.io/qt-5/qprinter.html#OutputFormat-enum
Related
I'm working on a script that does find/replace for missing items in your project. Unfortunately I'm running into a situation detecting and then replacing layered image sources (psd, ai, etc.).
1) I see no way of detecting if a AvItem is a layer within a layered image other than parsing the item.name, which is unreliable because a user can always rename items in the project panel.
2) Once I do know that it is a part of a layered image I cannot figure out how to re-link it to the correct image without replacing the layer with the merged image. item.replace(new_path) will replace that item with the whole image, not the layer within the image. For example:
var item = app.project.item(3); //assuming this is the 'layer' we want to replace
item.replace(new_path);
So is there a secret property somewhere which will reliably tell me if an item is a part of a layered image, and if so is there a way to relink it without replacing the layer with the entire merged image?
EDIT
Here's a function to guess if a layer is part of a layered image. It's not bullet-proof but it should work as long as the user does not rename the item:
function isSourceLayered (av_item) {
// check if there is a "/"
if (av_item.name.indexOf("/") != -1) {
// check if it is in a "layers" folder
if (av_item.parentFolder.name.indexOf("Layers") != -1) {
return true;
}
}
return false;
}
I just asked the same question on the Adobe extendscript forum. Unless there's undocumented features (and I spent a bit of time looking with Extendscript Toolkit's data browser) the fileSource object doesn't seem to have any attributes or methods to do this.
There is a kind of a workaround, you can import the file using ImportOptions.importAs(ImportAsType.COMP) This will import a comp, and you can loop through the layers matching the name, get the source of that layer and use that as your new source. But as you say, it doesn't work if the source has been renamed.
I've written this into a function, it's available on github Edit: I forgot that I changed the way that function works. It doesn't re-import layer sources because of this problem, it just uses the Duplicate menu command.
I have made a script that takes files from directory, and sends them to backburner for network rendering. When I run the script it renders fine but without the render elements they dont show in the backburner monitor nor do they save.
If I open some of the files manualy and send them to render with backburner it works fine, but not with the script?
The render element is VrayAlpha, but I dont think it matters.
This is the code Im using
on btnRender pressed do
(
outputFilesDir = textModelsOut.text + "*.max"
toRender = getFiles outputFilesDir
man = NetRender.GetManager()
man.connect #automatic "255.255.255.0"
man.GetControl()
for s in toRender do
(
renderModelPath = getFilenamePath s + filenameFromPath s
job = man.newJob file:renderModelPath
job.Submit()
)
man.Disconnect()
)
And this is quote from maxscript documentation, it says that render element data will not be available but it will be processed.
Jobs can not have maps included, and render element data will not be
available for submitted job but render elements will process
correctly. These problems are resent when submitting a job from a
file, but not when submitting the current scene.
Anyways my solution was to use job.newJob() to open each scene and submit the current scene.
You should always include your code (or at least some of it) so that we can check it for issues and test it our selves.
However, I usually use a struct called NetRenderAutomation, developed by Gravey.
You can find it here:
http://forums.cgsociety.org/showthread.php?f=98&t=1059510&page=1&pp=15
I haven't had any problems with it, and it is fairly easy to use, and you are even allowed to modify it, if you need some special features for your self.
Hope you can use the answer.
Else feel free to post some code, and I'll look into it.
Background: I downloaded a *.sql backup of my WordPress site's database, and replaced all instances of the old database table prefix with a new one (e.g. from the default wp_ to something like asdfghjkl_).
I've just learnt that WordPress uses serialized PHP strings in the database, and what I did will have messed with the integrity of the serialized string lengths.
The thing is, I deleted the backup file just before I learnt about this (as my website was still functioning fine), and installed a number of plugins since. So, there's no way I can revert back, and I therefore would like to know two things:
How can I fix this, if at all possible?
What kind of problems could this cause?
(This article states that, a WordPress blog for instance, could lose its settings and widgets. But this doesn't seem to have happened to me as all the settings for my blog are still intact. But I have no clue as to what could be broken on the inside, or what issues it'd pose in the future. Hence this question.)
Visit this page: http://unserialize.onlinephpfunctions.com/
On that page you should see this sample serialized string: a:1:{s:4:"Test";s:17:"unserialize here!";}. Take a piece of it-- s:4:"Test";. That means "string", 4 characters, then the actual string. I am pretty sure that what you did caused the numeric character count to be out of sync with the string. Play with the tool on the site mentioned above and you will see that you get an error if you change "Test" to "Tes", for example.
What you need to do is get those character counts to match your new string. If you haven't corrupted any of the other encoding-- removed a colon or something-- that should fix the problem.
I came to this same problem after trying to change the domain from localhost to the real URL. After some searching I found the answer in Wordpress documentation:
https://codex.wordpress.org/Moving_WordPress
I will quote what is written there:
To avoid that serialization issue, you have three options:
Use the Better Search Replace or Velvet Blues Update URLs plugins if you can > access your Dashboard.
Use WP-CLI's search-replace if your hosting provider (or you) have installed WP-CLI.
Run a search and replace query manually on your database. Note: Only perform a search and replace on the wp_posts table.
I ended up using WP-CLI which is able to replace things in the database without breaking serialization: http://wp-cli.org/commands/search-replace/
I know this is an old question, but better late than never, I suppose. I ran into this problem recently, after inheriting a database that had had a find/replace executed on serialized data. After many hours of researching, I discovered that this was because the string counts were off. Unfortunately, there was so much data with lots of escaping and newlines and I didn't know how to count in some cases and I had so much data that I needed something automated.
Along the way, I stumbled across this question and Benubird's post helped put me on the right path. His example code did not work in production use on complex data, containing numerous special characters and HTML, with very deep levels of nesting, and it did not properly handle certain escaped characters and encoding. So I modified it a bit and spent countless hours working through additional bugs to get my version to "fix" the serialized data.
// do some DB query here
while($res = db_fetch($qry)){
$str = $res->data;
$sCount=1; // don't try to count manually, which can be inaccurate; let serialize do its thing
$newstring = unserialize($str);
if(!$newstring) {
preg_match_all('/s:([0-9]+):"(.*?)"(?=;)/su',$str,$m);
# preg_match_all("/s:([0-9]+):(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")(?=;)/u",$str,$m); // alternate: almost works but leave quotes in $m[2] output
# print_r($m); exit;
foreach($m[1] as $k => $len) {
/*** Possibly specific to my case: Spyropress Builder in WordPress ***/
$m_clean = str_replace('\"','"',$m[2][$k]); // convert escaped double quotes so that HTML will render properly
// if newline is present, it will output directly in the HTML
// nl2br won't work here (must find literally; not with double quotes!)
$m_clean = str_replace('\n', '<br />', $m_clean);
$m_clean = nl2br($m_clean); // but we DO need to convert actual newlines also
/*********************************************************************/
if($sCount){
$m_new = $m[0][$k].';'; // we must account for the missing semi-colon not captured in regex!
// NOTE: If we don't flush the buffers, things like <img src="http://whatever" can be replaced with <img src="//whatever" and break the serialize count!!!
ob_end_flush(); // not sure why this is necessary but cost me 5 hours!!
$m_ser = serialize($m_clean);
if($m_new != $m_ser) {
print "Replacing: $m_new\n";
print "With: $m_ser\n";
$str = str_replace($m_new, $m_ser, $str);
}
}
else{
$m_len = (strlen($m[2][$k]) - substr_count($m[2][$k],'\n'));
if($len != $m_len) {
$newstr='s:'.$m_len.':"'.$m[2][$k].'"';
echo "Replacing: {$m[0][$k]}\n";
echo "With: $newstr\n\n";
$str = str_replace($m_new, $newstr, $str);
}
}
}
print_r($str); // this is your FIXED serialized data!! Yay!
}
}
A little geeky explanation on my changes:
I found that trying to count with Benubird's code as a base was too inaccurate for large datasets, so I ended up just using serialize to be sure the count was accurate.
I avoided the try/catch because, in my case, the try would succeed but just returned an empty string. So, I check for empty data instead.
I tried numerous regex's but only a mod on Benubird's would accurately handle all cases. Specifically, I had to modify the part that checked for the ";" because it would match on CSS like "width:100%; height:25px;" and broke the output. So, I used a positive lookahead to only match when the ";" was outside of the set of double quotes.
My case had lots of newlines, HTML, and escaped double quotes, so I had to add a block to clean that up.
There were a couple of weird situations where data would be replaced incorrectly by the regex and then the serialize would count it incorrectly as well. I found NOTHING on any sites to help with this and finally thought it might be related to caching or something like that and tried flushing the output buffer (ob_end_flush()), which worked, thank goodness!
Hope this helps someone... Took me almost 20 hours including the research and dealing with weird issues! :)
This script (https://interconnectit.com/products/search-and-replace-for-wordpress-databases/) can help to update an sql database with proper URLs everywhere, without encountering serialized data issues, because it will update the "characters count" that could throw your URLs out of sync whenever serialized data occurs.
The steps would be:
if you already have imported a messed up database (widgets not
working, theme options not there, etc), just drop that database
using PhpMyAdmin. That is, remove everything on it. Then export and
have at hand an un-edited dump of the old database.
Now you have to import the (un-edited) old database into the
newly created one. You can do this via an import, or copying over
the db from PhpMyAdmin. Notice that so far, we haven't done any
search and replace yet; we just have an old database content and
structure into a new database with its own user and password. Your site will be probably unaccessible at this point.
Make sure you have your WordPress files freshly uploaded to the
proper folder on the server, and edit your wp-config.php to make it
connect with the new database.
Upload the script into a "secret" folder - just for security
reasons - at the same level than wp-admin, wp-content, and wp-includes. Do not forget to remove it all once the search and
replace have taken place, because you risk to offer your DB details
open to the whole internet.
Now point your browser to the secret folder, and use the script's fine
interface. It is very self-explanatory. Once used, we proceed to
completely remove it from the server.
This should have your database properly updated, without any serialized data issues around: the new URL will be set everywhere, and serialized data characters counts will be accordingly updated.
Widgets will be passed over, and theme settings as well - two of the typical places that use serialized data in WordPress.
Done and tested solution!
If the error is due to the length of the strings being incorrect (something I have seen frequently), then you should be able to adapt this script to fix it:
foreach($strings as $key => $str)
{
try {
unserialize($str);
} catch(exception $e) {
preg_match_all('#s:([0-9]+):"([^;]+)"#',$str,$m);
foreach($m[1] as $k => $len) {
if($len != strlen($m[2][$k])) {
$newstr='s:'.strlen($m[2][$k]).':"'.$m[2][$k].'"';
echo "len mismatch: {$m[0][$k]}\n";
echo "should be: $newstr\n\n";
$strings[$key] = str_replace($m[0][$k], $newstr, $str);
}
}
}
}
I personally don't like working in PHP, or placing my DB credentials in an public file. I created a ruby script to fix serializations that you can run locally:
https://github.com/wsizoo/wordpress-fix-serialization
Context Edit:
I approached fixing serialization by first identifying serialization via regex, and then recalculating the byte size of the contained data string.
$content_to_fix.gsub!(/s:([0-9]+):\"((.|\n)*?)\";/) {"s:#{$2.bytesize}:\"#{$2}\";"}
I then update the specified data via an escaped sql update query.
escaped_fix_content = client.escape($fixed_content)
query = client.query("UPDATE #{$table} SET #{$column} = '#{escaped_fix_content}' WHERE #{$column_identifier} LIKE '#{$column_identifier_value}'")
Users open files in our app through a QFileDialog. The order of the filenames is bizarre. What is determining the sorting order, and how can we make it sort by filenames, or otherwise impose our own sorting, perhaps giving it a pointer to our own comparison function?
The documentation and online forums haven't been helpful. Unless it's well hidden, there doesn't seem to be any sorting method, property, etc.
This is a primarily Linux app, but also runs on Macs. (I know nothing about Mac.)
Here is the juicy part of the source code:
QtFileDialog chooser(parent, caption, directory, filter);
/// QtFileDialog is our class derived from QFileDialog
chooser.setModal(true);
chooser.setAcceptMode(acceptMode);
chooser.setFileMode(fileMode);
QStringList hist = chooser.history();
chooser.setHistory(hist);
/* point "x" */
if(chooser.exec()) {
QStringList files = chooser.selectedFiles();
...blah blah blah...
From one of the answers, I tried an evil experiment, adding this ill-informed guesswork code at "point x":
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->sort(1); // ???
chooser.setProxyModel(sorter);
But this crashed spectacularly at a point about 33 subroutine calls deep from this level of code. I admit, even after reading the Qt4 documentation and sample code, I have no idea of the proper usage of QSortFilterProxyModel.
Are you using QFileDialog by calling exec()? If you are, you should have a button to switch the view to Detail View. This will give you some column headers that you can click on to sort the files. It should remember that mode the next time the dialog opens but you can force it by calling setViewMode(QFileDialog::Detail) before calling exec().
An alternative is to call the static function QFileDialog::getOpenFileName() which will open a file dialog that is native to the OS on which you are running. Your users may like the familiarity of this option better.
Update 1:
About sort order in screen cap from OP:
This screen capture is actually showing a sorted list. I don't know if the listing behaviour is originating from the Qt dialog or the underlying file system but I know Windows XP and later do it this way.
When sorting filenames with embedded numbers, any runs of consecutive digits are treated as a single number. With the more classic plain string sorting, files would be sorted like this:
A_A_10e0
A_A_9a05
Going character by character, the first 1 sorts before the 9.
.. But with numerical interpretation (as in Windows 7 at least), they are sorted as:
A_A_9a05
A_A_10e0
The 9 sorts before the 10.
So, the sorting you are seeing is alphabetical with numerical interpretation and not just straight character by character. Some deep digging may be required to see if that is Qt behaviour or OS behaviour and whether or not it can be configured.
Update 2:
The QSortFilterProxyModel will sort the strings alphabetically by default so there is not much work to using it to get the behavior you are looking for. Use the following code where you have "point x" in your example.. (you almost had it :)
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->setDynamicSortFilter(true); // This ensures the proxy will resort when the model changes
chooser.setProxyModel(sorter);
I think what you need to do is create a QSortFilterProxyModel which you then set in your QFileDialog with QFileDialog::setProxyModel(QAbstractProxyModel * proxyModel)
Here are some relevant links to the Qt 4.6 docs about it.
http://doc.trolltech.com/4.6/qfiledialog.html#setProxyModel
http://doc.trolltech.com/4.6/qsortfilterproxymodel.html#details
I don't think it depends upon the implementation of Qt libraries... But upon the Native OS implementation..
For example in Windows,
if you use QFileDialog, it will display the Files and Directories by Name sorted.. It is the same when used in other applications. In the sense that, if you try to open a file through MS- Word, it indeed displays the Files and directories as Name sorted by default..
And am not sure about other environments since am not used to them...
But in Windows, you can change the sorted order by right-click in the area of Files and Directories display and can select the options you like.. For e.g like Name,size,type, modified... And also which is similar, when you use an MS-Word application...
So, I believe it does depend on the Native OS implementation and not on QFileDialog's...
I'm working in some old code which was originally designed for handling two different kinds of files. I was recently tasked with adding a new kind of file to this code. Most of my problems were solved by filling out an extensive XML file with a new entry that handled everything from what lists were named to how the file is written in plural lower case. But this ended up being insufficient, as there were maybe 50 different places in 24 different code files where I had to update hardcoded switch-statements that only branched for the original two file types.
Unfortunately there is no consistency in this; there are methods which operate half from the XML file, and half off of hardcode. Some of the files which look like they would operate off of the XML file don't, and some that I would expect that I'd need to update the hardcode don't need it. So the only way to find the majority of these is to run through testing the whole system when only part of it is operational, finding that one step to fix (when I'm lucky that error logging actually tells me what is going on), and then running the whole thing again. This wastes time testing the parts of the code which are already confirmed to work, time better spent testing the new parts I have to add on top of it all.
It's a hassle and a half, and to my luck I can expect that I will have to add yet another new kind of file in the near future.
Are there any solutions out there which can aid in this kind of endeavour? Something which I can input some parameters of current features, document what points in a whole code project actually need to be updated, and run something nice the next time I need to add a new feature to the code. It needn't even be fully automated, something that'll help me navigate straight to the specific points in everything and maybe even record what kind of parameters need to be loaded.
Doubt it matters specifically, but the code is comprised of ASP.NET pages, some ASP.NET controls, hundreds of C# code files, and a handful of additional XML files. It's all currently in a couple big Visual Studio 2008 projects.
Not exactly what you are describing, but if you can introduce a seam into the code and lay down some interfaces you can break out and mock, a suite of unit/integration tests would go a long way to helping you modify old code you may not fully understand well.
I completely agree with the comment about using Michael Feathers' book to learn how to wedge new tests into legacy code. I'd also strongly recommend Refactoring, by Martin Fowler. What it sounds like you need to do for your code is to implement the "Replace conditionals with polymorphism" refactoring.
I imagine your code today looks somewhat like this:
if (filetype == 23)
{
type23parser.parse(file);
}
else if (filetype == 69)
{
filestore = type69reader.read(file);
File newfile = convertFSto23(filestore);
type23parser.parse(newfile);
}
What you want to do is to abstract away all the "if (type == foo)" kinds of logic into strategy patterns that are created in a factory.
class FileRules : pReader(NULL), pParser(NULL)
{
private:
FileReaderRules *pReader;
FileParserRules *pParser;
public:
void read(File* inFile) {pReader->read(inFile);};
void parse(File* inFile) {pParser->parse(inFile);};
};
class FileRulesFactory
{
FileRules* GetRules(int inputFiletype, int parserType)
{
switch (inputFiletype)
{
case 23:
pReader = new ASCIIReader;
break;
case 69:
pReader = new EBCDICReader;
break;
}
switch (parserType)
... etc...
then your main line of code looks like this:
FileRules* rules = FileRulesFactory.GetRules(filetype, parsertype);
rules.read(file);
rules.parse(file);
Pull off this refactoring, and adding a new set of file types, parsers, readers, etc., becomes as simple as writing one exclusive to your new type.
Of course, go read the book. I vastly oversimplified it here, and probably got stuff wrong, but you should get the general idea of how to approach it from this. I can also recommend another book, "Head First Design Patterns", which has a great section on the Factory patterns (if you like those "Head First" kinds of books.)